# 機能設計書 23-Point in Time（PIT）

## 概要

本ドキュメントは、OpenSearchのPoint in Time（PIT）機能に関する機能設計書である。検索時点のインデックス状態を保持し、一貫性のある検索を行うための軽量な検索コンテキスト管理機能を定義する。

### 本機能の処理概要

**業務上の目的・背景**：スクロール検索はステートフルな検索コンテキストに紐づいた結果取得手法であるが、検索クエリの変更ができないなどの制約がある。PITは検索時点のインデックスの「読み取りビュー」を作成・保持することで、同一時点に対して異なるクエリを複数回実行できる柔軟な一貫性保証を提供する。ページネーションやsearch_afterとの組み合わせにより、効率的なディープページングが可能になる。

**機能の利用シーン**：大量データの安全なページネーション（search_after + PITパターン）、同一時点のデータに対する複数クエリの実行、一貫性が求められるレポート生成処理、リアルタイムダッシュボードでの安定した表示などで利用される。

**主要な処理内容**：
1. PIT作成（Create PIT）: 指定インデックスに対してリーダーコンテキストを作成し、PIT IDを返却する
2. PIT削除（Delete PIT）: 指定のPIT IDに対応するコンテキストを削除する
3. 全PIT削除（Delete All PITs）: 全てのアクティブなPITコンテキストを削除する
4. 全PIT一覧（Get All PITs）: 全てのアクティブなPITコンテキストの一覧を取得する

**関連システム・外部連携**：CreatePitControllerがTransportSearchActionを利用して各シャードにリーダーコンテキストを作成する。PitServiceがPIT関連の共通操作を提供する。

**権限による制御**：`indices:data/read/point_in_time/create`アクション名で作成が制御される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 34 | PIT作成 | 主画面 | Point in Timeコンテキストを作成する処理 |
| 35 | PIT削除 | 主画面 | IDベースでPoint in Time検索コンテキストを削除する処理 |
| 36 | 全PIT削除 | 主画面 | すべてのアクティブなPoint in Time検索コンテキストを削除する処理 |
| 37 | 全PIT取得 | 主画面 | すべてのアクティブなPoint in Time検索コンテキストを一覧表示する処理 |
| 166 | Cat PITセグメント | 参照画面 | PITのセグメント情報をテーブル形式で返す処理 |

## 機能種別

検索コンテキスト管理（CRUD操作）

## 入力仕様

### 入力パラメータ

#### Create PIT

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| keep_alive | TimeValue | Yes | PITコンテキストの有効期間 | null不可 |
| allow_partial_pit_creation | Boolean | No | 部分的なPIT作成の許可 | - |
| indices | String[] | Yes | 対象インデックス名 | null不可 |
| routing | String | No | ルーティング値 | - |
| preference | String | No | シャード優先指定 | - |
| indices_options | IndicesOptions | No | インデックス解決オプション | - |

#### Delete PIT

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| pit_id | String[] | Yes | 削除対象のPIT ID | - |

### 入力データソース

REST APIエンドポイント（`POST /{index}/_search/point_in_time`, `DELETE /_search/point_in_time`, `DELETE /_search/point_in_time/_all`, `GET /_search/point_in_time/_all`）

## 出力仕様

### 出力データ

#### Create PIT Response

| 項目名 | 型 | 説明 |
|--------|-----|------|
| pit_id | String | 作成されたPITのID |
| _shards | ShardStatistics | シャード実行統計 |
| creation_time | long | PIT作成時刻 |

#### Delete PIT Response

| 項目名 | 型 | 説明 |
|--------|-----|------|
| pits | DeletePitInfo[] | 各PIT IDの削除結果（成功/失敗） |

#### Get All PITs Response

| 項目名 | 型 | 説明 |
|--------|-----|------|
| pits | ListPitInfo[] | アクティブなPIT一覧 |

### 出力先

REST APIレスポンス（JSON形式）

## 処理フロー

### 処理シーケンス

```
1. Create PIT
   1.1 CreatePitRequestからSearchRequestを構築
       └─ toSearchRequest()でインデックス・ルーティング等をコピー
   1.2 CreatePitControllerで各シャードにリーダーコンテキスト作成
       └─ TransportSearchActionの仕組みを利用してシャード解決
   1.3 各シャードからShardSearchContextIdを収集
       └─ PIT IDとしてエンコードして返却
   1.4 PIT IDの更新
       └─ updatePitIdListenerで最終的なPIT IDを構築

2. Delete PIT
   2.1 PIT IDをデコードしてノード・シャード情報を取得
       └─ SearchContextId.decodeでPIT IDを解析
   2.2 ノードごとにPITコンテキスト削除リクエストを送信
       └─ PitService.deletePitContextsでノード別にグルーピング
   2.3 結果を集約してDeletePitResponseを構築

3. Get All PITs
   3.1 全データノードにPIT一覧リクエストを送信
       └─ PitService.getAllPitsでデータノードを列挙
   3.2 各ノードの応答を集約して返却
```

