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

## はじめに

このガイドラインは、OpenSearch (v3.5.0) のコードベースを効率的に理解するための手引きです。
Javaに精通していないエンジニアでも、段階的に学習できるよう構成されています。

**対象読者:**
- プロジェクトに新規参画するエンジニア
- 他言語からの経験者
- コードレビューを行う担当者

**プロジェクト概要:**
- 言語: Java (JDK 11+)
- ビルドシステム: Gradle (gradlew ラッパー)
- コア依存: Apache Lucene 10.3.2, Netty 4.2.9, Jackson 2.20.1, Log4j 2.25.3, gRPC 1.75.0
- ソースファイル数: Java 11,239ファイル

---

## 1. 言語基礎

> このセクションでは、Javaの基本構文とOpenSearchで使用される概念を解説します。

### 1.1 プログラム構造

Javaプログラムは**パッケージ宣言**、**インポート文**、**クラス定義**の3つのブロックで構成されます。OpenSearchでは `org.opensearch` をルートパッケージとしています。

```java
// ファイル: server/src/main/java/org/opensearch/bootstrap/OpenSearch.java:33-60
package org.opensearch.bootstrap;                    // パッケージ宣言

import org.opensearch.cli.ExitCodes;                 // インポート文
import org.opensearch.cli.Terminal;
import org.opensearch.common.cli.EnvironmentAwareCommand;
import org.opensearch.common.logging.LogConfigurator;

class OpenSearch extends EnvironmentAwareCommand {   // クラス定義
    // フィールド、コンストラクタ、メソッドがここに含まれる
}
```

ソースファイルの配置規則として、パッケージ名がそのままディレクトリ構造に対応します。例えば `org.opensearch.bootstrap` パッケージのクラスは `server/src/main/java/org/opensearch/bootstrap/` ディレクトリに配置されます。

### 1.2 データ型と変数

Javaは**静的型付け言語**です。変数宣言時に型を明示します。OpenSearchではプリミティブ型、配列、ジェネリクス付きコレクションが頻出します。

```java
// ファイル: server/src/main/java/org/opensearch/action/search/SearchRequest.java:87-129
public static final int DEFAULT_PRE_FILTER_SHARD_SIZE = 128;     // int型定数
public static final int DEFAULT_BATCHED_REDUCE_SIZE = 512;       // int型定数

private SearchType searchType = SearchType.DEFAULT;               // 列挙型
private String[] indices = Strings.EMPTY_ARRAY;                   // String配列
private Boolean requestCache;                                     // ラッパー型(null許容)
private int batchedReduceSize = DEFAULT_BATCHED_REDUCE_SIZE;      // プリミティブ型
private boolean ccsMinimizeRoundtrips = true;                     // プリミティブ型
```

**修飾子の意味:**
| 修飾子 | 意味 |
|--------|------|
| `private` | クラス内部のみアクセス可 |
| `public` | どこからでもアクセス可 |
| `protected` | 同パッケージとサブクラスからアクセス可 |
| `static` | インスタンスに依存しないクラスレベルの変数/メソッド |
| `final` | 再代入不可(定数化) |
| `volatile` | マルチスレッドでの可視性保証 |

### 1.3 制御構造

条件分岐、ループ、例外処理はJavaの標準的な構文を使用します。

```java
// ファイル: server/src/main/java/org/opensearch/bootstrap/OpenSearch.java:129-163
@Override
protected void execute(Terminal terminal, OptionSet options, Environment env) throws UserException {
    // 条件分岐: if文
    if (options.nonOptionArguments().isEmpty() == false) {
        throw new UserException(ExitCodes.USAGE, "Positional arguments not allowed, found " + options.nonOptionArguments());
    }
    if (options.has(versionOption)) {
        // ... バージョン出力
        return;
    }

    final boolean daemonize = options.has(daemonizeOption);
    final Path pidFile = pidfileOption.value(options);

    // try-catch: 例外処理
    try {
        env.validateTmpDir();
    } catch (IOException e) {
        throw new UserException(ExitCodes.CONFIG, e.getMessage());
    }

    try {
        init(daemonize, pidFile, quiet, env);
    } catch (NodeValidationException e) {
        throw new UserException(ExitCodes.CONFIG, e.getMessage());
    }
}
```

```java
// ファイル: server/src/main/java/org/opensearch/bootstrap/OpenSearch.java:109-122
// for-eachループ
for (final String property : new String[] { "networkaddress.cache.ttl", "networkaddress.cache.negative.ttl" }) {
    final String overrideProperty = "opensearch." + property;
    final String overrideValue = System.getProperty(overrideProperty);
    if (overrideValue != null) {
        try {
            Security.setProperty(property, Integer.toString(Integer.valueOf(overrideValue)));
        } catch (final NumberFormatException e) {
            throw new IllegalArgumentException("failed to parse [" + overrideProperty + "]", e);
        }
    }
}
```

### 1.4 関数/メソッド定義

Javaではすべての関数はクラスのメソッドとして定義されます。OpenSearchでは `@Override` アノテーションによるメソッドオーバーライドが頻出します。

```java
// ファイル: server/src/main/java/org/opensearch/rest/action/RestMainAction.java:61-78
@Override
public List<Route> routes() {                                    // 戻り値型: List<Route>
    return unmodifiableList(asList(new Route(GET, "/"), new Route(HEAD, "/")));
}

@Override
public String getName() {                                        // 戻り値型: String
    return "main_action";
}

@Override
public RestChannelConsumer prepareRequest(                       // 戻り値型: RestChannelConsumer
    final RestRequest request,                                   // 引数: RestRequest
    final NodeClient client                                      // 引数: NodeClient
) throws IOException {
    return channel -> client.execute(                             // ラムダ式による関数型インターフェース実装
        MainAction.INSTANCE,
        new MainRequest(),
        new RestBuilderListener<MainResponse>(channel) {         // 匿名内部クラス
            @Override
            public RestResponse buildResponse(MainResponse mainResponse, XContentBuilder builder) throws Exception {
                return convertMainResponse(mainResponse, request, builder);
            }
        }
    );
}
```

