# 機能設計書 31-バケット集計

## 概要

本ドキュメントは、OpenSearchのバケット集計（Bucket Aggregation）機能の設計を記述する。バケット集計はドキュメントをグループ化し、各グループ（バケット）に含まれるドキュメントの集合を生成する集計機能である。

### 本機能の処理概要

バケット集計は、検索結果のドキュメントをフィールド値や条件に基づいてグループ化（バケット化）し、各バケットのドキュメント数やサブ集計結果を返却する機能である。Terms、Histogram、Date Histogram、Range、Filter、Nested、Composite等の多様なバケット集計タイプを提供する。

**業務上の目的・背景**：大量のドキュメントをカテゴリ別、時系列別、数値範囲別等にグループ化して分析・可視化するニーズに対応する。例えば、売上データを月別に集計したり、商品カテゴリ別のドキュメント数を算出する際に利用される。ダッシュボードやレポートの基盤機能となる重要な集計機能である。

**機能の利用シーン**：検索APIのaggregationsパラメータ内でバケット集計タイプを指定して利用する。複数のバケット集計をネストしたり、メトリクス集計やパイプライン集計と組み合わせて多段階の分析を行うことが可能。

**主要な処理内容**：
1. 検索リクエストからバケット集計定義をパース（AggregationBuilder）
2. バケット集計のファクトリ経由でAggregatorインスタンスを生成
3. Luceneセグメント単位でLeafBucketCollectorによりドキュメントをバケットに分類
4. 各シャードでのローカル集計結果をInternalAggregationとしてシリアライズ
5. コーディネーティングノードで各シャード結果をreduce（マージ）して最終結果を返却

**関連システム・外部連携**：Luceneインデックスのフィールドデータ・DocValues・グローバルオーディナルを使用。Star-Treeインデックスによる事前集計との統合も対応。

**権限による制御**：検索APIに対するアクセス権限に従う。インデックスレベルの読み取り権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 21 | 検索 | 補助機能 | 検索結果に対するバケット集計処理 |

## 機能種別

計算処理（集計・分析）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| type | String | Yes | バケット集計タイプ（terms, histogram, date_histogram, range, filter, filters, global, missing, nested, reverse_nested, composite, adjacency_matrix, sampler, diversified_sampler等） | サポートされるタイプ名であること |
| field | String | No | 集計対象フィールド名 | インデックスに存在するフィールドであること |
| size | Integer | No | 返却するバケット数（termsの場合デフォルト10） | 0以上の整数 |
| shard_size | Integer | No | シャードレベルで返却するバケット数 | size以上の整数 |
| min_doc_count | Long | No | バケットに含まれる最小ドキュメント数 | 0以上 |
| order | BucketOrder | No | バケットのソート順（_count, _key等） | 有効なソートキー |
| interval / fixed_interval / calendar_interval | String | No | ヒストグラム・日付ヒストグラムの間隔 | 有効な間隔値 |
| ranges | Array | No | Range集計の範囲定義 | from/toが有効な値 |
| include / exclude | String/Array | No | Terms集計のフィルタ条件 | 有効な正規表現またはリスト |
| script | Script | No | スクリプトベースの集計 | 有効なスクリプト定義 |
| missing | Object | No | フィールド値が欠損している場合の代替値 | フィールド型と互換 |

### 入力データソース

検索APIリクエストのaggregationsセクション。LuceneインデックスのDocValuesまたはフィールドデータから値を取得。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| aggregations | Object | 集計結果のルートオブジェクト |
| buckets | Array | バケットの配列 |
| key | Object | バケットのキー値 |
| doc_count | Long | バケット内のドキュメント数 |
| sub_aggregations | Object | ネストされたサブ集計結果（存在する場合） |

### 出力先

検索APIレスポンスのaggregationsフィールド内にJSON形式で返却。

## 処理フロー

### 処理シーケンス

```
1. 検索リクエスト受信
   └─ REST APIハンドラがリクエストをパース
2. AggregationBuilderの構築
   └─ 各バケット集計タイプに対応するBuilderがパラメータを保持
3. AggregatorFactoryの生成
   └─ QueryShardContextを使用してファクトリを構築
4. Aggregatorインスタンスの生成
   └─ ファクトリからAggregator（BucketsAggregator派生）を生成
5. シャードレベル集計実行
   └─ LeafBucketCollectorでセグメント単位にドキュメントをバケットに分類
6. ローカル結果の構築
   └─ InternalAggregation（InternalTerms, InternalHistogram等）としてシリアライズ
7. コーディネーティングノードでのreduce
   └─ 各シャード結果をマージし最終バケット数に切り詰め
8. レスポンス返却
   └─ JSON形式で検索レスポンスに含めて返却
```

### フローチャート

