# 機能設計書 29-検索プロファイリング

## 概要

本ドキュメントは、OpenSearchの検索プロファイリング機能に関する機能設計書である。検索クエリの実行時間を詳細にプロファイリングする機能を定義する。

### 本機能の処理概要

**業務上の目的・背景**：検索クエリのパフォーマンス問題を診断するために、クエリの各フェーズ（Query、Fetch）および各コンポーネント（クエリ、集計、フェッチ）の実行時間を詳細に計測する必要がある。プロファイリング機能はこの情報を提供し、ボトルネックの特定とクエリ最適化を支援する。

**機能の利用シーン**：検索クエリのパフォーマンスチューニング、遅いクエリの原因特定、集計パフォーマンスの分析、シャードレベルでの実行時間の比較、コンカレントセグメント検索のプロファイリングなどで利用される。

**主要な処理内容**：
1. 検索リクエストに`profile: true`を指定してプロファイリングを有効化する
2. Profilersオブジェクトが各シャードでQueryProfiler、AggregationProfiler、FetchProfilerを管理する
3. 各プロファイラーがAbstractProfileTreeを構築し、処理の階層的な実行時間を記録する
4. ProfileShardResultにクエリ/集計/フェッチのプロファイル結果とネットワーク時間を格納する
5. SearchResponseのprofile_resultsフィールドとして結果を返却する

**関連システム・外部連携**：ContextIndexSearcherにプロファイラーを設定し、Luceneの検索実行をフックしてプロファイル情報を収集する。

**権限による制御**：検索APIの権限（`indices:data/read/search`）に準拠する。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 21 | 検索 | 補助機能 | 検索クエリの実行時間プロファイリング処理 |

## 機能種別

パフォーマンス計測（検索プロファイリング）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| profile | boolean | No | プロファイリングの有効/無効 | デフォルト: false |

### 入力データソース

検索APIリクエストボディ内の`profile`フラグ。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| profile.shards | Map<String, ProfileShardResult> | シャードごとのプロファイル結果 |
| profile.shards[].searches | QueryProfileShardResult[] | クエリフェーズのプロファイル |
| profile.shards[].searches[].query | ProfileResult[] | 各クエリコンポーネントの実行時間 |
| profile.shards[].searches[].query[].type | String | クエリタイプ名 |
| profile.shards[].searches[].query[].description | String | クエリの説明 |
| profile.shards[].searches[].query[].time_in_nanos | long | 実行時間（ナノ秒） |
| profile.shards[].searches[].query[].breakdown | Map | 詳細内訳 |
| profile.shards[].searches[].query[].children | ProfileResult[] | 子クエリのプロファイル |
| profile.shards[].aggregations | AggregationProfileShardResult | 集計プロファイル |
| profile.shards[].fetch | FetchProfileShardResult | フェッチフェーズプロファイル |
| profile.shards[].network_time | NetworkTime | ネットワーク時間 |

### 出力先

SearchResponseのprofile_resultsフィールド（JSON形式）

## 処理フロー

### 処理シーケンス

```
1. profile=trueの検索リクエスト受信
   └─ SearchSourceBuilder.profile(true)で有効化
2. 各シャードでProfilersオブジェクト作成
   └─ ContextIndexSearcherにQueryProfilerを設定
3. クエリフェーズのプロファイリング
   └─ QueryProfilerがクエリの各ノードの実行時間をTimerで計測
4. 集計フェーズのプロファイリング
   └─ AggregationProfilerが集計の実行時間を計測
5. フェッチフェーズのプロファイリング
   └─ FetchProfilerがフェッチ処理の実行時間を計測
6. ProfileShardResultの構築
   └─ クエリ/集計/フェッチ/ネットワーク時間を統合
7. SearchResponseにプロファイル結果を含めて返却
```

### フローチャート