### フローチャート

```mermaid
flowchart TD
    A[Create PIT Request] --> B[SearchRequest構築]
    B --> C[CreatePitController.executeCreatePit]
    C --> D[各シャードにリーダーコンテキスト作成]
    D --> E[ShardSearchContextId収集]
    E --> F[PIT IDエンコード]
    F --> G[CreatePitResponse返却]

    H[Delete PIT Request] --> I[PIT IDデコード]
    I --> J[ノード別グルーピング]
    J --> K[各ノードにコンテキスト削除送信]
    K --> L[結果集約]
    L --> M[DeletePitResponse返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-23-01 | keep_alive必須 | PIT作成時にkeep_aliveは必須 | Create PIT |
| BR-23-02 | 部分作成許可 | allow_partial_pit_creationがtrueの場合、一部シャード失敗でもPITを作成 | allow_partial_pit_creation=true |
| BR-23-03 | 自動期限切れ | keep_alive期間を過ぎたPITコンテキストは自動的に削除される | 常時 |
| BR-23-04 | ノード不在時のフォールバック | 削除時にノードが見つからない場合、失敗として報告 | Delete PIT |

### 計算ロジック

特になし。

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| Create PIT | 対象インデックスの各シャード | コンテキスト作成 | リーダーコンテキスト（読み取りスナップショット）を作成 |
| Delete PIT | 対象シャード | コンテキスト削除 | リーダーコンテキストを解放 |
| Get All PITs | 全データノード | 情報取得 | アクティブなPIT情報を収集 |

### テーブル別操作詳細

該当なし（Luceneのリーダーコンテキスト管理であり、テーブル操作ではない）。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 400 | ActionRequestValidationException | keep_aliveが未指定 | keep_aliveを指定する |
| 404 | IndexNotFoundException | 指定インデックスが存在しない | インデックス名を確認する |
| 500 | SearchPhaseExecutionException | シャードレベルのPIT作成失敗 | クラスタの状態を確認する |

### リトライ仕様

PIT作成失敗時は再実行可能。PIT削除でノードが見つからない場合は失敗を報告するが、他のノードの削除は継続する。

## トランザクション仕様

PITコンテキストはインデックスの読み取りスナップショットを保持する。PITの存続期間中はセグメントのマージが完了してもスナップショット時点のセグメントが保持される。

## パフォーマンス要件

- PITコンテキストはリソース（メモリ、ファイルディスクリプタ）を消費するため、不要になったら明示的に削除することを推奨
- keep_aliveは必要最小限の値を設定する

## セキュリティ考慮事項

- アクション名`indices:data/read/point_in_time/create`等による権限制御
- PIT IDにはシャード情報が含まれるため、外部への漏洩に注意が必要

## 備考

- PublicApi(since = "2.3.0")としてマークされている
- クロスクラスタ検索のリモートクラスタPITもサポート
- PitServiceがgetIndicesForPitsでPIT IDからインデックス名を解決する機能を提供

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | CreatePitRequest.java | `server/src/main/java/org/opensearch/action/search/CreatePitRequest.java` | keep_alive, indices, allow_partial_pit_creation等のフィールド |
| 1-2 | CreatePitResponse.java | `server/src/main/java/org/opensearch/action/search/CreatePitResponse.java` | PIT ID、シャード統計のレスポンス構造 |
| 1-3 | DeletePitRequest.java | `server/src/main/java/org/opensearch/action/search/DeletePitRequest.java` | 削除対象PIT IDリスト |
| 1-4 | DeletePitResponse.java | `server/src/main/java/org/opensearch/action/search/DeletePitResponse.java` | 削除結果リスト |
| 1-5 | SearchContextId.java | `server/src/main/java/org/opensearch/action/search/SearchContextId.java` | PIT IDのエンコード・デコード |

**読解のコツ**: CreatePitRequest.toSearchRequest()（200-207行目）がPIT作成用のSearchRequestへの変換を行う。keep_aliveが必須であることはvalidate()（127-133行目）で確認できる。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | CreatePitAction.java | `server/src/main/java/org/opensearch/action/search/CreatePitAction.java` | アクション定義。NAME = "indices:data/read/point_in_time/create" |
| 2-2 | RestCreatePitAction.java | `server/src/main/java/org/opensearch/rest/action/search/RestCreatePitAction.java` | REST APIエンドポイント |

#### Step 3: PIT作成のトランスポート層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | TransportCreatePitAction.java | `server/src/main/java/org/opensearch/action/search/TransportCreatePitAction.java` | PIT作成のTransportAction |
| 3-2 | CreatePitController.java | `server/src/main/java/org/opensearch/action/search/CreatePitController.java` | PIT作成の制御ロジック |

**主要処理フロー**:
- **69-81行目（TransportCreatePitAction）**: doExecute - StepListenerを使ったPIT作成のパイプライン
- **80行目**: createPitController.executeCreatePitに処理を委譲
- **91-120行目**: CreateReaderContextRequest - シャードレベルのコンテキスト作成リクエスト

#### Step 4: PIT管理サービスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | PitService.java | `server/src/main/java/org/opensearch/action/search/PitService.java` | PIT共通操作（削除、一覧取得） |

**主要処理フロー**:
- **70-127行目**: deletePitContexts - ノード別のPITコンテキスト削除
- **164-170行目**: getIndicesForPits - PIT IDからインデックス名解決
- **186-220行目**: getAllPits - 全データノードからPIT一覧取得

### プログラム呼び出し階層図

```
RestCreatePitAction (REST)
    |
    +-- TransportCreatePitAction.doExecute()
            |
            +-- CreatePitController.executeCreatePit()
                    |
                    +-- TransportSearchAction (シャード解決)
                    |
                    +-- SearchTransportService (各シャードにコンテキスト作成)
                    |
                    +-- PIT IDエンコード・返却