```mermaid
flowchart TD
    A[検索リクエスト受信] --> B[AggregationBuilderパース]
    B --> C[AggregatorFactory構築]
    C --> D[Aggregator生成]
    D --> E{Star-Tree対応?}
    E -->|Yes| F[StarTreeBucketCollectorで集計]
    E -->|No| G[LeafBucketCollectorで集計]
    F --> H[InternalAggregation構築]
    G --> H
    H --> I[シャード結果送信]
    I --> J[コーディネータでreduce]
    J --> K[最終結果返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-31-01 | バケットサイズ上限 | termsのsizeパラメータは返却バケット数を制限する | Terms集計 |
| BR-31-02 | シャードサイズ | shard_sizeはsizeの1.5倍+10がデフォルト | Terms集計 |
| BR-31-03 | 最小ドキュメント数 | min_doc_count未満のバケットは結果から除外 | Terms/Histogram集計 |
| BR-31-04 | マルチバケット消費制限 | search.max_bucketsの設定でバケット数上限を制御 | 全バケット集計 |
| BR-31-05 | 遅延収集 | DeferableBucketAggregatorにより不要なサブ集計を遅延実行 | ネストされた集計 |

### 計算ロジック

- Terms集計：フィールド値ごとにドキュメントをカウントし、上位size件のバケットを返却
- Histogram集計：`bucket_key = Math.floor((value - offset) / interval) * interval + offset`
- Date Histogram集計：日付のRoundingロジックによりカレンダー単位・固定間隔でバケット化
- Range集計：指定された数値範囲ごとにドキュメントを分類

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| バケット集計 | Luceneインデックス | SELECT（読取） | DocValues/フィールドデータからフィールド値を読み取り |

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

#### Luceneインデックス

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | 集計対象フィールド | 検索クエリでフィルタされたドキュメント | DocValuesまたはフィールドデータ経由 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 400 | search_phase_execution_exception | 集計パラメータが不正 | リクエストパラメータを修正 |
| 400 | illegal_argument_exception | サポートされない集計タイプ | 正しい集計タイプを指定 |
| 503 | too_many_buckets_exception | バケット数がmax_bucketsを超過 | max_buckets設定を調整するかクエリを限定 |
| 400 | illegal_argument_exception | フィールド型と集計タイプの不整合 | フィールド型に適した集計を使用 |

### リトライ仕様

バケット集計はステートレスな読み取り操作のため、クライアント側でのリトライが可能。シャード障害時はpartial結果を返却するか失敗するかをallow_partial_search_results設定で制御。

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

読み取り専用操作のためトランザクション制御は不要。検索コンテキスト内でのスナップショットの一貫性はLuceneのIndexReaderにより保証。

## パフォーマンス要件

- Terms集計のパフォーマンスはフィールドのカーディナリティに依存
- グローバルオーディナルの構築によりキーワードフィールドのTerms集計を最適化
- DeferableBucketAggregatorにより不要なサブ集計の計算を遅延・スキップ
- Star-Treeインデックスが利用可能な場合は事前集計データにより高速化

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

- インデックスの読み取り権限が必要
- フィールドレベルセキュリティが適用されている場合、許可されたフィールドのみ集計可能
- ドキュメントレベルセキュリティにより、アクセス可能なドキュメントのみが集計対象

## 備考

- バケット集計はネスト可能であり、Terms > Date Histogram > Avg のような多段集計が構築可能
- Composite集計はページネーション対応のバケット集計であり、大量のバケットを効率的に取得可能
- Sampler集計は上位Nドキュメントに対してのみサブ集計を実行し、パフォーマンスを向上させる

---

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

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

### 推奨読解順序

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

バケット集計の基盤となるデータ構造と抽象クラスを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | MultiBucketsAggregation.java | `server/src/main/java/org/opensearch/search/aggregations/bucket/MultiBucketsAggregation.java` | バケット集計結果のインターフェース。Bucketオブジェクトの構造を理解 |
| 1-2 | SingleBucketAggregation.java | `server/src/main/java/org/opensearch/search/aggregations/bucket/SingleBucketAggregation.java` | 単一バケット集計（filter, global等）のインターフェース |
| 1-3 | BucketOrder.java | `server/src/main/java/org/opensearch/search/aggregations/BucketOrder.java` | バケットのソート順定義 |

**読解のコツ**: OpenSearchの集計フレームワークはAggregationBuilder -> AggregatorFactory -> Aggregator -> InternalAggregationの階層構造で処理が流れる。各バケット集計タイプがこのパターンに従っている。

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

バケット集計の基底クラスであるBucketsAggregatorを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | BucketsAggregator.java | `server/src/main/java/org/opensearch/search/aggregations/bucket/BucketsAggregator.java` | 全バケット集計の基底クラス。docCounts配列によるバケット管理 |

**主要処理フロー**:
1. **70行目**: BucketsAggregatorクラス定義。AggregatorBaseを継承
2. **72-75行目**: BigArrays、docCounts（LongArray）、DocCountProviderをフィールドとして保持
3. **77-80行目**: コンストラクタでSearchContext等を受け取り初期化

#### Step 3: 代表的なバケット集計実装（Terms集計）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | TermsAggregationBuilder.java | `server/src/main/java/org/opensearch/search/aggregations/bucket/terms/TermsAggregationBuilder.java` | Terms集計のビルダー。size, shard_size, min_doc_count等のパラメータ管理 |
| 3-2 | TermsAggregatorFactory.java | `server/src/main/java/org/opensearch/search/aggregations/bucket/terms/TermsAggregatorFactory.java` | フィールド型に基づいてStringTermsAggregator/LongTermsAggregator等を選択 |
| 3-3 | GlobalOrdinalsStringTermsAggregator.java | `server/src/main/java/org/opensearch/search/aggregations/bucket/terms/GlobalOrdinalsStringTermsAggregator.java` | キーワードフィールドのTerms集計実装。グローバルオーディナルを使用した高効率集計 |

**主要処理フロー**:
- **69行目**: TermsAggregationBuilder.NAME = "terms"で集計名を定義
- **75-79行目**: EXECUTION_HINT、SHARD_SIZE、MIN_DOC_COUNT、REQUIRED_SIZE等のパラメータフィールド

#### Step 4: 遅延バケット収集メカニズムを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | DeferableBucketAggregator.java | `server/src/main/java/org/opensearch/search/aggregations/bucket/DeferableBucketAggregator.java` | サブ集計の遅延収集メカニズム |
| 4-2 | BestBucketsDeferringCollector.java | `server/src/main/java/org/opensearch/search/aggregations/bucket/BestBucketsDeferringCollector.java` | 最良バケットに対してのみサブ集計を実行 |

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

```
SearchAction (REST API)
    |
    +-- SearchService.executeQueryPhase()
          |
          +-- AggregationPhase.preProcess()
          |     +-- AggregatorFactories.createTopLevelAggregators()
          |           +-- TermsAggregationBuilder.build()
          |                 +-- TermsAggregatorFactory.create()
          |                       +-- GlobalOrdinalsStringTermsAggregator / LongTermsAggregator
          |
          +-- AggregationPhase.execute()
          |     +-- BucketsAggregator.getLeafCollector()
          |           +-- LeafBucketCollector.collect()
          |                 +-- collectBucket() / collectExistingBucket()
          |
          +-- AggregationPhase.buildAggregation()
                +-- BucketsAggregator.buildAggregations()
                      +-- InternalTerms / InternalHistogram 等を構築