### 1.5 モジュール/インポート

Javaでは `import` 文でクラスを読み込みます。OpenSearchではプロジェクト内パッケージ間の参照と外部ライブラリの参照の2種類があります。

```java
// ファイル: server/src/main/java/org/opensearch/rest/action/RestMainAction.java:35-52
// プロジェクト内部のインポート (org.opensearch.*)
import org.opensearch.action.main.MainAction;
import org.opensearch.action.main.MainRequest;
import org.opensearch.action.main.MainResponse;
import org.opensearch.core.rest.RestStatus;
import org.opensearch.rest.BaseRestHandler;
import org.opensearch.rest.RestRequest;
import org.opensearch.transport.client.node.NodeClient;

// Java標準ライブラリのインポート
import java.io.IOException;
import java.util.List;

// staticインポート: メソッドやフィールドを直接参照可能にする
import static java.util.Arrays.asList;
import static java.util.Collections.unmodifiableList;
import static org.opensearch.rest.RestRequest.Method.GET;
import static org.opensearch.rest.RestRequest.Method.HEAD;
```

**パッケージ構造のルール:**
- `org.opensearch.core.*` - コアAPIインターフェース(libs/coreモジュール)
- `org.opensearch.common.*` - 共通ユーティリティ
- `org.opensearch.action.*` - アクション(リクエスト/レスポンス処理)
- `org.opensearch.rest.*` - REST API層
- `org.opensearch.cluster.*` - クラスタ管理
- `org.opensearch.index.*` - インデックス管理
- `org.opensearch.search.*` - 検索エンジン
- `org.opensearch.transport.*` - ノード間通信

---

## 2. プロジェクト固有の概念

> このセクションでは、OpenSearch特有の概念を解説します。

### 2.1 フレームワーク固有の概念

#### カスタムDIフレームワーク (Guice Fork)

OpenSearchはGoogle Guiceのフォーク版(`org.opensearch.common.inject`)を内蔵しています。`@Inject` アノテーションによりコンストラクタインジェクションを実現します。

```java
// ファイル: server/src/main/java/org/opensearch/common/inject/Inject.java:66-81
@Target({ METHOD, CONSTRUCTOR, FIELD })
@Retention(RUNTIME)
@Documented
public @interface Inject {
    boolean optional() default false;
}
```

```java
// ファイル: server/src/main/java/org/opensearch/action/search/TransportSearchAction.java:192-199
@Inject
public TransportSearchAction(
    NodeClient client,
    ThreadPool threadPool,
    CircuitBreakerService circuitBreakerService,
    TransportService transportService,
    SearchService searchService,
    SearchTransportService searchTransportService,
    // ... 多数の依存が注入される
```

#### ライフサイクル管理

コンポーネントの起動・停止を統一的に管理するための `AbstractLifecycleComponent` パターンを採用しています。

```java
// ファイル: libs/common/src/main/java/org/opensearch/common/lifecycle/AbstractLifecycleComponent.java:45-85
public abstract class AbstractLifecycleComponent implements LifecycleComponent {
    protected final Lifecycle lifecycle = new Lifecycle();
    private final List<LifecycleListener> listeners = new CopyOnWriteArrayList<>();

    @Override
    public void start() {
        synchronized (lifecycle) {
            if (!lifecycle.canMoveToStarted()) return;
            for (LifecycleListener listener : listeners) listener.beforeStart();
            doStart();                                    // サブクラスで実装
            lifecycle.moveToStarted();
            for (LifecycleListener listener : listeners) listener.afterStart();
        }
    }

    protected abstract void doStart();                    // テンプレートメソッドパターン
    protected abstract void doStop();
    protected abstract void doClose() throws IOException;
}
```

`ClusterService` はこのパターンの代表的な実装例です。

```java
// ファイル: server/src/main/java/org/opensearch/cluster/service/ClusterService.java:69
@PublicApi(since = "1.0.0")
public class ClusterService extends AbstractLifecycleComponent {
    // ...
}
```

#### PublicApi / ExperimentalApi アノテーション

OpenSearchではAPIの安定性を示すためにカスタムアノテーションを使用します。

| アノテーション | 意味 |
|---------------|------|
| `@PublicApi(since = "x.x.x")` | 安定版公開API。互換性が保証される |
| `@ExperimentalApi` | 実験的API。変更・削除の可能性あり |
| `@opensearch.internal` (Javadocタグ) | 内部API。外部使用は非推奨 |
| `@opensearch.api` (Javadocタグ) | 公開APIであることを示す |

### 2.2 プロジェクト独自のパターン

#### ActionListenerパターン (非同期コールバック)

OpenSearchでは非同期処理の結果通知に `ActionListener<T>` インターフェースを広く使用しています。成功時に `onResponse(T)`、失敗時に `onFailure(Exception)` が呼ばれます。

```java
// ファイル: server/src/main/java/org/opensearch/rest/action/RestMainAction.java:72-79
return channel -> client.execute(
    MainAction.INSTANCE,
    new MainRequest(),
    new RestBuilderListener<MainResponse>(channel) {    // ActionListenerの実装
        @Override
        public RestResponse buildResponse(MainResponse mainResponse, XContentBuilder builder) throws Exception {
            return convertMainResponse(mainResponse, request, builder);
        }
    }
);
```

