# 機能設計書 117-フォースマージ

## 概要

本ドキュメントは、OpenSearchのフォースマージ（Force Merge）機能の設計書である。Luceneセグメントの強制マージを実行する機能を提供する。

### 本機能の処理概要

**業務上の目的・背景**：Luceneはドキュメントの追加・更新・削除に伴い、複数のセグメントファイルを生成する。セグメント数が増加すると検索パフォーマンスが低下する。フォースマージは、これらのセグメントを指定数以下に強制的にマージすることで、検索パフォーマンスを向上させ、ディスク使用量を最適化する。また、削除マーク付きドキュメントの物理的な除去（expunge deletes）も可能である。

**機能の利用シーン**：書き込みが停止したインデックスの最適化、定期的なインデックスメンテナンス、削除済みドキュメントの物理削除、ディスク使用量の削減などの場面で利用される。

**主要な処理内容**：
1. RESTリクエストの受付と対象インデックスの解決
2. クラスタブロックチェック（METADATA_WRITE）
3. 対象シャード（全シャードまたはプライマリのみ）の特定
4. 各シャードでIndexShard.forceMerge()を実行
5. マージ後のフラッシュ（デフォルト有効）
6. マージ結果の集約とレスポンス返却

**関連システム・外部連携**：Luceneのセグメントマージ機能に依存する。

**権限による制御**：METADATA_WRITEレベルのクラスタブロックチェック。対象インデックスへの書き込み権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 82 | 強制マージ | 主画面 | 1つ以上のインデックスで強制マージを実行する処理 |

## 機能種別

データ管理 / インデックス最適化

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| index | String | No | 対象インデックス名（カンマ区切り、未指定時は全インデックス） | 有効なインデックス名 |
| max_num_segments | int | No | マージ後の最大セグメント数（デフォルト: -1、自動判定） | -1以上の整数 |
| only_expunge_deletes | boolean | No | 削除マーク付きドキュメントの除去のみ実行（デフォルト: false） | true/false |
| flush | boolean | No | マージ後にフラッシュを実行（デフォルト: true） | true/false |
| primary_only | boolean | No | プライマリシャードのみに実行（デフォルト: false） | true/false |

### 入力データソース

REST API経由のリクエスト。`POST /{index}/_forcemerge` または `POST /_forcemerge`。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| _shards.total | int | 対象シャード総数 |
| _shards.successful | int | 成功シャード数 |
| _shards.failed | int | 失敗シャード数 |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. RESTリクエスト受付
   └─ パラメータ解析、ForceMergeRequest生成
2. クラスタブロックチェック
   └─ METADATA_WRITEレベルのグローバル・インデックスブロック確認
3. 対象シャード特定
   └─ primary_only=trueの場合はプライマリのみ、それ以外は全シャード
4. 各シャードでフォースマージ実行
   └─ IndexShard.forceMerge(request)
   └─ FORCE_MERGEスレッドプールで実行
5. レスポンス集約
   └─ 各シャードの結果を集約してForceMergeResponseを生成
```

### フローチャート

```mermaid
flowchart TD
    A[RESTリクエスト受信] --> B[ForceMergeRequest生成]
    B --> C{クラスタブロックチェック}
    C -->|ブロックあり| D[例外返却]
    C -->|OK| E{primary_only?}
    E -->|Yes| F[プライマリシャードのみ取得]
    E -->|No| G[全シャード取得]
    F --> H[各シャードでforceMerge実行]
    G --> H
    H --> I{max_num_segments指定?}
    I -->|Yes| J[指定数以下にマージ]
    I -->|No| K[必要に応じてマージ]
    J --> L{flush?}
    K --> L
    L -->|Yes| M[フラッシュ実行]
    L -->|No| N[スキップ]
    M --> O[レスポンス返却]
    N --> O
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-117-01 | デフォルトフラッシュ | マージ後にデフォルトでフラッシュが実行される | flush=true（デフォルト） |
| BR-117-02 | UUID記録 | フォースマージUUIDがコミットデータに記録される | マージ実行時 |
| BR-117-03 | ブロックチェック | METADATA_WRITEブロックがある場合は実行不可 | 常時 |
| BR-117-04 | 長時間操作 | フォースマージは時間のかかる操作であり、非同期実行が推奨される | 大規模インデックス |

### 計算ロジック

特になし。Luceneのセグメントマージポリシーに基づく。

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| フォースマージ | 対象インデックス | UPDATE | Luceneセグメントの統合 |
| フラッシュ | 対象インデックス | UPDATE | トランスログのフラッシュ |

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

