# 画面設計書 11-複数ドキュメント取得

## 概要

本ドキュメントは、OpenSearchのMulti Get API（`_mget`）エンドポイントに関する画面設計書である。1回のリクエストで複数のドキュメントを効率的に取得するためのREST APIインターフェースを定義する。

### 本画面の処理概要

本APIは、複数のドキュメントIDを指定して一括でドキュメントを取得する機能を提供する。個別にGETリクエストを繰り返す代わりに、1回のHTTPリクエストで複数のドキュメントを取得でき、ネットワークラウンドトリップを削減してパフォーマンスを向上させる。

**業務上の目的・背景**：アプリケーションが複数のドキュメントを表示・処理する場合（例：一覧画面でのID指定による詳細取得、関連ドキュメントの一括読み込み）、個別のGETリクエストを繰り返すとネットワークオーバーヘッドが大きくなる。Multi Get APIにより、1回のリクエストで複数ドキュメントを取得し、レイテンシの削減とスループットの向上を実現する。

**画面へのアクセス方法**：HTTPクライアント（curl、アプリケーションコード等）から`GET /_mget`または`POST /_mget`、`GET /{index}/_mget`または`POST /{index}/_mget`エンドポイントにリクエストを送信する。

**主要な操作・処理内容**：
1. リクエストボディに`docs`配列（インデックス名・ドキュメントID・取得フィールド等を指定）または`ids`配列（同一インデックス内のID一覧）を指定する
2. 各ドキュメントのインデックス名を解決し、ルーティング情報に基づいてシャードを特定する
3. シャードごとにMultiGetShardRequestをグループ化し、各シャードに対してバッチリクエストを実行する
4. 各シャードからの応答を集約し、元のリクエスト順序を保持してレスポンスを構築する

**画面遷移**：本APIは独立したエンドポイントであり、ドキュメント取得（No.5）の一括版である。取得したドキュメントの内容を基に、ドキュメント更新（No.10）やドキュメント削除（No.9）を呼び出す運用が一般的である。

**権限による表示制御**：OpenSearch Securityプラグインが有効な場合、インデックスレベルのread権限が必要である。各ドキュメントの所属インデックスに対する権限が個別にチェックされ、権限のないドキュメントは取得に失敗する。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 11 | ドキュメント取得 | 主機能 | 1リクエストで複数ドキュメントを一括取得する処理 |

## 画面種別

API（複数ドキュメント一括取得）

## URL/ルーティング

| メソッド | パス | 説明 |
|---------|------|------|
| GET/POST | `/_mget` | インデックス指定なし（ボディ内で個別指定） |
| GET/POST | `/{index}/_mget` | デフォルトインデックスを指定 |

## 入出力項目

### URLパスパラメータ

| パラメータ | 型 | 必須 | 説明 |
|-----------|------|------|------|
| index | string | いいえ | デフォルトのインデックス名 |

### クエリパラメータ

| パラメータ | 型 | 必須 | デフォルト | 説明 |
|-----------|------|------|-----------|------|
| stored_fields | list | いいえ | - | レスポンスに含めるストアドフィールドのカンマ区切りリスト |
| preference | string | いいえ | random | 操作を実行するノードまたはシャードの指定 |
| realtime | boolean | いいえ | true | リアルタイムモードで操作を実行するかどうか |
| refresh | boolean | いいえ | false | 操作前にドキュメントを含むシャードをリフレッシュするかどうか |
| routing | string | いいえ | - | 特定のルーティング値 |
| _source | list | いいえ | - | _sourceフィールドを返すかどうか、または返すフィールドのリスト |
| _source_excludes | list | いいえ | - | _sourceフィールドから除外するフィールドのリスト |
| _source_includes | list | いいえ | - | _sourceフィールドから抽出して返すフィールドのリスト |

### リクエストボディ