#### REST Action チェーンパターン

REST APIリクエストは以下の階層で処理されます:

```
RestHandler (インターフェース)
  -> BaseRestHandler (基底クラス)
    -> RestSearchAction 等 (具象REST処理)
      -> TransportSearchAction 等 (トランスポート処理)
        -> SearchService 等 (実際のビジネスロジック)
```

#### Settingフレームワーク

設定値の宣言的な管理を行うフレームワークです。

```java
// ファイル: server/src/main/java/org/opensearch/action/search/TransportSearchAction.java:147-153
public static final Setting<Long> SHARD_COUNT_LIMIT_SETTING = Setting.longSetting(
    "action.search.shard_count.limit",     // 設定キー
    Long.MAX_VALUE,                        // デフォルト値
    1L,                                    // 最小値
    Property.Dynamic,                      // 動的変更可能
    Property.NodeScope                     // ノードレベル設定
);
```

---

## 3. 命名規則

> このセクションでは、プロジェクト全体で使用される命名規則を解説します。

### 3.1 ファイル・ディレクトリ命名

| パターン | 意味 | 例 |
|---------|------|-----|
| `PascalCase.java` | Javaソースファイル(クラス名と同一) | `SearchRequest.java`, `Node.java` |
| `*Tests.java` / `*Test.java` | テストクラス | `SearchRequestTests.java` |
| `*IT.java` | 統合テスト | `SearchIT.java` |
| `package-info.java` | パッケージレベルのJavadoc | 各パッケージに配置 |
| `小文字ハイフン区切り` | ディレクトリ名(Gradleモジュール) | `rest-api-spec`, `build-tools` |

### 3.2 クラス・関数・変数命名

| プレフィックス/サフィックス | 意味 | 例 |
|---------------------------|------|-----|
| `*Service` | サービスクラス(ビジネスロジックの中核) | `ClusterService`, `SearchService`, `IndicesService` |
| `*Action` | アクション定義(REST/Transportの処理単位) | `SearchAction`, `ClusterHealthAction` |
| `Transport*Action` | トランスポート層のアクション実装 | `TransportSearchAction`, `TransportClusterHealthAction` |
| `Rest*Action` | REST APIハンドラ | `RestSearchAction`, `RestMainAction` |
| `*Request` | リクエストオブジェクト | `SearchRequest`, `MainRequest` |
| `*Response` | レスポンスオブジェクト | `SearchResponse`, `MainResponse` |
| `*Exception` | 例外クラス | `OpenSearchException`, `NodeValidationException` |
| `*Plugin` | プラグインインターフェース | `ActionPlugin`, `SearchPlugin`, `AnalysisPlugin` |
| `*Module` | Guice DIモジュール | `ActionModule`, `ClusterModule`, `NetworkModule` |
| `*Builder` | ビルダーパターン | `SearchSourceBuilder`, `QueryBuilder` |
| `*Settings` | 設定管理 | `ClusterSettings`, `IndexSettings` |
| `Abstract*` | 抽象基底クラス | `AbstractLifecycleComponent`, `AbstractModule` |
| `Internal*` | 内部実装(外部使用非推奨) | `InternalSearchResponse`, `InternalAggregation` |
| `*Listener` | イベントリスナー | `ActionListener`, `LifecycleListener` |
| `*Handler` | ハンドラ(処理委譲先) | `RestHandler`, `BaseRestHandler` |

### 3.3 プログラム分類一覧

| 分類 | パッケージ | 命名パターン | 役割 |
|------|-----------|-------------|------|
| RESTハンドラ | `org.opensearch.rest.action.*` | `Rest*Action` | HTTP APIエンドポイント |
| トランスポートアクション | `org.opensearch.action.*` | `Transport*Action` | 内部通信でのアクション実行 |
| サービス | 各パッケージ | `*Service` | ビジネスロジック |
| リクエスト/レスポンス | `org.opensearch.action.*` | `*Request` / `*Response` | データ転送オブジェクト |
| プラグイン | `org.opensearch.plugins` | `*Plugin` | 拡張ポイントインターフェース |
| モジュール | 各パッケージ | `*Module` | DI設定 |
| 設定 | `org.opensearch.common.settings` | `*Settings` / `Setting<T>` | 設定管理 |
| テスト | `*Tests` / `*IT` | テストクラス | 検証コード |

---

## 4. ディレクトリ構造

> このセクションでは、プロジェクトのディレクトリ構造を解説します。

```
OpenSearch-main/
├── server/                    # メインサーバー実装 (最重要)
│   ├── src/main/java/org/opensearch/
│   │   ├── bootstrap/         # 起動処理
│   │   ├── node/              # ノード管理
│   │   ├── cluster/           # クラスタ管理
│   │   ├── action/            # アクション定義
│   │   ├── rest/              # REST API層
│   │   ├── index/             # インデックス管理
│   │   ├── search/            # 検索エンジン
│   │   ├── transport/         # ノード間通信
│   │   ├── common/            # 共通ユーティリティ
│   │   └── plugins/           # プラグインAPI定義
│   ├── src/test/              # ユニットテスト
│   └── src/internalClusterTest/ # 統合テスト
├── libs/                      # コアライブラリ群
│   ├── core/                  # コアAPI・インターフェース
│   ├── common/                # 共通ユーティリティ
│   ├── x-content/             # JSON/YAML等のコンテンツ処理
│   └── ...                    # その他ライブラリ
├── modules/                   # 26のビルトインモジュール
│   ├── lang-painless/         # Painlessスクリプトエンジン
│   ├── analysis-common/       # 共通アナライザ
│   ├── transport-netty4/      # Netty4トランスポート
│   └── ...
├── plugins/                   # 33のプラグイン実装
│   ├── analysis-icu/          # ICUアナライザ
│   ├── repository-s3/         # S3リポジトリ
│   └── ...
├── client/                    # Javaクライアントライブラリ
├── distribution/              # 配布パッケージング
├── buildSrc/                  # Gradleビルドプラグイン
├── test/                      # テストフレームワーク
│   └── framework/             # テストユーティリティ
├── qa/                        # 品質保証テストスイート
│   ├── rolling-upgrade/       # ローリングアップグレードテスト
│   ├── mixed-cluster/         # 混合クラスタテスト
│   └── evil-tests/            # システムレベルテスト
├── rest-api-spec/             # REST API仕様(YAML)
├── benchmarks/                # パフォーマンスベンチマーク
└── sandbox/                   # 実験的機能
```

