# 画面設計書 140-スクリプト作成・更新

## 概要

本ドキュメントは、OpenSearchのストアドスクリプト作成・更新API（`PUT /_scripts/{id}`）の画面設計書である。ストアドスクリプトを新規作成または既存スクリプトを更新するためのREST APIエンドポイントの仕様を定義する。

### 本画面の処理概要

本APIは、OpenSearchクラスタにストアドスクリプトを登録・更新するエンドポイントである。スクリプトはPainless、Mustache、Expressionなどの言語で記述でき、検索クエリのカスタムスコアリング、ドキュメント更新のロジック、検索テンプレート、インジェストパイプラインなどで再利用可能な形で保管される。

**業務上の目的・背景**：ストアドスクリプトを使用することで、複雑な処理ロジックを一元管理し、複数のリクエストから再利用できるようになる。インラインスクリプトと比較して、セキュリティ管理が容易であり、スクリプトの変更がクラスタ全体に即座に反映される利点がある。典型的な用途として、カスタムスコアリング関数、条件付きフィールド更新、Mustacheテンプレートによる検索定義のパラメータ化などがある。

**画面へのアクセス方法**：HTTPクライアントから `PUT /_scripts/{id}` または `POST /_scripts/{id}` へスクリプト定義をJSON形式のリクエストボディとともに送信する。オプションで `PUT /_scripts/{id}/{context}` のようにコンテキストを指定することも可能。

**主要な操作・処理内容**：
1. クライアントがスクリプトIDとスクリプト定義（言語、ソースコード）をPUT/POSTリクエストで送信する
2. RestPutStoredScriptActionがリクエストを受け取り、PutStoredScriptRequestを構築する
3. ScriptServiceがスクリプト定義をバリデーション（コンパイル検証）し、クラスタ状態を更新する
4. クラスタ状態の更新が全ノードに伝播された後、確認レスポンスを返却する

**画面遷移**：スクリプト取得API（139）で既存定義を確認した後に本APIで更新を行う。作成したスクリプトは検索API（21）の`script_fields`や`script_score`、ドキュメント更新API（10）のスクリプト更新、検索テンプレートAPI（26）などで使用される。

**権限による表示制御**：クラスタのスクリプト管理権限が必要。権限不足の場合は403エラーが返却される。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 82 | ストアドスクリプト | 主機能 | スクリプトを作成または更新する処理 |

## 画面種別

登録・編集（REST API PUT/POSTエンドポイント）

## URL/ルーティング

| メソッド | パス | 説明 |
|---------|------|------|
| PUT | `/_scripts/{id}` | スクリプトを作成または更新する |
| POST | `/_scripts/{id}` | スクリプトを作成または更新する |
| PUT | `/_scripts/{id}/{context}` | コンテキスト指定でスクリプトを作成または更新する |
| POST | `/_scripts/{id}/{context}` | コンテキスト指定でスクリプトを作成または更新する |

## 入出力項目

### パスパラメータ

| パラメータ名 | 型 | 必須 | 説明 |
|-------------|-----|------|------|
| id | string | はい | スクリプトID |
| context | string | いいえ | スクリプトコンテキスト（score、update等） |

### クエリパラメータ

| パラメータ名 | 型 | 必須 | デフォルト | 説明 |
|-------------|-----|------|-----------|------|
| timeout | time | いいえ | 30s | 操作の明示的タイムアウト |
| cluster_manager_timeout | time | いいえ | 30s | クラスタマネージャノードへの接続タイムアウト |
| master_timeout | time | いいえ | 30s | （非推奨）cluster_manager_timeoutを使用すること |
| context | string | いいえ | - | スクリプトをコンパイルするコンテキスト名 |

### リクエストボディ（必須）

| 項目名 | 型 | 必須 | 説明 |
|--------|-----|------|------|
| script | object | はい | スクリプト定義 |
| script.lang | string | はい | スクリプト言語（painless、mustache等） |
| script.source | string | はい | スクリプトのソースコード |

## 表示項目

### レスポンスボディ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| acknowledged | boolean | クラスタ状態の更新が全ノードに承認されたか |

## イベント仕様

### 1-スクリプト作成・更新リクエスト

クライアントからPUT/POSTリクエストを受信すると、RestPutStoredScriptActionの`prepareRequest`メソッドが呼び出される。パスパラメータからスクリプトIDとコンテキスト（任意）を取得し、リクエストボディからスクリプト定義をパースする。StoredScriptSource.parse()を使用してスクリプトソースを解析した後、PutStoredScriptRequestオブジェクトを生成する。クラスタマネージャタイムアウトと操作タイムアウトを設定し、`client.admin().cluster().putStoredScript()`を呼び出す。ScriptServiceはスクリプトのコンパイル検証（指定コンテキストでのコンパイル可否チェック）を行った上でクラスタ状態を更新する。

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| スクリプト作成・更新 | ClusterState（ScriptMetadata） | INSERT/UPDATE | クラスタ状態にスクリプト定義を登録または更新 |

### テーブル別更新項目詳細

#### ClusterState - ScriptMetadata

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT/UPDATE | scripts[{id}] | リクエストボディのスクリプト定義（StoredScriptSource） | 同一IDのスクリプトが存在する場合は上書き |

## メッセージ仕様

