# 機能設計書 26-フィールドキャパビリティ

## 概要

本ドキュメントは、OpenSearchのField Capabilities API機能に関する機能設計書である。インデックス横断でフィールドの型情報を取得する機能を定義する。

### 本機能の処理概要

**業務上の目的・背景**：複数のインデックスにまたがるデータ分析やダッシュボード構築において、各インデックスのフィールドがどのような型で定義されているか、検索可能か、集計可能かといった情報を事前に把握する必要がある。Field Capabilities APIはこの情報をインデックス横断で効率的に取得し、動的なクエリ構築やUIの自動生成を支援する。

**機能の利用シーン**：OpenSearch Dashboardsのインデックスパターン設定時のフィールド情報取得、クロスクラスタ検索でのフィールド互換性確認、動的クエリビルダーでのフィールド型判定、データ品質チェックでのスキーマ不整合検出などで利用される。

**主要な処理内容**：
1. ローカルインデックスとリモートクラスタインデックスを解決する
2. 各インデックスに対してFieldCapabilitiesIndexActionを実行し、フィールド情報を収集する
3. リモートクラスタの場合は、リモートクラスタクライアントを使用して情報を取得する
4. 全インデックスの結果をマージし、フィールドごとの型情報・検索可否・集計可否を統合する

**関連システム・外部連携**：リモートクラスタサービス（RemoteClusterService）と連携し、クロスクラスタのフィールド情報取得をサポートする。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 25 | フィールド機能 | 主画面 | 複数インデックス間のフィールド機能情報を返す処理 |

## 機能種別

メタデータ取得（インデックスフィールド情報の取得）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| fields | String[] | Yes | 取得対象のフィールド名（ワイルドカード対応） | - |
| indices | String[] | No | 対象インデックス名 | - |
| index_filter | QueryBuilder | No | インデックスフィルタ（canMatchで使用） | - |
| include_unmapped | boolean | No | マッピングされていないフィールドを含めるか | デフォルト: false |
| merge_results | boolean | No | 結果をマージするか | デフォルト: true |
| indices_options | IndicesOptions | No | インデックス解決オプション | - |

### 入力データソース

REST APIエンドポイント（`GET /_field_caps`, `GET /{index}/_field_caps`, `POST /_field_caps`, `POST /{index}/_field_caps`）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| indices | String[] | フィールド情報が返されたインデックス名リスト |
| fields | Map<String, Map<String, FieldCapabilities>> | フィールド名 -> 型名 -> FieldCapabilities のマップ |
| fields.{field}.{type}.type | String | フィールドの型名 |
| fields.{field}.{type}.searchable | boolean | 検索可能か |
| fields.{field}.{type}.aggregatable | boolean | 集計可能か |
| fields.{field}.{type}.indices | String[] | この型でマッピングされているインデックス |
| fields.{field}.{type}.non_searchable_indices | String[] | 検索不可のインデックス |
| fields.{field}.{type}.non_aggregatable_indices | String[] | 集計不可のインデックス |
| fields.{field}.{type}.meta | Map | メタデータ |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. インデックスの解決
   └─ ローカルインデックスとリモートクラスタインデックスを分離
2. ローカルインデックスの処理
   └─ 各具体的インデックスに対してFieldCapabilitiesIndexActionを実行
3. リモートクラスタインデックスの処理
   └─ リモートクラスタクライアント経由でmerge_results=falseで個別結果を取得
4. 結果のマージ
   └─ フィールドごとに型情報・searchable・aggregatable・indicesを統合
5. unmappedフィールドの追加（オプション）
   └─ include_unmapped=trueの場合、全インデックスに存在しないフィールドを"unmapped"型で追加
6. FieldCapabilitiesResponseとして返却
```

### フローチャート

```mermaid
flowchart TD
    A[FieldCapabilitiesRequest] --> B[インデックス解決]
    B --> C{ローカル / リモート分離}
    C -->|ローカル| D[各インデックスにFieldCapabilitiesIndexAction]
    C -->|リモート| E[リモートクラスタクライアント経由で取得]
    D --> F[CountDownで完了待ち]
    E --> F
    F --> G{merge_results?}
    G -->|Yes| H[結果マージ]
    G -->|No| I[個別結果をそのまま返却]
    H --> J{include_unmapped?}
    J -->|Yes| K[unmappedフィールド追加]
    J -->|No| L[FieldCapabilitiesResponse返却]
    K --> L
    I --> L
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-26-01 | 型の統合 | 同一フィールドが異なるインデックスで異なる型の場合、複数の型エントリが返される | 常時 |
| BR-26-02 | searchable/aggegatable判定 | 全インデックスでsearchable/aggregatableが同一でない場合、non_searchable/non_aggregatable_indicesに不一致インデックスを列挙 | 型が複数存在する場合 |
| BR-26-03 | unmapped型 | include_unmapped=trueの場合、一部インデックスにマッピングされていないフィールドは"unmapped"型として追加 | include_unmapped=true |
| BR-26-04 | canMatch最適化 | index_filter指定時、canMatchでフィルタに一致しないインデックスをスキップ | index_filter指定時 |

### 計算ロジック

特になし。

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| フィールド情報取得 | 対象インデックスのマッピング | メタデータ取得 | 各インデックスのフィールドマッピング情報を取得 |

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

読み取り専用のメタデータ操作。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 404 | IndexNotFoundException | 指定インデックスが存在しない | インデックス名を確認する |
| 500 | Exception | インデックスレベルのフィールド情報取得失敗 | 個別インデックスの失敗は無視され、残りの結果で応答 |