### 各ディレクトリの役割

| ディレクトリ | 役割 | 主要ファイル |
|-------------|------|-------------|
| `server/` | OpenSearchのコアサーバー実装。全機能の中心 | `Node.java`, `Bootstrap.java`, `ClusterService.java` |
| `libs/core/` | コアAPIインターフェース定義。外部依存のない純粋なAPI | `ActionListener.java`, `StreamInput/Output.java` |
| `libs/common/` | 共通ユーティリティ(ライフサイクル、設定等) | `AbstractLifecycleComponent.java`, `Lifecycle.java` |
| `modules/` | ビルトインモジュール(配布物に同梱) | 各モジュール内の `*Plugin.java` |
| `plugins/` | オプショナルプラグイン(個別インストール) | 各プラグイン内の `*Plugin.java` |
| `client/` | Javaクライアントライブラリ | `RestHighLevelClient.java` |
| `buildSrc/` | Gradleカスタムプラグイン(ビルドロジック) | `*.gradle`, `*.java` |
| `test/framework/` | テスト用基底クラス・ユーティリティ | `OpenSearchTestCase.java`, `OpenSearchIntegTestCase.java` |
| `qa/` | E2Eテスト・互換性テスト | `*IT.java` |
| `rest-api-spec/` | REST API仕様定義(YAMLフォーマット) | `*.json` (API仕様) |
| `benchmarks/` | JMHベンチマーク | `*Benchmark.java` |
| `sandbox/` | 実験的機能(フィーチャーフラグ管理下) | 各実験機能の実装 |

---

## 5. アーキテクチャ

> このセクションでは、プロジェクトのアーキテクチャパターンを解説します。

### 5.1 全体アーキテクチャ

OpenSearchは**レイヤードアーキテクチャ**と**プラグインアーキテクチャ**を組み合わせた設計です。

```
                         ┌─────────────────────────────────────┐
                         │          Client (REST/HTTP)          │
                         └───────────────┬─────────────────────┘
                                         │
                         ┌───────────────▼─────────────────────┐
                         │      REST Layer (RestHandler)        │
                         │  RestSearchAction, RestMainAction    │
                         └───────────────┬─────────────────────┘
                                         │
                         ┌───────────────▼─────────────────────┐
                         │   Action Layer (TransportAction)     │
                         │  TransportSearchAction, etc.         │
                         └───────────────┬─────────────────────┘
                                         │
              ┌──────────────────────────┼──────────────────────────┐
              │                          │                          │
  ┌───────────▼───────────┐  ┌───────────▼───────────┐  ┌──────────▼──────────┐
  │   Cluster Service     │  │   Search Service      │  │  Indices Service    │
  │   (ClusterState管理)  │  │   (検索実行)          │  │  (インデックス管理) │
  └───────────┬───────────┘  └───────────┬───────────┘  └──────────┬──────────┘
              │                          │                          │
  ┌───────────▼──────────────────────────▼──────────────────────────▼──────────┐
  │                     Transport Layer (ノード間通信)                         │
  │                     TransportService, Netty4Transport                     │
  └───────────┬───────────────────────────────────────────────────────────────┘
              │
  ┌───────────▼───────────────────────────────────────────────────────────────┐
  │                     Lucene (検索エンジンコア)                              │
  └───────────────────────────────────────────────────────────────────────────┘
```

### 5.2 レイヤー構成

| レイヤー | 責務 | 代表的なファイル |
|---------|------|-----------------|
| Bootstrap | プロセス起動・初期化 | `OpenSearch.java`, `Bootstrap.java` |
| Node | ノードインスタンスの管理・DIコンテナ構築 | `Node.java` |
| REST | HTTP APIエンドポイント処理 | `RestHandler.java`, `BaseRestHandler.java`, `RestSearchAction.java` |
| Action | アクション(ビジネスロジック)実行 | `TransportSearchAction.java`, `SearchAction.java` |
| Service | ドメイン固有の処理 | `ClusterService.java`, `SearchService.java`, `IndicesService.java` |
| Transport | ノード間通信 | `TransportService.java`, `Netty4Transport.java` |
| Index/Shard | データストア(Luceneラッパー) | `IndexService.java`, `IndexShard.java` |
| Plugin | 拡張ポイント | `Plugin.java`, `ActionPlugin.java` |

### 5.3 データフロー

REST APIリクエストのデータフロー:

```
1. HTTP Request
   → 2. RestController (URLルーティング)
     → 3. RestXxxAction.prepareRequest() (リクエスト解析)
       → 4. NodeClient.execute() (アクション実行)
         → 5. TransportXxxAction.doExecute() (トランスポート処理)
           → 6. XxxService (ビジネスロジック)
             → 7. ActionListener.onResponse() (レスポンス返却)
               → 8. RestResponse (HTTP Response)
```

---

## 6. 主要コンポーネント

> このセクションでは、主要なコンポーネントとその連携を解説します。

### 6.1 エントリーポイント