フォースマージはLuceneレベルの操作であり、セグメントファイルの統合・削除マークのパージを行う。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 400 | ClusterBlockException | METADATA_WRITEブロック | ブロックを解除する |
| 500 | IOException | マージ処理中のI/Oエラー | ディスク状態を確認する |

### リトライ仕様

個別シャードの失敗はshardFailuresに記録され、他のシャードの処理は続行される。

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

各シャードの操作は独立して実行される。全体のロールバック機能はない。

## パフォーマンス要件

- フォースマージは重いI/O操作であり、FORCE_MERGEスレッドプールで実行される
- 大規模インデックスでは長時間かかる可能性がある
- 書き込みが活発なインデックスでの実行は推奨されない

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

- METADATA_WRITEレベルの権限チェック
- 対象インデックスへのアクセス権限

## 備考

- アクション名: indices:admin/forcemerge
- スレッドプール: FORCE_MERGE
- TransportBroadcastByNodeActionを拡張

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ForceMergeRequest.java | `server/src/main/java/org/opensearch/action/admin/indices/forcemerge/ForceMergeRequest.java` | リクエストパラメータ：maxNumSegments, onlyExpungeDeletes, flush, primaryOnly, forceMergeUUID |

**読解のコツ**: ForceMergeRequestはBroadcastRequestを拡張し、ブロードキャスト操作としてクラスタ内の全対象シャードに配信される。Defaultsサブクラスにデフォルト値が定義されている。

**主要処理フロー**:
- **70-75行目**: Defaults定義。MAX_NUM_SEGMENTS=-1, ONLY_EXPUNGE_DELETES=false, FLUSH=true, PRIMARY_ONLY=false
- **88-89行目**: forceMergeUUID。各フォースマージ操作に一意のUUIDを割り当て
- **97-99行目**: コンストラクタ。UUIDs.randomBase64UUID()でUUID生成

#### Step 2: トランスポートアクションを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | TransportForceMergeAction.java | `server/src/main/java/org/opensearch/action/admin/indices/forcemerge/TransportForceMergeAction.java` | ブロードキャスト操作のメインロジック |

**主要処理フロー**:
- **60-63行目**: TransportBroadcastByNodeActionを拡張
- **82行目**: FORCE_MERGEスレッドプールで実行
- **111-114行目**: shardOperation。IndexShardを取得してforceMerge(request)を実行
- **122-128行目**: shards()。primary_only=trueの場合はプライマリのみ、それ以外は全シャード
- **131-133行目**: checkGlobalBlock。METADATA_WRITEブロック確認

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

```
REST: POST /{index}/_forcemerge
    |
    +-- RestForceMergeAction
            |
            +-- TransportForceMergeAction
                    |
                    +-- checkGlobalBlock (METADATA_WRITE)
                    +-- checkRequestBlock (METADATA_WRITE)
                    +-- shards() (全シャードまたはプライマリのみ)
                    +-- shardOperation()
                            |
                            +-- IndicesService.indexServiceSafe()
                            +-- IndexService.getShard()
                            +-- IndexShard.forceMerge(request)
```

### データフロー図

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

REST Request         --> ForceMergeRequest生成           --> ブロードキャストリクエスト
  (max_num_segments,
   only_expunge_deletes,     +-> 各ノードに配信
   flush, primary_only)      +-> 各シャードでforceMerge     --> EmptyResult

                             +-> 結果集約                  --> ForceMergeResponse
                                                              (_shards: total/successful/failed)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ForceMergeAction.java | `server/src/main/java/org/opensearch/action/admin/indices/forcemerge/ForceMergeAction.java` | ソース | アクション定義 |
| ForceMergeRequest.java | `server/src/main/java/org/opensearch/action/admin/indices/forcemerge/ForceMergeRequest.java` | ソース | リクエストデータ構造 |
| ForceMergeResponse.java | `server/src/main/java/org/opensearch/action/admin/indices/forcemerge/ForceMergeResponse.java` | ソース | レスポンスデータ構造 |
| ForceMergeRequestBuilder.java | `server/src/main/java/org/opensearch/action/admin/indices/forcemerge/ForceMergeRequestBuilder.java` | ソース | リクエストビルダー |
| TransportForceMergeAction.java | `server/src/main/java/org/opensearch/action/admin/indices/forcemerge/TransportForceMergeAction.java` | ソース | トランスポートアクション |