### リトライ仕様

個別インデックスの失敗は無視され、残りのインデックスの結果で応答する。

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

読み取り専用のメタデータ操作であり、トランザクション管理は不要。

## パフォーマンス要件

- CountDownパターンで並行にインデックスレベルの情報取得を実行
- canMatch最適化により、不要なインデックスへのリクエストをスキップ可能

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

- アクション名`indices:data/read/field_caps`による権限制御
- リモートクラスタへのアクセスにはクロスクラスタ検索の権限が必要

## 備考

- TransportIndicesResolvingActionを実装し、インデックス解決を明示的に行う
- リモートクラスタの結果にはクラスタエイリアスプレフィクスが付与される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | FieldCapabilitiesRequest.java | `server/src/main/java/org/opensearch/action/fieldcaps/FieldCapabilitiesRequest.java` | リクエスト構造。fields, indices, indexFilter, includeUnmapped |
| 1-2 | FieldCapabilitiesResponse.java | `server/src/main/java/org/opensearch/action/fieldcaps/FieldCapabilitiesResponse.java` | レスポンス構造。indices配列、fields Map |
| 1-3 | FieldCapabilities.java | `server/src/main/java/org/opensearch/action/fieldcaps/FieldCapabilities.java` | フィールドごとの能力情報。searchable, aggregatable |
| 1-4 | IndexFieldCapabilities.java | `server/src/main/java/org/opensearch/action/fieldcaps/IndexFieldCapabilities.java` | インデックスレベルのフィールド能力 |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | FieldCapabilitiesAction.java | `server/src/main/java/org/opensearch/action/fieldcaps/FieldCapabilitiesAction.java` | アクション定義 |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | TransportFieldCapabilitiesAction.java | `server/src/main/java/org/opensearch/action/fieldcaps/TransportFieldCapabilitiesAction.java` | メイン実行ロジック |
| 3-2 | TransportFieldCapabilitiesIndexAction.java | `server/src/main/java/org/opensearch/action/fieldcaps/TransportFieldCapabilitiesIndexAction.java` | インデックスレベルの情報取得 |

**主要処理フロー**:
- **94-165行目（TransportFieldCapabilitiesAction）**: doExecute - インデックス解決、並行実行、結果マージ
- **98-100行目**: ローカルとリモートのインデックス分離
- **101-102行目**: CountDownによる並行完了待ち
- **131-136行目**: 各ローカルインデックスへのshardAction.execute
- **140-163行目**: リモートクラスタクライアント経由の情報取得
- **190-211行目**: merge() - 結果のマージロジック
- **213-224行目**: addUnmappedFields - unmappedフィールド追加

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

```
REST (/_field_caps)
    |
    +-- TransportFieldCapabilitiesAction.doExecute()
            |
            +-- resolveIndices() [ローカル/リモート分離]
            |
            +-- [ローカル] TransportFieldCapabilitiesIndexAction.execute()
            |       |
            |       +-- FieldCapabilitiesIndexResponse (per index)
            |
            +-- [リモート] remoteClusterClient.fieldCaps()
            |       |
            |       +-- FieldCapabilitiesResponse -> IndexResponses
            |
            +-- merge() [全結果統合]
                    |
                    +-- innerMerge() [フィールドごとのBuilder統合]
                    +-- addUnmappedFields() [unmapped追加]
                    +-- FieldCapabilitiesResponse
```

### データフロー図

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

fields: ["*"]       resolveIndices()                          indices: [...]
indices: [...]          |                                     fields: {
                   +----+----+                                   "field1": {
                   |         |                                     "keyword": {
              Local       Remote                                     searchable: true,
                   |         |                                       aggregatable: true
              IndexAction  remoteClient                            }
                   |         |                                   }
              IndexResponse[]                                 }
                   |         |
                   +----+----+
                        |
                   merge()
                        |
                   FieldCapabilitiesResponse
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| FieldCapabilitiesAction.java | `server/src/main/java/org/opensearch/action/fieldcaps/FieldCapabilitiesAction.java` | ソース | アクション型定義 |
| FieldCapabilitiesRequest.java | `server/src/main/java/org/opensearch/action/fieldcaps/FieldCapabilitiesRequest.java` | ソース | リクエストモデル |
| FieldCapabilitiesResponse.java | `server/src/main/java/org/opensearch/action/fieldcaps/FieldCapabilitiesResponse.java` | ソース | レスポンスモデル |
| FieldCapabilities.java | `server/src/main/java/org/opensearch/action/fieldcaps/FieldCapabilities.java` | ソース | フィールド能力情報 |
| IndexFieldCapabilities.java | `server/src/main/java/org/opensearch/action/fieldcaps/IndexFieldCapabilities.java` | ソース | インデックスレベルフィールド能力 |
| FieldCapabilitiesIndexRequest.java | `server/src/main/java/org/opensearch/action/fieldcaps/FieldCapabilitiesIndexRequest.java` | ソース | インデックスレベルリクエスト |
| FieldCapabilitiesIndexResponse.java | `server/src/main/java/org/opensearch/action/fieldcaps/FieldCapabilitiesIndexResponse.java` | ソース | インデックスレベルレスポンス |
| TransportFieldCapabilitiesAction.java | `server/src/main/java/org/opensearch/action/fieldcaps/TransportFieldCapabilitiesAction.java` | ソース | メイン実行ロジック |
| TransportFieldCapabilitiesIndexAction.java | `server/src/main/java/org/opensearch/action/fieldcaps/TransportFieldCapabilitiesIndexAction.java` | ソース | インデックスレベル実行 |