OpenSearchの起動は以下の順序で行われます:

**ステップ1: OpenSearch.main()** -- プロセスのエントリーポイント

```java
// ファイル: server/src/main/java/org/opensearch/bootstrap/OpenSearch.java:86-107
@SuppressWarnings("removal")
public static void main(final String[] args) throws Exception {
    overrideDnsCachePolicyProperties();     // DNS設定のオーバーライド
    LogConfigurator.registerErrorListener(); // ログ設定
    final OpenSearch opensearch = new OpenSearch();
    int status = main(args, opensearch, Terminal.DEFAULT);
    if (status != ExitCodes.OK) {
        // エラーログ出力とプロセス終了
        exit(status);
    }
}
```

**ステップ2: Bootstrap.init()** -- 内部初期化

```java
// ファイル: server/src/main/java/org/opensearch/bootstrap/Bootstrap.java:89-93
final class Bootstrap {
    private static volatile Bootstrap INSTANCE;
    private volatile Node node;                  // Nodeインスタンスを保持
    private final CountDownLatch keepAliveLatch = new CountDownLatch(1);
    // ...
}
```

Bootstrap は以下を実行します:
1. ネイティブリソースの初期化(メモリロック、システムコールフィルタ等)
2. `Node` インスタンスの生成
3. KeepAliveスレッドの起動

**ステップ3: Node** -- コアノード実装(約2,475行)

`Node.java` はOpenSearchの中核で、すべてのサービスのDI設定と起動を管理します。

```java
// ファイル: server/src/main/java/org/opensearch/node/Node.java:33-99 (importの一部)
// Node.javaは100以上のクラスをインポートしており、
// ClusterService, SearchService, IndicesService, TransportService等
// すべてのコアサービスをここで組み立てます。
```

### 6.2 ビジネスロジック

ビジネスロジックは主に `*Service` クラスと `Transport*Action` クラスに実装されています。

**TransportSearchAction** -- 検索処理の中核:

```java
// ファイル: server/src/main/java/org/opensearch/action/search/TransportSearchAction.java:142-190
public class TransportSearchAction extends HandledTransportAction<SearchRequest, SearchResponse>
    implements TransportIndicesResolvingAction<SearchRequest> {

    final NodeClient client;
    private final ThreadPool threadPool;
    final ClusterService clusterService;
    final SearchTransportService searchTransportService;
    private final RemoteClusterService remoteClusterService;
    final SearchPhaseController searchPhaseController;
    private final SearchService searchService;
    private final IndexNameExpressionResolver indexNameExpressionResolver;
    // ... 多数のサービス依存
}
```

**ClusterService** -- クラスタ状態管理:

```java
// ファイル: server/src/main/java/org/opensearch/cluster/service/ClusterService.java:69-72
@PublicApi(since = "1.0.0")
public class ClusterService extends AbstractLifecycleComponent {
    private final ClusterManagerService clusterManagerService;
    private final ClusterApplierService clusterApplierService;
    // ...
}
```

### 6.3 データアクセス

OpenSearchのデータアクセスはApache Luceneを介して行われます。主要なクラス階層は:

- `IndicesService` -- 全インデックスの管理
- `IndexService` -- 単一インデックスの管理
- `IndexShard` -- 単一シャードの管理(Lucene IndexWriterを保持)

データの読み書きは `IndexShard` を通じて行われ、Luceneの `Directory`, `IndexWriter`, `IndexReader` を内部的に使用します。

### 6.4 ユーティリティ/共通機能

| ユーティリティ | パッケージ | 用途 |
|---------------|-----------|------|
| `Settings` / `Setting<T>` | `org.opensearch.common.settings` | 型安全な設定管理 |
| `XContentBuilder` | `org.opensearch.core.xcontent` | JSON/YAML等のコンテンツ生成 |
| `StreamInput` / `StreamOutput` | `org.opensearch.core.common.io.stream` | バイナリシリアライゼーション |
| `ThreadPool` | `org.opensearch.threadpool` | スレッドプール管理 |
| `TimeValue` | `org.opensearch.common.unit` | 時間値の統一的な表現 |
| `ByteSizeValue` | `org.opensearch.core.common.unit` | バイトサイズの統一的な表現 |

---

## 7. よく使われるパターン

> このセクションでは、コード内で頻出するパターンを解説します。

### パターン一覧

| パターン | 説明 | 出現頻度 | 代表的なファイル |
|---------|------|---------|-----------------|
| ActionListenerコールバック | 非同期処理の結果通知 | 高 | `TransportSearchAction.java` |
| テンプレートメソッド | 基底クラスでフロー定義、サブクラスで詳細実装 | 高 | `AbstractLifecycleComponent.java`, `BaseRestHandler.java` |
| ビルダーパターン | 不変オブジェクトの段階的構築 | 高 | `SearchSourceBuilder.java`, `Settings.builder()` |
| DIコンストラクタインジェクション | `@Inject`による依存注入 | 高 | `TransportSearchAction.java` |
| FunctionalInterface / ラムダ | 関数型インターフェースとラムダ式 | 高 | `RestHandler.java`, `RestMainAction.java` |
| Setting宣言パターン | 設定値の宣言的定義 | 中 | `TransportSearchAction.java` |
| プラグイン拡張ポイント | インターフェースによる拡張 | 中 | `Plugin.java`, `ActionPlugin.java` |

### 各パターンの詳細

#### パターン1: ActionListenerコールバック

**目的:** 非同期処理の結果を呼び出し元にコールバックで返す。OpenSearch全体で最も頻出するパターン。