```mermaid
flowchart TD
    A[SearchRequest with profile=true] --> B[各シャードでProfilers作成]
    B --> C[ContextIndexSearcherにQueryProfiler設定]
    C --> D[クエリフェーズ実行+プロファイリング]
    D --> E[集計フェーズ実行+プロファイリング]
    E --> F[フェッチフェーズ実行+プロファイリング]
    F --> G[ProfileShardResult構築]
    G --> H[SearchResponseにprofile_results追加]
    H --> I[レスポンス返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-29-01 | 階層的プロファイル | クエリの階層構造に沿ってプロファイル結果がツリー形式で提供される | 常時 |
| BR-29-02 | コンカレント検索対応 | コンカレントセグメント検索が有効な場合、ConcurrentQueryProfilerが使用される | isConcurrentSegmentSearchEnabled=true |
| BR-29-03 | ブレークダウン | 各クエリコンポーネントについて、create_weight、build_scorer等の詳細内訳が提供される | 常時 |
| BR-29-04 | フェッチプロファイル | V3.2.0以降でFetchProfileShardResultがサポートされる | Version >= V_3_2_0 |

### 計算ロジック

Timerクラスを使用してナノ秒精度で実行時間を計測する。

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 検索 | 対象インデックス | SELECT | 通常の検索と同様（プロファイリング情報を追加収集） |

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

通常の検索と同様。プロファイリング自体はインデックスデータの変更を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | - | プロファイリング自体にはエラーケースはない | 検索APIのエラー処理に準拠 |

### リトライ仕様

検索APIのリトライ仕様に準拠。

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

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

## パフォーマンス要件

- プロファイリングはオーバーヘッドを伴うため、本番環境での常時使用は推奨されない
- Timer使用によるナノ秒精度の計測

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

- 検索APIの権限に準拠
- プロファイル結果にクエリ構造が含まれるため、センシティブなクエリ情報が漏洩しないよう注意

## 備考

- Profilers.java はPublicApi(since = "1.0.0")としてマーク
- ProfileMetricUtilでカスタムプラグインメトリクスのサポート
- ConcurrentQueryProfileTree/ConcurrentQueryProfilerでコンカレント検索のプロファイリングに対応

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ProfileShardResult.java | `server/src/main/java/org/opensearch/search/profile/ProfileShardResult.java` | シャードレベルプロファイル結果。queryProfileResults, aggProfileShardResult, fetchProfileResult, networkTime |
| 1-2 | ProfileResult.java | `server/src/main/java/org/opensearch/search/profile/ProfileResult.java` | 個別プロファイル結果（type, description, time_in_nanos, breakdown, children） |
| 1-3 | NetworkTime.java | `server/src/main/java/org/opensearch/search/profile/NetworkTime.java` | ネットワーク時間情報 |

**読解のコツ**: ProfileShardResultの57-63行目で4つの主要コンポーネント（query, aggregation, fetch, network）の構造を理解する。Version.V_3_2_0以降でfetchProfileResultが追加された点（99-103行目）に注意。

#### Step 2: プロファイラー管理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Profilers.java | `server/src/main/java/org/opensearch/search/profile/Profilers.java` | プロファイラー管理の中核。QueryProfiler, AggregationProfiler, FetchProfilerの管理 |

**主要処理フロー**:
- **69-86行目**: コンストラクタ - ContextIndexSearcher、コンカレント対応フラグ、カスタムメトリクスを受け取る
- **82行目**: コンカレント有効時はConcurrentAggregationProfilerを使用
- **89-96行目**: addQueryProfiler - 新しいQueryProfilerを作成してsearcherに設定

#### Step 3: プロファイルツリー構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | AbstractInternalProfileTree.java | `server/src/main/java/org/opensearch/search/profile/AbstractInternalProfileTree.java` | プロファイルツリーの基底クラス |
| 3-2 | AbstractProfileBreakdown.java | `server/src/main/java/org/opensearch/search/profile/AbstractProfileBreakdown.java` | ブレークダウンの基底クラス |
| 3-3 | Timer.java | `server/src/main/java/org/opensearch/search/profile/Timer.java` | ナノ秒精度タイマー |

#### Step 4: サブプロファイラーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | query/ | `server/src/main/java/org/opensearch/search/profile/query/` | クエリプロファイラー実装 |
| 4-2 | aggregation/ | `server/src/main/java/org/opensearch/search/profile/aggregation/` | 集計プロファイラー実装 |
| 4-3 | fetch/ | `server/src/main/java/org/opensearch/search/profile/fetch/` | フェッチプロファイラー実装 |

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

```
SearchRequest (profile=true)
    |
    +-- SearchService.createContext()
            |
            +-- Profilers(searcher, isConcurrentSegmentSearchEnabled)
                    |
                    +-- QueryProfiler (per search phase)
                    |       |
                    |       +-- InternalQueryProfileTree / ConcurrentQueryProfileTree
                    |       +-- Timer (ナノ秒計測)
                    |
                    +-- AggregationProfiler / ConcurrentAggregationProfiler
                    |
                    +-- FetchProfiler
                    |
                    +-- ProfileShardResult
                            |
                            +-- QueryProfileShardResult[]
                            +-- AggregationProfileShardResult
                            +-- FetchProfileShardResult
                            +-- NetworkTime
```

### データフロー図

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

profile=true ──────> Profilers構築 ──────> SearchResponse.profile
                         |
                    QueryProfiler
                         |
                    AggregationProfiler
                         |
                    FetchProfiler
                         |
                    ProfileShardResult
                         |
                    SearchProfileShardResults
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Profilers.java | `server/src/main/java/org/opensearch/search/profile/Profilers.java` | ソース | プロファイラー管理 |
| ProfileShardResult.java | `server/src/main/java/org/opensearch/search/profile/ProfileShardResult.java` | ソース | シャードレベル結果 |
| ProfileResult.java | `server/src/main/java/org/opensearch/search/profile/ProfileResult.java` | ソース | 個別プロファイル結果 |
| SearchProfileShardResults.java | `server/src/main/java/org/opensearch/search/profile/SearchProfileShardResults.java` | ソース | 検索プロファイル結果統合 |
| AbstractInternalProfileTree.java | `server/src/main/java/org/opensearch/search/profile/AbstractInternalProfileTree.java` | ソース | プロファイルツリー基底 |
| AbstractProfileBreakdown.java | `server/src/main/java/org/opensearch/search/profile/AbstractProfileBreakdown.java` | ソース | ブレークダウン基底 |
| AbstractProfiler.java | `server/src/main/java/org/opensearch/search/profile/AbstractProfiler.java` | ソース | プロファイラー基底 |
| Timer.java | `server/src/main/java/org/opensearch/search/profile/Timer.java` | ソース | ナノ秒タイマー |
| NetworkTime.java | `server/src/main/java/org/opensearch/search/profile/NetworkTime.java` | ソース | ネットワーク時間 |
| ProfileMetric.java | `server/src/main/java/org/opensearch/search/profile/ProfileMetric.java` | ソース | プロファイルメトリクス |
| ProfileMetricUtil.java | `server/src/main/java/org/opensearch/search/profile/ProfileMetricUtil.java` | ソース | メトリクスユーティリティ |
| ContextualProfileBreakdown.java | `server/src/main/java/org/opensearch/search/profile/ContextualProfileBreakdown.java` | ソース | コンテキスト付きブレークダウン |
