# 機能設計書 9-インデックスビュー

## 概要

本ドキュメントは、OpenSearchにおけるインデックスビュー機能の設計を記述する。複数のインデックスに対する仮想的なビューを提供する実験的（Experimental）機能である。

### 本機能の処理概要

インデックスビュー機能は、複数のインデックスパターンをまとめたビューを定義し、ビューを通じた横断検索を可能にする抽象化レイヤーを提供する。ビューはクラスタ状態（ClusterState）のメタデータとして管理される。

**業務上の目的・背景**：複数のインデックスに分散したデータを論理的にグループ化し、統一的なアクセスポイントを提供する。エイリアスと類似の目的であるが、ビューはより構造化されたメタデータ（名前、説明、ターゲット一覧、作成・更新日時）を持つ。

**機能の利用シーン**：複数のインデックスパターンに対する横断検索、論理的なデータグループの定義、インデックスパターンの一元管理。

**主要な処理内容**：
1. ビューの作成（Create）
2. ビューの更新（Update）
3. ビューの取得（Get）
4. ビューの削除（Delete）
5. ビュー名一覧の取得（List）
6. ビューを通じた検索（Search）

**関連システム・外部連携**：検索機能（SearchAction）と連携し、ビューのターゲットインデックスパターンを展開して検索を実行する。

**権限による制御**：`cluster:admin/views/create`、`views:data/read/get`、`cluster:admin/views/delete`、`cluster:admin/views/update`、`views:data/read/list`、`views:data/read/search`のアクション権限が必要。

**注意**：本機能は `@ExperimentalApi` アノテーションが付与されており、実験的APIである。将来的にAPIの変更や削除が行われる可能性がある。

## 関連画面

画面機能マッピングにはビュー関連の画面定義は存在しない（実験的機能のため）。

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面機能マッピング未定義 |

## 機能種別

CRUD操作（Create/Read/Update/Delete）/ クラスタ状態管理

## 入力仕様

### 入力パラメータ（ビュー作成/更新）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | String | Yes | ビュー名 | 空でないこと、64文字以内 |
| description | String | No | ビューの説明 | 256文字以内、未指定時は空文字列 |
| targets | List\<Target\> | Yes | ターゲットインデックスパターンのリスト | 空でないこと、最大25件 |
| targets[].index_pattern | String | Yes | インデックスパターン | 空でないこと、64文字以内 |

### 入力パラメータ（ビュー取得/削除）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | String | Yes | ビュー名 | 空でないこと |

### 入力パラメータ（ビュー検索）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| view | String | Yes | ビュー名 | 空でないこと |
| (SearchRequest params) | - | No | 標準の検索パラメータ | scrollは使用不可 |

### 入力データソース

REST API。具体的なエンドポイントは実験的APIのため変更の可能性がある。

## 出力仕様

### 出力データ（作成/更新/取得）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| view | View | ビュー情報 |
| view.name | String | ビュー名 |
| view.description | String | ビューの説明 |
| view.created_at | long | 作成日時（ミリ秒） |
| view.modified_at | long | 更新日時（ミリ秒） |
| view.targets | Set\<Target\> | ターゲット一覧 |

### 出力データ（削除）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| acknowledged | boolean | 操作が承認されたか |

### 出力データ（名前一覧）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| views | List\<String\> | ビュー名のリスト |

### 出力データ（検索）

SearchResponseと同一形式。

### 出力先

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

## 処理フロー

### 処理シーケンス（ビュー作成）

```
1. REST APIリクエスト受信
   └─ CreateViewAction.Requestの生成
2. クラスタブロックチェック
   └─ METADATA_WRITEグローバルブロックチェック
3. ViewService.createView()呼び出し
   └─ Viewオブジェクト構築（name, description, currentTime, targets）
4. ClusterStateUpdateTask投入
   └─ 同名ビューの存在チェック（作成時はallowOverriding=false）
   └─ Metadata.builder().put(view)でビューメタデータ登録
5. GetViewAction.Responseの返却
```

### 処理シーケンス（ビュー検索）