**実装例:**
```java
// ファイル: server/src/main/java/org/opensearch/rest/action/RestMainAction.java:72-79
return channel -> client.execute(
    MainAction.INSTANCE,
    new MainRequest(),
    new RestBuilderListener<MainResponse>(channel) {
        @Override
        public RestResponse buildResponse(MainResponse mainResponse, XContentBuilder builder) throws Exception {
            return convertMainResponse(mainResponse, request, builder);
        }
    }
);
```

**解説:** `client.execute()` は非同期実行され、処理完了時に `ActionListener` の `onResponse()` (成功時) または `onFailure()` (失敗時) が呼ばれます。`RestBuilderListener` は `ActionListener` の実装であり、レスポンスをRESTチャネルに書き戻す処理を担います。

#### パターン2: テンプレートメソッドパターン

**目的:** 処理フローを基底クラスで定義し、具体的な処理内容をサブクラスに委譲する。

**実装例:**
```java
// ファイル: libs/common/src/main/java/org/opensearch/common/lifecycle/AbstractLifecycleComponent.java:69-83
@Override
public void start() {
    synchronized (lifecycle) {
        if (!lifecycle.canMoveToStarted()) return;
        for (LifecycleListener listener : listeners) listener.beforeStart();
        doStart();                          // サブクラスで実装
        lifecycle.moveToStarted();
        for (LifecycleListener listener : listeners) listener.afterStart();
    }
}

protected abstract void doStart();          // サブクラスで実装が必要
```

**解説:** `start()` メソッドで「状態チェック -> リスナー通知 -> 実処理 -> 状態遷移 -> リスナー通知」のフローを定義し、`doStart()` という抽象メソッドで実処理をサブクラスに委譲します。`stop()`, `close()` も同様の構造です。

#### パターン3: REST Action チェーン

**目的:** RESTリクエストをパース、バリデーション、実行、レスポンス生成の各ステップに分解する。

**実装例:**
```java
// ファイル: server/src/main/java/org/opensearch/rest/action/search/RestSearchAction.java:90-129
public class RestSearchAction extends BaseRestHandler {

    @Override
    public String getName() {
        return "search_action";
    }

    @Override
    public List<Route> routes() {
        return unmodifiableList(asList(
            new Route(GET, "/_search"),
            new Route(POST, "/_search"),
            new Route(GET, "/{index}/_search"),
            new Route(POST, "/{index}/_search")
        ));
    }

    // prepareRequest()でリクエストを解析し、
    // TransportSearchActionに処理を委譲
}
```

**解説:** `BaseRestHandler` が `handleRequest()` を実装し、パラメータの検証後に `prepareRequest()` を呼び出します。サブクラスは `routes()` でURLパターンを定義し、`prepareRequest()` でリクエスト解析とアクション実行を行います。

#### パターン4: プラグイン拡張ポイント

**目的:** コアの変更なしに機能を追加可能にする。

**実装例:**
```java
// ファイル: server/src/main/java/org/opensearch/plugins/Plugin.java:93-119
@PublicApi(since = "1.0.0")
public abstract class Plugin implements Closeable {

    // Guiceモジュールの追加
    public Collection<Module> createGuiceModules() {
        return Collections.emptyList();
    }

    // ライフサイクル管理されるサービスの追加
    public Collection<Class<? extends LifecycleComponent>> getGuiceServiceClasses() {
        return Collections.emptyList();
    }
}
```

**解説:** `Plugin` 基底クラスはデフォルト実装(空リスト返却)を持つ各種メソッドを定義します。プラグインは必要なメソッドのみオーバーライドし、また `ActionPlugin`, `SearchPlugin` 等の特化インターフェースを追加実装することで機能を拡張します。

---

## 8. 業務フロー追跡の実践例

> このセクションでは、実際の業務フローをコードで追跡する方法を解説します。

### 8.1 フロー追跡の基本手順

1. エントリーポイントを特定(REST APIの場合は `Rest*Action` クラス)
2. `routes()` メソッドでURLパターンを確認
3. `prepareRequest()` でリクエスト解析処理を追跡
4. `client.execute()` の呼び出し先 `Transport*Action` を追跡
5. `ActionListener` のコールバックでレスポンス生成を確認

### 8.2 フロー追跡の実例

#### 例1: 検索リクエスト (`GET /_search`) の処理フロー

**概要:** クライアントからの検索リクエストがOpenSearch内部でどのように処理されるかを追跡します。

**処理フロー:**
```
HTTP GET /_search
  → RestSearchAction.prepareRequest()
    → NodeClient.execute(SearchAction.INSTANCE, SearchRequest, ActionListener)
      → TransportSearchAction.doExecute()
        → SearchService (各シャードでクエリ実行)
          → ActionListener.onResponse(SearchResponse)
            → RestResponse (HTTP 200)
```

**詳細な追跡:**

1. **URLルーティング** (`server/src/main/java/org/opensearch/rest/action/search/RestSearchAction.java:122-129`)
   ```java
   @Override
   public List<Route> routes() {
       return unmodifiableList(asList(
           new Route(GET, "/_search"),
           new Route(POST, "/_search"),
           new Route(GET, "/{index}/_search"),
           new Route(POST, "/{index}/_search")
       ));
   }
   ```
   `RestController` がURLパターンに基づいて `RestSearchAction` にディスパッチします。

2. **RESTリクエスト解析** (`RestSearchAction.prepareRequest()`)
   HTTPパラメータ(クエリ文字列、リクエストボディ)から `SearchRequest` オブジェクトを構築します。

3. **アクション実行** (`TransportSearchAction`)
   ```java
   // ファイル: server/src/main/java/org/opensearch/action/search/TransportSearchAction.java:142-144
   public class TransportSearchAction extends HandledTransportAction<SearchRequest, SearchResponse>
       implements TransportIndicesResolvingAction<SearchRequest> {
   ```
   `SearchRequest` を受け取り、クラスタ状態からターゲットシャードを特定し、各シャードに対して並行にクエリを実行します。