| メッセージID | メッセージ内容 | 種別 | 発生条件 |
|-------------|--------------|------|---------|
| 200 | `{"acknowledged": true}` | 成功 | スクリプトが正常に作成・更新された場合 |
| 400 | スクリプト定義が不正 | エラー | スクリプトのコンパイルエラー、不正な言語指定等 |
| 403 | 権限不足 | エラー | 必要な権限がない場合 |

## 例外処理

- **不正なスクリプト定義**: スクリプト言語が不明、ソースコードのコンパイルエラー等の場合、IllegalArgumentExceptionがスローされHTTPステータス400が返却される
- **リクエストボディの欠如**: リクエストボディが空の場合、エラーが返却される
- **スクリプトコンパイルエラー**: 指定されたコンテキストでスクリプトがコンパイルできない場合、ScriptExceptionがスローされる
- **クラスタマネージャノード接続タイムアウト**: タイムアウトエラーが返却される
- **クラスタブロック**: メタデータ書き込みブロック設定時にClusterBlockExceptionが返却される

## 備考

- 同一IDのスクリプトが既に存在する場合は上書き更新される
- スクリプト言語として主にPainless（セキュアなスクリプト言語）が推奨されている
- コンテキストを指定すると、そのコンテキスト（score、update、ingest等）でのコンパイル可否が事前検証される
- `master_timeout` パラメータはバージョン2.0.0で非推奨
- PUT/POST両方のHTTPメソッドに対応

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | PutStoredScriptRequest.java | `server/src/main/java/org/opensearch/action/admin/cluster/storedscripts/PutStoredScriptRequest.java` | 登録リクエストの構造。id、context、content、source |
| 1-2 | StoredScriptSource.java | `server/src/main/java/org/opensearch/script/StoredScriptSource.java` | スクリプトソースのパース処理。lang、sourceフィールド |

**読解のコツ**: RestPutStoredScriptActionではStoredScriptSource.parse()を使用してリクエストボディをパースしており、この処理でlangとsourceが抽出される点に注意。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | RestPutStoredScriptAction.java | `server/src/main/java/org/opensearch/rest/action/admin/cluster/RestPutStoredScriptAction.java` | RESTリクエストの受付処理 |

**主要処理フロー**:
1. **行63-69**: ルート定義 - 4パス（PUT/POST x コンテキスト有無）を登録
2. **行80**: パスパラメータ`id`を取得
3. **行81**: パスパラメータ`context`を取得
4. **行82-83**: リクエストボディのコンテンツとメディアタイプを取得
5. **行84**: StoredScriptSource.parse()でスクリプトソースをパース
6. **行86**: PutStoredScriptRequest(id, context, content, mediaType, source)を生成
7. **行87-89**: タイムアウト設定の適用（cluster_manager_timeout、master_timeout、timeout）
8. **行90**: `client.admin().cluster().putStoredScript()` を呼び出し

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ScriptService.java | `server/src/main/java/org/opensearch/script/ScriptService.java` | putStoredScript()メソッドによるスクリプト登録処理。コンパイル検証、クラスタ状態更新 |

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

```
RestPutStoredScriptAction.prepareRequest()
    |
    +-- StoredScriptSource.parse(content, mediaType)
    |
    +-- PutStoredScriptRequest(id, context, content, mediaType, source)
    |
    +-- client.admin().cluster().putStoredScript()
            |
            +-- TransportPutStoredScriptAction
                    |
                    +-- ScriptService.putStoredScript()
                    |       |
                    |       +-- コンパイル検証（コンテキスト指定時）
                    |       |
                    |       +-- AckedClusterStateUpdateTask
                    |               |
                    |               +-- ClusterState.metadata().putCustom(ScriptMetadata)
                    |
                    +-- AcknowledgedResponse -> JSONレスポンス
```

### データフロー図

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

PUT /_scripts/{id}
    |
    +-- id (パスパラメータ)      --> RestPutStoredScriptAction         --> PutStoredScriptRequest
    +-- context (パスパラメータ)        |                                     |
    +-- リクエストボディ(JSON)          v                                     v
        {script: {lang, source}}  StoredScriptSource.parse()          ソースパース
    +-- timeout                        |                                     |
                                       v                                     v
                                ScriptService.putStoredScript()       コンパイル検証
                                       |                                     |
                                       v                                     v
                                ClusterState更新                     AcknowledgedResponse
                                                                            |
                                                                            v
                                                                  {"acknowledged": true}
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| RestPutStoredScriptAction.java | `server/src/main/java/org/opensearch/rest/action/admin/cluster/RestPutStoredScriptAction.java` | ソース | RESTエントリーポイント |
| PutStoredScriptRequest.java | `server/src/main/java/org/opensearch/action/admin/cluster/storedscripts/PutStoredScriptRequest.java` | ソース | リクエストデータ構造 |
| PutStoredScriptAction.java | `server/src/main/java/org/opensearch/action/admin/cluster/storedscripts/PutStoredScriptAction.java` | ソース | アクション定義 |
| StoredScriptSource.java | `server/src/main/java/org/opensearch/script/StoredScriptSource.java` | ソース | スクリプトソース定義・パース |
| ScriptService.java | `server/src/main/java/org/opensearch/script/ScriptService.java` | ソース | スクリプト管理サービス |
| ScriptMetadata.java | `server/src/main/java/org/opensearch/script/ScriptMetadata.java` | ソース | スクリプトメタデータ |
| put_script.json | `rest-api-spec/src/main/resources/rest-api-spec/api/put_script.json` | API仕様 | REST API仕様定義 |