| フィールド | 型 | 必須 | 説明 |
|-----------|------|------|------|
| docs | array | docs/idsいずれか必須 | 取得するドキュメントの詳細情報の配列 |
| docs[]._index | string | はい | ドキュメントのインデックス名 |
| docs[]._id | string | はい | ドキュメントID |
| docs[].routing | string | いいえ | ルーティング値 |
| docs[]._source | boolean/object | いいえ | ソースフィルタリング設定 |
| docs[].stored_fields | list | いいえ | 取得するストアドフィールドのリスト |
| ids | array | docs/idsいずれか必須 | ドキュメントIDの配列（URL内でインデックスを指定した場合に使用） |

## 表示項目

### レスポンスボディ

| フィールド | 型 | 説明 |
|-----------|------|------|
| docs | array | 取得結果の配列（リクエスト順） |
| docs[]._index | string | ドキュメントのインデックス名 |
| docs[]._id | string | ドキュメントID |
| docs[]._version | number | ドキュメントのバージョン |
| docs[].found | boolean | ドキュメントが見つかったかどうか |
| docs[]._source | object | ドキュメントのソースデータ |
| docs[].error | object | エラーが発生した場合のエラー情報 |

## イベント仕様

### 1-Multi Getリクエスト実行

クライアントからMulti Getリクエストを受信すると、以下の処理が実行される。

1. `RestMultiGetAction.prepareRequest()`がリクエストパラメータを解析し、`MultiGetRequest`オブジェクトを構築する（行78-101）
2. `TransportMultiGetAction.doExecute()`がクラスタ状態を取得し、グローバルブロックの読み取りチェックを実行する（行90-92）
3. 各アイテムについてインデックス名を解決し、ルーティング情報を取得する（行97-115）
4. `ShardId`を計算し、同一シャードへのリクエストをグループ化する（行117-129）
5. シャードごとに`TransportShardMultiGetAction`を実行し、結果を`AtomicArray`に集約する（行140-177）
6. 全シャードからの応答が揃った時点で`MultiGetResponse`を構築して返却する

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| Multi Getリクエスト | Luceneインデックス | SELECT | 複数ドキュメントを一括で読み取る（更新なし） |

### テーブル別更新項目詳細

本APIは読み取り専用であり、データベース（Luceneインデックス）の更新は行わない。

## メッセージ仕様

| メッセージ種別 | 条件 | メッセージ内容 |
|--------------|------|--------------|
| 成功 | 全ドキュメント取得成功 | HTTPステータス200、各docsのfound=true |
| 部分成功 | 一部ドキュメント未発見 | HTTPステータス200、該当docsのfound=false |
| エラー | インデックス未存在 | 該当docsにerrorオブジェクトが含まれる |
| エラー | ルーティング必須のインデックスでルーティング未指定 | RoutingMissingExceptionが該当docsのerrorに含まれる |
| エラー | 廃止パラメータ使用 | fieldsパラメータ指定時に"The parameter [fields] is no longer supported"エラー |
| エラー | グローバル読み取りブロック | ClusterBlockExceptionがスローされる |

## 例外処理

| 例外 | 条件 | 動作 |
|------|------|------|
| ClusterBlockException | クラスタに読み取りブロックが設定されている場合 | リクエスト全体が失敗し、HTTPステータス403を返す |
| RoutingMissingException | ルーティングが必須のインデックスでルーティング未指定 | 該当ドキュメントのみ失敗、他は正常処理 |
| IndexNotFoundException | 指定インデックスが存在しない場合 | 該当ドキュメントのみ失敗 |
| IllegalArgumentException | 廃止されたfieldsパラメータを使用した場合 | リクエスト全体が失敗 |

## 備考

- `realtime`パラメータがtrue（デフォルト）の場合、リフレッシュ前のトランザクションログからもドキュメントを取得できる
- セグメントレプリケーションが有効なインデックスでは、リアルタイム取得時に自動的にプライマリシャードにルーティングされる（`shouldForcePrimaryRouting`メソッド、行85-87）
- `docs`形式と`ids`形式は排他的であり、同一リクエスト内での混在は非推奨

---

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

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

### 推奨読解順序

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

まず、Multi Get APIのリクエスト・レスポンスのデータ構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | mget.json | `rest-api-spec/src/main/resources/rest-api-spec/api/mget.json` | APIのURL、メソッド、パラメータ定義を確認 |
| 1-2 | MultiGetRequest.java | `server/src/main/java/org/opensearch/action/get/MultiGetRequest.java` | リクエストのデータ構造（items, preference, realtime等） |
| 1-3 | MultiGetResponse.java | `server/src/main/java/org/opensearch/action/get/MultiGetResponse.java` | レスポンスのデータ構造（responses配列） |