```
1. REST APIリクエスト受信
   └─ SearchViewAction.Requestの生成
2. ViewService.searchView()呼び出し
   └─ ビューの存在チェック（getViewOrThrowException）
   └─ ターゲットのインデックスパターン展開
   └─ request.indices(indices)で検索対象設定
3. SearchAction.INSTANCEの実行（client.executeLocally）
4. SearchResponseの返却
```

### フローチャート

```mermaid
flowchart TD
    A[REST API リクエスト受信] --> B{操作種別}
    B -->|作成| C[METADATA_WRITE ブロックチェック]
    B -->|更新| C
    B -->|取得| D[METADATA_READ ブロックチェック]
    B -->|削除| C
    B -->|名前一覧| E[ViewService.listViewNames]
    B -->|検索| F[ViewService.searchView]
    C --> G[ViewService.createView/updateView/deleteView]
    G --> H[ClusterStateUpdateTask投入]
    H --> I[クラスタ状態更新]
    I --> J[レスポンス返却]
    D --> K[ViewService.getView]
    K --> J
    E --> J
    F --> L[ビュー存在チェック]
    L -->|存在しない| ERR[ViewNotFoundException]
    L -->|存在する| M[ターゲットパターン展開]
    M --> N[SearchAction実行]
    N --> J
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | ビュー名必須 | ビュー名は空であってはならない | 全操作 |
| BR-02 | ビュー名長制限 | ビュー名は64文字以内 | 作成/更新時 |
| BR-03 | 説明長制限 | 説明は256文字以内 | 作成/更新時 |
| BR-04 | ターゲット必須 | ターゲットリストは空であってはならない | 作成/更新時 |
| BR-05 | ターゲット数上限 | ターゲットは最大25件 | 作成/更新時 |
| BR-06 | パターン長制限 | ターゲットのインデックスパターンは64文字以内 | 作成/更新時 |
| BR-07 | 重複作成禁止 | 同名のビューが既に存在する場合、作成はエラー | 作成時 |
| BR-08 | 更新時上書き許可 | 更新操作では同名ビューの上書きが許可される | 更新時 |
| BR-09 | スクロール不可 | ビュー検索ではscrollは使用不可 | 検索時 |
| BR-10 | タイムスタンプ管理 | 作成時はcreatedAt/modifiedAtに現在時刻、更新時はmodifiedAtのみ更新 | 作成/更新時 |

### 計算ロジック

該当なし

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 作成 | ClusterState.metadata.views | INSERT | ビューメタデータの追加 |
| 更新 | ClusterState.metadata.views | UPDATE | ビューメタデータの更新 |
| 削除 | ClusterState.metadata.views | DELETE | ビューメタデータの削除（removeView） |
| 取得 | ClusterState.metadata.views | READ | ビューメタデータの読み取り |
| 名前一覧 | ClusterState.metadata.views | READ | ビューキーセットの取得 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 400 | ActionRequestValidationException | name未指定、ターゲット未指定、各種長さ制限違反 | パラメータを修正 |
| 400 | ActionRequestValidationException | ビュー検索でscrollを指定 | scrollを削除 |
| 404 | ViewNotFoundException | 指定ビューが存在しない（取得/更新/削除/検索） | ビュー名を確認 |
| 409 | ViewAlreadyExistsException | 同名ビューが既に存在する（作成時） | 別名を使用するか更新APIを使用 |
| 403 | ClusterBlockException | クラスタブロック中 | ブロック解除後に再実行 |

### リトライ仕様

Create/Update/Delete: TransportClusterManagerNodeActionの標準リトライ機構が適用される。
Search/ListViewNames: HandledTransportActionのため、標準リトライ機構は適用されない。

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

ビューの作成/更新/削除はClusterStateUpdateTaskとしてクラスタ状態更新にアトミックに実行される。検索操作はクラスタ状態を変更しない読み取り操作である。

## パフォーマンス要件

ビューのCRUD操作自体は軽量（クラスタ状態メタデータの読み書きのみ）。ビュー検索は内部的にSearchActionに委譲するため、検索対象インデックスの数とデータ量に依存する。

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

- 作成: `cluster:admin/views/create`
- 取得: `views:data/read/get`
- 更新: `cluster:admin/views/update`
- 削除: `cluster:admin/views/delete`
- 名前一覧: `views:data/read/list`
- 検索: `views:data/read/search`

## 備考

- 本機能は `@ExperimentalApi` アノテーションが付与されており、実験的APIである
- Create/Update/Delete/GetはTransportClusterManagerNodeAction、Search/ListViewNamesはHandledTransportAction
- ビュー検索はSearchAction.INSTANCEに委譲（client.executeLocally）
- 更新時はCreateViewAction.Requestを再利用する設計
- ターゲットはTreeSetで管理されるため、自然順序で並び替えられる

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | CreateViewAction.java | `server/src/main/java/org/opensearch/action/admin/indices/view/CreateViewAction.java` | Requestの内部クラス。name, description, targets。バリデーション定数: MAX_NAME_LENGTH=64(47行目), MAX_DESCRIPTION_LENGTH=256(48行目), MAX_TARGET_COUNT=25(49行目), MAX_TARGET_INDEX_PATTERN_LENGTH=64(50行目) |
| 1-2 | GetViewAction.java | `server/src/main/java/org/opensearch/action/admin/indices/view/GetViewAction.java` | ResponseにViewオブジェクトを格納。117-171行目 |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | CreateViewAction.TransportAction | `server/src/main/java/org/opensearch/action/admin/indices/view/CreateViewAction.java` (238行目以降) | 作成のエントリーポイント |
| 2-2 | GetViewAction.TransportAction | `server/src/main/java/org/opensearch/action/admin/indices/view/GetViewAction.java` (176行目以降) | 取得のエントリーポイント |
| 2-3 | UpdateViewAction.TransportAction | `server/src/main/java/org/opensearch/action/admin/indices/view/UpdateViewAction.java` (70行目以降) | 更新のエントリーポイント |
| 2-4 | DeleteViewAction.TransportAction | `server/src/main/java/org/opensearch/action/admin/indices/view/DeleteViewAction.java` (115行目以降) | 削除のエントリーポイント |
| 2-5 | SearchViewAction.TransportAction | `server/src/main/java/org/opensearch/action/admin/indices/view/SearchViewAction.java` (113行目以降) | 検索のエントリーポイント。HandledTransportActionを使用 |
| 2-6 | ListViewNamesAction.TransportAction | `server/src/main/java/org/opensearch/action/admin/indices/view/ListViewNamesAction.java` (116行目以降) | 名前一覧のエントリーポイント。HandledTransportActionを使用 |

**主要処理フロー（作成）**:
- **256-257行目**: executor() -- MANAGEMENTスレッドプール
- **266-272行目**: clusterManagerOperation() -- viewService.createView()呼び出し
- **275-277行目**: checkBlock() -- METADATA_WRITEグローバルブロック

**主要処理フロー（取得）**:
- **194-195行目**: executor() -- MANAGEMENTスレッドプール
- **204-206行目**: clusterManagerOperation() -- viewService.getView()呼び出し
- **210-211行目**: checkBlock() -- METADATA_READグローバルブロック

**主要処理フロー（検索）**:
- **124-125行目**: doExecute() -- viewService.searchView()呼び出し

#### Step 3: サービス層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ViewService.java | `server/src/main/java/org/opensearch/action/admin/indices/view/ViewService.java` | 全CRUD操作の中核ロジック |

**主要メソッド**:
- **48-58行目**: createView() -- Viewオブジェクト構築、createOrUpdateView(Operation.CreateView)呼び出し
- **60-77行目**: updateView() -- 既存ビュー取得、createdAtを保持して更新
- **79-101行目**: deleteView() -- ビュー存在チェック、ClusterStateUpdateTaskでremoveView
- **103-107行目**: getView() -- getViewOrThrowException()でビュー取得
- **109-120行目**: listViewNames() -- Metadata.views().keySet()から名前一覧取得
- **122-129行目**: searchView() -- ビュー取得、ターゲットパターン展開、SearchAction実行
- **131-138行目**: getViewOrThrowException() -- ビューが存在しない場合ViewNotFoundException
- **140-151行目**: Operation enum -- CreateView(allowOverriding=false), UpdateView(allowOverriding=true)
- **153-177行目**: createOrUpdateView() -- ClusterStateUpdateTaskで作成/更新の共通処理。157行目: 作成時は同名ビュー存在チェック

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

```
[作成] CreateViewAction.TransportAction
    |
    +-- checkBlock() -- METADATA_WRITE グローバルブロック
    |
    +-- clusterManagerOperation()
          |
          +-- ViewService.createView() (48行目)
                |
                +-- View構築 (55行目)
                +-- createOrUpdateView(Operation.CreateView) (57行目)
                      |
                      +-- ClusterStateUpdateTask (154行目)
                            +-- 同名ビュー存在チェック (157行目)
                            +-- Metadata.builder().put(view) (160行目)