4. **レスポンス返却**
   各シャードの結果が `SearchPhaseController` で統合され、`ActionListener.onResponse(SearchResponse)` を通じてREST層に返却されます。

#### 例2: ノード起動フロー

**概要:** OpenSearchプロセスの起動から、クラスタ参加までのフロー。

**処理フロー:**
```
OpenSearch.main()
  → Bootstrap.init()
    → Bootstrap.setup() (ネイティブリソース初期化)
      → Node コンストラクタ (DIコンテナ構築、全サービス初期化)
        → Node.start() (各サービスの起動)
          → ClusterService.start(), TransportService.start(), ...
            → Discovery (クラスタへの参加)
```

**詳細な追跡:**

1. **main()** (`server/src/main/java/org/opensearch/bootstrap/OpenSearch.java:86`)
   ```java
   public static void main(final String[] args) throws Exception {
       overrideDnsCachePolicyProperties();
       LogConfigurator.registerErrorListener();
       final OpenSearch opensearch = new OpenSearch();
       int status = main(args, opensearch, Terminal.DEFAULT);
   }
   ```

2. **Bootstrap.init()** (`server/src/main/java/org/opensearch/bootstrap/Bootstrap.java:89-117`)
   ```java
   final class Bootstrap {
       private static volatile Bootstrap INSTANCE;
       private volatile Node node;
       // ネイティブリソース初期化、Node生成、keepAliveスレッド起動
   }
   ```

3. **Node コンストラクタ** (`server/src/main/java/org/opensearch/node/Node.java`)
   約2,475行のファイルで、100以上のサービスをGuice DIコンテナに登録し、起動順序を管理します。

### 8.3 フロー追跡チェックリスト

- [ ] エントリーポイントを特定したか (`Rest*Action` のroutes()を確認)
- [ ] 呼び出し関係を把握したか (RestAction -> TransportAction -> Service)
- [ ] データの変換ポイントを確認したか (HTTP params -> *Request -> 内部処理 -> *Response -> HTTP response)
- [ ] エラーハンドリングを確認したか (ActionListener.onFailure(), try-catch)
- [ ] 最終的な出力を確認したか (RestResponse, XContentBuilder)

---

## 9. 設計書の参照順序

> このセクションでは、プロジェクト理解のための設計書参照順序を案内します。

### 9.1 目的別ロードマップ

#### 全体像を把握したい場合
1. `README.md` -- プロジェクト概要
2. `DEVELOPER_GUIDE.md` -- 開発者ガイド(Project Layout セクション)
3. `server/src/main/java/org/opensearch/node/Node.java` -- コアノード実装
4. `server/src/main/java/org/opensearch/plugins/Plugin.java` -- プラグインAPI

#### 特定機能を理解したい場合
1. `rest-api-spec/` -- REST API仕様(YAML)で対象APIを特定
2. `server/src/main/java/org/opensearch/rest/action/` -- 対応する `Rest*Action` を確認
3. `server/src/main/java/org/opensearch/action/` -- 対応する `Transport*Action` を確認
4. 対応する `*Service` クラスでビジネスロジックを確認

#### 改修作業を行う場合
1. 対象機能の `Rest*Action` から `Transport*Action` までのフローを確認
2. 関連する `*Service` クラスの実装を確認
3. `server/src/test/` -- 対応するユニットテストを確認
4. `server/src/internalClusterTest/` -- 統合テストを確認
5. `DEVELOPER_GUIDE.md` -- コーディング規約を確認

#### プラグインを開発したい場合
1. `server/src/main/java/org/opensearch/plugins/Plugin.java` -- 基底クラス
2. 実装対象のインターフェース(`ActionPlugin`, `SearchPlugin` 等)を確認
3. `plugins/` 配下の既存プラグインを参考実装として確認
4. `test/framework/` -- テストユーティリティを確認

### 9.2 ドキュメント一覧

| ドキュメント | 概要 | 参照タイミング |
|-------------|------|---------------|
| `README.md` | プロジェクト概要・クイックスタート | 最初に読む |
| `DEVELOPER_GUIDE.md` | 開発環境構築・コーディング規約・プロジェクト構造 | 開発開始時 |
| `CONTRIBUTING.md` | コントリビューション手順 | PR作成前 |
| `CHANGELOG.md` | 変更履歴 | バージョン間の差異確認時 |
| `rest-api-spec/` | REST API仕様(YAML/JSONフォーマット) | API理解時 |
| `docs/` | 各種設計書・ガイドライン | 設計理解時 |

---

## 10. トラブルシューティング

> このセクションでは、コードリーディング時によくある問題と解決法を解説します。

### よくある疑問と回答

#### Q: クラスが多すぎてどこから読めばよいかわからない
A: まず `Rest*Action` クラスから始めてください。REST APIのURLパターン(`routes()`)を手がかりに、関心のある機能のエントリーポイントを特定できます。そこから `prepareRequest()` -> `Transport*Action` -> `*Service` と追跡してください。

#### Q: DIで依存が注入されるため、実装クラスがどれかわからない
A: `Node.java` のコンストラクタ内でGuiceモジュールへのバインディング設定を確認してください。約2,475行のファイルですが、`bind()` や `new xxxxModule()` の記述を探すことで、どの実装クラスが使用されているか特定できます。

#### Q: `ActionListener` のコールバックチェーンが追いにくい
A: ラムダ式やネストされた匿名クラスが多用されているため、IDEの「呼び出し階層」機能を使用してください。IntelliJ IDEAでは `Ctrl+Alt+H` (Call Hierarchy) が有効です。また、`ActionListener.wrap()` や `StepListener` 等のユーティリティでチェーンが構成されている場合も多いです。