**読解のコツ**: MultiGetRequest内部の`Item`クラスが個々のドキュメント指定を表現している。`add()`メソッドでXContentParserからボディをパースする処理に注目。

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

RESTリクエストの受信からTransport層への委譲までを追う。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | RestMultiGetAction.java | `server/src/main/java/org/opensearch/rest/action/document/RestMultiGetAction.java` | RESTハンドラの実装 |

**主要処理フロー**:
1. **行66-69**: routes()でGET/POSTの`/_mget`と`/{index}/_mget`の4つのルートを定義
2. **行78-101**: prepareRequest()でパラメータ解析、MultiGetRequestの構築、NodeClient.multiGet()の呼び出し
3. **行83-88**: 廃止されたfieldsパラメータのチェック
4. **行96-98**: XContentParserを使ったリクエストボディのパース

#### Step 3: Transport層の処理を理解する

シャードベースの並列取得処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | TransportMultiGetAction.java | `server/src/main/java/org/opensearch/action/get/TransportMultiGetAction.java` | シャードへのリクエスト分散処理 |

**主要処理フロー**:
- **行90-92**: クラスタ状態の取得とグローバルブロックチェック
- **行94-130**: 各アイテムをシャードIDごとにグループ化
- **行85-87**: セグメントレプリケーション時のプライマリルーティング強制
- **行140-177**: シャード別の非同期実行と結果集約

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

```
RestMultiGetAction.prepareRequest()                    [行78]
    |
    +-- MultiGetRequest.add()                          [リクエストボディパース]
    |
    +-- NodeClient.multiGet()
            |
            +-- TransportMultiGetAction.doExecute()    [行90]
                    |
                    +-- ClusterState.blocks().globalBlockedRaiseException()  [行92]
                    |
                    +-- IndexNameExpressionResolver.concreteSingleIndex()    [行102]
                    |
                    +-- ClusterService.operationRouting().getShards()        [行117]
                    |
                    +-- TransportShardMultiGetAction.execute()               [行148]
                            |
                            +-- ShardMultiGetAction (各シャードでのドキュメント取得)
```

### データフロー図

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

HTTPリクエスト                RestMultiGetAction                  MultiGetResponse
(POST /_mget)          パラメータ解析・リクエスト構築
   |                              |
   v                              v
リクエストボディ           TransportMultiGetAction               レスポンスJSON
{docs:[...]}           シャード別グループ化・並列実行           {docs:[...]}
   |                              |
   v                              v
各doc指定              TransportShardMultiGetAction            各docの結果
(_index, _id)          シャード内ドキュメント取得              (found/error)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| mget.json | `rest-api-spec/src/main/resources/rest-api-spec/api/mget.json` | API定義 | REST API仕様の定義 |
| RestMultiGetAction.java | `server/src/main/java/org/opensearch/rest/action/document/RestMultiGetAction.java` | ソース | RESTハンドラ |
| TransportMultiGetAction.java | `server/src/main/java/org/opensearch/action/get/TransportMultiGetAction.java` | ソース | Transport層の実行処理 |
| MultiGetRequest.java | `server/src/main/java/org/opensearch/action/get/MultiGetRequest.java` | ソース | リクエストデータ構造 |
| MultiGetResponse.java | `server/src/main/java/org/opensearch/action/get/MultiGetResponse.java` | ソース | レスポンスデータ構造 |
| TransportShardMultiGetAction.java | `server/src/main/java/org/opensearch/action/get/TransportShardMultiGetAction.java` | ソース | シャードレベルの取得処理 |
| MultiGetShardRequest.java | `server/src/main/java/org/opensearch/action/get/MultiGetShardRequest.java` | ソース | シャード別リクエスト |
| MultiGetShardResponse.java | `server/src/main/java/org/opensearch/action/get/MultiGetShardResponse.java` | ソース | シャード別レスポンス |