RestDeletePitAction (REST)
    |
    +-- TransportDeletePitAction.doExecute()
            |
            +-- PitService.deletePitContexts()
                    |
                    +-- SearchTransportService.sendFreePITContexts()
```

### データフロー図

```
[入力]                    [処理]                              [出力]

CreatePitRequest ──> CreatePitController ──────> CreatePitResponse
  (indices,             |                        (pit_id, _shards)
   keep_alive)          |
                   各シャードにリーダーコンテキスト作成
                        |
                   ShardSearchContextId収集
                        |
                   PIT IDエンコード

DeletePitRequest ──> PitService.deletePitContexts ──> DeletePitResponse
  (pit_id)              |                              (pits[])
                   SearchContextId.decode
                        |
                   ノード別コンテキスト削除
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| CreatePitAction.java | `server/src/main/java/org/opensearch/action/search/CreatePitAction.java` | ソース | PIT作成アクション定義 |
| CreatePitRequest.java | `server/src/main/java/org/opensearch/action/search/CreatePitRequest.java` | ソース | PIT作成リクエスト |
| CreatePitResponse.java | `server/src/main/java/org/opensearch/action/search/CreatePitResponse.java` | ソース | PIT作成レスポンス |
| TransportCreatePitAction.java | `server/src/main/java/org/opensearch/action/search/TransportCreatePitAction.java` | ソース | PIT作成トランスポート層 |
| CreatePitController.java | `server/src/main/java/org/opensearch/action/search/CreatePitController.java` | ソース | PIT作成制御ロジック |
| DeletePitAction.java | `server/src/main/java/org/opensearch/action/search/DeletePitAction.java` | ソース | PIT削除アクション定義 |
| DeletePitRequest.java | `server/src/main/java/org/opensearch/action/search/DeletePitRequest.java` | ソース | PIT削除リクエスト |
| DeletePitResponse.java | `server/src/main/java/org/opensearch/action/search/DeletePitResponse.java` | ソース | PIT削除レスポンス |
| DeletePitInfo.java | `server/src/main/java/org/opensearch/action/search/DeletePitInfo.java` | ソース | PIT削除結果情報 |
| PitService.java | `server/src/main/java/org/opensearch/action/search/PitService.java` | ソース | PIT共通サービス |
| GetAllPitsAction.java | `server/src/main/java/org/opensearch/action/search/GetAllPitsAction.java` | ソース | 全PIT取得アクション |
| SearchContextId.java | `server/src/main/java/org/opensearch/action/search/SearchContextId.java` | ソース | PIT IDエンコード・デコード |
| RestCreatePitAction.java | `server/src/main/java/org/opensearch/rest/action/search/RestCreatePitAction.java` | ソース | REST作成エンドポイント |
| RestDeletePitAction.java | `server/src/main/java/org/opensearch/rest/action/search/RestDeletePitAction.java` | ソース | REST削除エンドポイント |
| RestGetAllPitsAction.java | `server/src/main/java/org/opensearch/rest/action/search/RestGetAllPitsAction.java` | ソース | REST全PIT取得エンドポイント |