```

### データフロー図

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

検索リクエスト       +--> AggregationBuilderパース
(aggregationsセクション)    |
                     +--> AggregatorFactory生成
                     |
Luceneセグメント     +--> LeafBucketCollector
(DocValues)          |     +-- ドキュメントをバケットに分類
                     |     +-- docCounts配列を更新
                     |
                     +--> InternalAggregation構築    +--> 検索レスポンス
                     |                                    (aggregationsフィールド)
                     +--> reduce（コーディネータ）
                           +-- シャード結果マージ
                           +-- 上位Nバケット選択
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| BucketsAggregator.java | `server/src/main/java/org/opensearch/search/aggregations/bucket/BucketsAggregator.java` | ソース | 全バケット集計の基底クラス |
| TermsAggregationBuilder.java | `server/src/main/java/org/opensearch/search/aggregations/bucket/terms/TermsAggregationBuilder.java` | ソース | Terms集計ビルダー |
| TermsAggregatorFactory.java | `server/src/main/java/org/opensearch/search/aggregations/bucket/terms/TermsAggregatorFactory.java` | ソース | Terms集計ファクトリ |
| DateHistogramAggregationBuilder.java | `server/src/main/java/org/opensearch/search/aggregations/bucket/histogram/DateHistogramAggregationBuilder.java` | ソース | Date Histogram集計ビルダー |
| HistogramAggregationBuilder.java | `server/src/main/java/org/opensearch/search/aggregations/bucket/histogram/HistogramAggregationBuilder.java` | ソース | Histogram集計ビルダー |
| RangeAggregationBuilder.java | `server/src/main/java/org/opensearch/search/aggregations/bucket/range/RangeAggregationBuilder.java` | ソース | Range集計ビルダー |
| FilterAggregationBuilder.java | `server/src/main/java/org/opensearch/search/aggregations/bucket/filter/FilterAggregationBuilder.java` | ソース | Filter集計ビルダー |
| CompositeAggregationBuilder.java | `server/src/main/java/org/opensearch/search/aggregations/bucket/composite/CompositeAggregationBuilder.java` | ソース | Composite集計ビルダー |
| DeferableBucketAggregator.java | `server/src/main/java/org/opensearch/search/aggregations/bucket/DeferableBucketAggregator.java` | ソース | 遅延バケット集計基底 |
| BucketUtils.java | `server/src/main/java/org/opensearch/search/aggregations/bucket/BucketUtils.java` | ソース | バケットユーティリティ |
| DocCountProvider.java | `server/src/main/java/org/opensearch/search/aggregations/bucket/DocCountProvider.java` | ソース | ドキュメントカウント提供 |