#### Q: テストクラスがどこにあるかわからない
A: 対象クラス名に `Tests` サフィックスを付けたファイルを同一パッケージ構造内で検索してください。
- ユニットテスト: `server/src/test/java/org/opensearch/...`
- 統合テスト: `server/src/internalClusterTest/java/org/opensearch/...`
- QAテスト: `qa/` 配下

#### Q: プラグインの拡張ポイントが多すぎて、どのインターフェースを実装すればよいかわからない
A: `Plugin.java` のJavadocに拡張可能なインターフェース一覧が記載されています。主要なものは:
- `ActionPlugin` -- REST API/アクションの追加
- `SearchPlugin` -- 検索機能(クエリ、アグリゲーション等)の追加
- `AnalysisPlugin` -- テキスト分析機能の追加
- `IngestPlugin` -- インジェストパイプラインの追加
- `RepositoryPlugin` -- スナップショットリポジトリの追加

### デバッグのヒント

1. **ログ設定**: `config/log4j2.properties` でログレベルを調整。特定パッケージのログを `DEBUG` に設定可能。
2. **ブレークポイント設定**: REST APIの処理を追う場合、`BaseRestHandler.handleRequest()` にブレークポイントを設定するとすべてのREST処理をキャプチャできます。
3. **テスト実行**: `./gradlew :server:test --tests "*SearchRequest*"` のようにテストを限定実行できます。
4. **Gradleタスク確認**: `./gradlew tasks` で利用可能なタスク一覧を確認できます。

---

## 付録

### A. 用語集

| 用語 | 説明 |
|-----|------|
| Node | OpenSearchの1つのインスタンス(プロセス) |
| Cluster | 1つ以上のNodeの集合 |
| Index | ドキュメントの論理的なコレクション(RDBMSのデータベースに相当) |
| Shard | Indexの物理的な分割単位。各ShardはLuceneインデックス |
| Replica | Shardのコピー。冗長性と読み取りスループットの向上 |
| Cluster Manager | クラスタのメタデータとシャード配置を管理するノード |
| Transport | ノード間通信のための内部プロトコル |
| REST | クライアント向けHTTP API |
| Action | リクエスト-レスポンスの処理単位 |
| Plugin | 機能を拡張するためのモジュール |
| Module (ビルトイン) | 配布物に同梱されるプラグイン |
| Ingest Pipeline | ドキュメントのインデックス前処理チェーン |
| Painless | OpenSearch組み込みのスクリプト言語 |
| Aggregation | データの集計・分析処理 |
| Mapping | ドキュメントのスキーマ定義 |
| Setting | 動的/静的な設定パラメータ |
| Feature Flag | 実験的機能の有効/無効を制御するフラグ |
| ActionListener | 非同期処理の結果を受け取るコールバックインターフェース |
| Lifecycle | コンポーネントの状態管理(INITIALIZED -> STARTED -> STOPPED -> CLOSED) |

### B. ファイル一覧

| ファイル/ディレクトリ | 説明 | 主な内容 |
|---------------------|------|---------|
| `server/src/main/java/org/opensearch/bootstrap/OpenSearch.java` | プロセスエントリーポイント | main()メソッド、コマンドライン解析 |
| `server/src/main/java/org/opensearch/bootstrap/Bootstrap.java` | 内部起動処理 | ネイティブリソース初期化、Node生成 |
| `server/src/main/java/org/opensearch/node/Node.java` | コアノード実装 | DIコンテナ構築、サービス起動管理 |
| `server/src/main/java/org/opensearch/rest/RestHandler.java` | RESTハンドラインターフェース | handleRequest(), routes() |
| `server/src/main/java/org/opensearch/rest/BaseRestHandler.java` | RESTハンドラ基底クラス | prepareRequest(), パラメータ検証 |
| `server/src/main/java/org/opensearch/rest/action/search/RestSearchAction.java` | 検索REST API | /_search エンドポイント |
| `server/src/main/java/org/opensearch/rest/action/RestMainAction.java` | メインREST API | / エンドポイント |
| `server/src/main/java/org/opensearch/action/search/TransportSearchAction.java` | 検索トランスポートアクション | 検索処理のオーケストレーション |
| `server/src/main/java/org/opensearch/action/search/SearchRequest.java` | 検索リクエスト | 検索パラメータの定義 |
| `server/src/main/java/org/opensearch/cluster/service/ClusterService.java` | クラスタサービス | クラスタ状態管理 |
| `server/src/main/java/org/opensearch/plugins/Plugin.java` | プラグイン基底クラス | プラグイン拡張ポイント定義 |
| `libs/common/src/main/java/org/opensearch/common/lifecycle/AbstractLifecycleComponent.java` | ライフサイクル基底クラス | start/stop/close管理 |
| `server/src/main/java/org/opensearch/common/inject/Inject.java` | DIアノテーション | コンストラクタインジェクション |
| `DEVELOPER_GUIDE.md` | 開発者ガイド | 開発環境構築・プロジェクト構造 |

### C. 参考資料

- [OpenSearch公式ドキュメント](https://opensearch.org/docs/latest/)
- [OpenSearch GitHubリポジトリ](https://github.com/opensearch-project/OpenSearch)
- [Java SE ドキュメント](https://docs.oracle.com/en/java/)
- [Apache Lucene ドキュメント](https://lucene.apache.org/core/)
- [Gradle ドキュメント](https://docs.gradle.org/)
- [DEVELOPER_GUIDE.md](../../DEVELOPER_GUIDE.md) -- プロジェクト内開発者ガイド