[取得] GetViewAction.TransportAction
    |
    +-- checkBlock() -- METADATA_READ グローバルブロック
    |
    +-- clusterManagerOperation()
          |
          +-- ViewService.getView() (103行目)
                +-- getViewOrThrowException() (131行目)

[検索] SearchViewAction.TransportAction (HandledTransportAction)
    |
    +-- doExecute()
          |
          +-- ViewService.searchView() (122行目)
                +-- getViewOrThrowException() (123行目)
                +-- view.getTargets() -> indices (125行目)
                +-- client.executeLocally(SearchAction.INSTANCE) (128行目)

[名前一覧] ListViewNamesAction.TransportAction (HandledTransportAction)
    |
    +-- doExecute()
          |
          +-- ViewService.listViewNames() (109行目)
                +-- Metadata.views().keySet() (114行目)
```

### データフロー図

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

CreateViewAction.Request ---> CreateViewAction.TransportAction --> GetViewAction.Response
 (name, description,           |                                   (view)
  targets)                     +-> ViewService.createView()
                                    +-> View構築
                                    +-> createOrUpdateView()
                                         +-> ClusterStateUpdateTask

SearchViewAction.Request ---> SearchViewAction.TransportAction --> SearchResponse
 (view, SearchRequest)         |
                               +-> ViewService.searchView()
                                    +-> getViewOrThrowException()
                                    +-> targets -> indices展開
                                    +-> SearchAction.INSTANCE実行
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ViewService.java | `server/src/main/java/org/opensearch/action/admin/indices/view/ViewService.java` | ソース | ビュー操作の中核サービス |
| CreateViewAction.java | `server/src/main/java/org/opensearch/action/admin/indices/view/CreateViewAction.java` | ソース | 作成アクション（Request/TransportAction） |
| GetViewAction.java | `server/src/main/java/org/opensearch/action/admin/indices/view/GetViewAction.java` | ソース | 取得アクション（Request/Response/TransportAction） |
| UpdateViewAction.java | `server/src/main/java/org/opensearch/action/admin/indices/view/UpdateViewAction.java` | ソース | 更新アクション |
| DeleteViewAction.java | `server/src/main/java/org/opensearch/action/admin/indices/view/DeleteViewAction.java` | ソース | 削除アクション |
| SearchViewAction.java | `server/src/main/java/org/opensearch/action/admin/indices/view/SearchViewAction.java` | ソース | 検索アクション |
| ListViewNamesAction.java | `server/src/main/java/org/opensearch/action/admin/indices/view/ListViewNamesAction.java` | ソース | 名前一覧アクション |
| ViewAlreadyExistsException.java | `server/src/main/java/org/opensearch/action/admin/indices/view/ViewAlreadyExistsException.java` | ソース | ビュー重複例外 |
| ViewNotFoundException.java | `server/src/main/java/org/opensearch/action/admin/indices/view/ViewNotFoundException.java` | ソース | ビュー未発見例外 |
| View.java | `server/src/main/java/org/opensearch/cluster/metadata/View.java` | ソース | ビューメタデータモデル |
