OpenSearchについて整理してみた

# 背景・目的
最近、Amazon OpenSearch Serviceに触れる機会が増えてきました。そこでOpenSearchの知識を整理しようと思います。

# まとめ

下記に特徴をまとめます

|特徴|説明|
|:--|:--|
|OpenSearchとは|Apache Luceneに基づく分散検索および分析エンジン<BR>OpenSearch にデータを追加すると、　下記の期待されるすべての機能を使用して、そのデータに対して全文検索を実行できる<BR>・フィールドによる検索<BR>・複数のインデックスの検索<BR>・フィールドのブースト<BR>・スコアによる結果のランク付け<BR>・フィールドによる結果の並べ替え<BR>・結果の集計など<BR><BR>優れたパフォーマンスを提供し、アプリケーションのニーズが拡大・縮小するのに合わせてスケールアップ・ダウンできる|
|Document|ドキュメントは、テキストまたは構造化データを保存する単位。JSONで保存される|
|Index| ・インデックスはドキュメントのコレクション<BR>・検索するときは、インデックスに含まれるデータをクエリする<BR>・インデックスは、従来のDB内のデータベーステーブルを表す|
|Clusters and nodes|OpenSearch は分散検索エンジンとして設計されており、1 つ以上のノード上で実行できる<BR>OpenSearch クラスターはノードの集合|
|Nodes|下記のノードタイプがある。<BR>・Cluster manager<BR>・Cluster manager eligible<BR>・Data<BR>・Ingest<BR>・Coordinating<BR>・Dynamic<BR>・Search|
|Shards|インデックスをシャードに分割する。各シャードにはインデックス内のドキュメントのサブセットが格納される<BR>シャードの数が多いほど良いというわけではない<BR>目安としては、シャードのサイズを 10～50 GB に制限する|
|Primary and replica shard|シャードはプライマリ (オリジナル) シャードまたはレプリカ (コピー) シャードのいずれかになる<BR>デフォルトでは、OpenSearch はプライマリ シャードごとにレプリカ シャードを作成する|
|Inverted index|OpenSearch インデックスは、転置インデックスと呼ばれるデータ構造を使用する<BR>転置インデックスは、単語をその単語が出現するドキュメントにマッピングする|
|Relevance|ドキュメントを検索すると、OpenSearch はクエリ内の単語とドキュメント内の単語を照合する<BR>各ドキュメントには関連性スコアが割り当てられ、そのドキュメントがクエリにどの程度一致したかを示す<BR>OpenSearch は BM25 ランキング アルゴリズムを使用してドキュメントの関連性スコアを計算し、関連性で並べ替えた結果を返す|


# 概要
## OpenSearch and OpenSearch Dashboards
### Getting started
下記を基に整理します。

https://opensearch.org/docs/latest/getting-started/

- Apache Luceneに基づく分散検索および分析エンジン
- OpenSearch にデータを追加すると、　下記の期待されるすべての機能を使用して、そのデータに対して全文検索を実行できる
    - フィールドによる検索
    - 複数のインデックスの検索
    - フィールドのブースト
    - スコアによる結果のランク付け
    - フィールドによる結果の並べ替え
    - 結果の集計など
- 優れたパフォーマンスを提供し、アプリケーションのニーズが拡大・縮小するのに合わせてスケールアップ・ダウンできる


#### コンポーネント
下記のコンポーネントが含まれる
- OpenSearch Dashboards
    - データ可視化のUI
- Data Prepper
    - 後続の分析と可視化のために下記が可能なデータコレクター
        - フィルタリング
        - エンリッチング
        - トランスフォーミング
        - 正規化
        - 集約
- Clients
    - 一般的な言語でOpenSearchと通信できるAPI

#### ユースケース
- Observability
    - PPL=Piped Processing Languageを使用してデータ駆動型イベントを視覚化し、保存されているデータを探索、検索、クエリする
- Search: 
    - 語彙検索、機械学習（ML）を活用した会話型検索までアプリケーションに最適な検索方法を選択する
- Machine learning
    - アプリケーションにMLモデルを統合
- Security analytics
    - セキュリティの脅威を調査・検出・分析する


### Introduction to OpenSearch
下記を基に整理します。

https://opensearch.org/docs/latest/getting-started/intro/

#### Document
- ドキュメントは、テキストまたは構造化データを保存する単位。JSONで保存される

#### Index
- インデックスはドキュメントのコレクション
- 検索するときは、インデックスに含まれるデータをクエリする
- インデックスは、従来のDB内のデータベーステーブルを表す

#### Clusters and nodes
- OpenSearch は分散検索エンジンとして設計されており、1 つ以上のノード上で実行できる
- OpenSearch クラスターはノードの集合

##### Creating a cluster

https://opensearch.org/docs/latest/tuning-your-cluster/

- 単一ノードのクラスタ、または複数ノードクラスタとして動作できる
- 下記は、4 ノード クラスターを含む基本アーキテクチャの例
    - 1 つの専用クラスターマネージャーノード
    - 1 つの専用コーディネーティング ノード
    - クラスター マネージャー対応でデータの取り込みにも使用される 
    - 2 つのデータ ノード
    <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/edb24946-481c-4fbd-89e2-b0d3a012aba9.png" width=400 />
    
    ※[出典:Creating a cluster](https://opensearch.org/docs/latest/tuning-your-cluster/)


###### Nodes
いくつかのノードタイプがあります。

|Node type|説明|プロダクション向けのベストプラクティス
|:--|:--|:--|
|Cluster manager|クラスターの全体的な操作を管理し、クラスターの状態を追跡する<BR>下記を行う<BR>・インデックスの作成と削除<BR>・クラスターに参加および離脱するノードの追跡<BR>・クラスター内の各ノードの状態の確認<BR>・およびノー​​ドへのシャードの割り当て|3 つの異なるゾーンに 3 つの専用クラスター マネージャー ノードを配置する|
|Cluster manager eligible|投票プロセスを通じて、その中から 1 つのノードをクラスター マネージャー ノードとして選出する|専用のクラスター マネージャー ノードがあることを確認する。<BR>これには、他のすべてのノードタイプをfalseとしてマークする|
|Data|データを保存および検索します。ローカル シャードですべてのデータ関連操作 (インデックス作成、検索、集計) を実行する<BR>クラスターのワーカーノード。多くのディスク容量が必要|データ ノードを追加するときは、ゾーン間でバランスが取れるようにする<BR>例<BR>ゾーンが 3 つある場合は、ゾーンごとに 1 つずつ、3 の倍数でデータ ノードを追加する|
|Ingest|データをクラスタに保存する前に、Pre-processを行う。<BR>インデックスを追加する前に、変換する取り込みパイプラインを実行する|大量データや複雑なIngest パイプラインの場合は、専用ノードを推奨<BR>また、データノードからインデックス作成をオフロードし、データノードを検索と集計専用に使用することも可能|
|Coordinating|クライアントの要求をデータノード上のシャードに委任し結果を収集して、1つの最終結果に集約しクライアントに返す|検索負荷の高いワークロードの場合、コーディネート専用ノードを複数用意する。その際には多くのコアCPUを使用することを推奨|
|Dynamic|MLタスクなどのカスタムワークロードに特定のノードをアサインすることで、データノードからのリソースの消費を防ぐ|
|Search|検索可能なスナップショットへのアクセスを提供<BR>頻繁に使用されるセグメントをキャッシュし、最も使用頻度の低いデータセグメントを削除するなど行う|検索ノードには、スナップショット キャッシュとして割り当てられたインデックスが含まれるため、ディスクよりもCPUとメモリが多いノードを推奨|


##### Shards
- インデックスをシャードに分割する。各シャードにはインデックス内のドキュメントのサブセットが格納される
    <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/bcb5bf5a-f156-4832-a715-3cf2df65139a.png" width=400 />
    [出典：Introduction to OpenSearch](https://opensearch.org/docs/latest/getting-started/intro/)

    
- シャードは、クラスター内のノード間で均等に分散するために使用される
- 例
    - 400 GB のインデックスはクラスター内の単一のノードでは処理できないほど大きい可能性がある
        - 40 GB ずつの 10 個のシャードに分割すると、OpenSearch はシャードを 10 個のノードに分散し、各シャードを個別に管理できる

- 下記はインデックス 1 とインデックス 2 の 2 つのインデックスを持つクラスターの例
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/24aa489c-36c6-46b7-905c-2fcf2003f0ff.png)
    [出典：Introduction to OpenSearch](https://opensearch.org/docs/latest/getting-started/intro/)

- シャードの数が多いほど良いというわけではない
- たとえば、400 GB のインデックスを 1,000 個のシャードに分割すると、クラスターに不必要な負担がかかる
- 目安としては、シャードのサイズを 10～50 GB に制限する

##### Primary and replica shards
- シャードはプライマリ (オリジナル) シャードまたはレプリカ (コピー) シャードのいずれかになる
- デフォルトでは、OpenSearch はプライマリ シャードごとにレプリカ シャードを作成する
    - インデックスを 10 個のシャードに分割すると、OpenSearch は 10 個のレプリカ シャードを作成する
- 例
    - クラスター内の各インデックスの各シャードにレプリカを 1 つ追加する
    - 下記のようにクラスターにはインデックス 1 に合計 2 つのシャードと 2 つのレプリカ
    - インデックス 2 に合計 4 つのシャードと 4 つのレプリカが含まれる
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/45a74c0b-5285-418f-a295-622ee161b5d8.png)
     [出典：Introduction to OpenSearch](https://opensearch.org/docs/latest/getting-started/intro/)

    - レプリカシャードは、ノード障害が発生した場合のバックアップとして機能する
    - OpenSearchはレプリカシャードを対応するプライマリシャードとは異なるノードに配布する
    - クラスタが検索リクエストを処理する速度も向上する

##### Inverted index
- OpenSearch インデックスは、転置インデックスと呼ばれるデータ構造を使用する
- 転置インデックスは、単語をその単語が出現するドキュメントにマッピングする


##### Relevance
- ドキュメントを検索すると、OpenSearch はクエリ内の単語とドキュメント内の単語を照合する
- 各ドキュメントには関連性スコアが割り当てられ、そのドキュメントがクエリにどの程度一致したかを示す
- 検索クエリ内の個々の単語は検索用語と呼ばれます。各検索用語は次のルールに従ってスコア付けされる
    1. ドキュメント内でより頻繁に出現する検索用語は、より高いスコアが付けられる傾向がある
        - 例:犬に関する文書で「犬」という単語を何度も使用している文書は、「犬」という単語をあまり使用していない文書よりも関連性が高いと考えられる
        - the　frequency component of the score
    1. より多くのドキュメントに出現する検索用語は、スコアが低くなる傾向がある
        - 例：「blue」と「axolotl」という用語のクエリでは、より一般的な単語である「blue」よりも「axolotl」を含むドキュメントが優先される
        -  the　inverse document frequency component of the score.
    1. 長いドキュメントでの一致は、短いドキュメントでの一致よりもスコアが低くなる傾向がある 
        - 完全な辞書を含むドキュメントは、どの単語にも一致しますが、特定の単語とはあまり関連性がない
        - the　length normalization component of the score.

- OpenSearch は BM25 ランキング アルゴリズムを使用してドキュメントの関連性スコアを計算し、関連性で並べ替えた結果を返す

##### Advanced concepts
###### Update lifecycle
- 更新操作のライフサイクルは、次の手順で構成される
    1. 更新はプライマリ シャードによって受信され、シャードのトランザクション ログ (トランスログ) に書き込まれる。更新が確認される前に、トランスログがディスクにフラッシュされ、 その後 fsync が実行される
    1. 更新は Lucene インデックス ライターにも渡され、メモリ内バッファーに追加される
    1. 更新操作では、Lucene インデックス ライターはメモリ内のバッファーをディスクにフラッシュし (各バッファーは新しい Lucene セグメントになる)、結果のセグメント ファイルに対して新しいインデックス リーダーが開かれ、更新内容が検索で表示される
    1. フラッシュ操作では、シャードは Lucene セグメントを fsync する。セグメント ファイルは更新の永続的な表現であるため、耐久性を提供するためにトランスログは必要なくなり、更新はトランスログから消去できる

###### Translog
- インデックス作成または一括呼び出しは、ドキュメントがトランスログに書き込まれ、トランスログがディスクにフラッシュされたときに応答する
- 更新は永続的
- 更新は、更新操作が完了するまで検索要求には表示されない

###### Refresh
- OpenSearch は定期的に更新操作を実行し、メモリ内の Lucene インデックスからファイルにドキュメントを書き込む
- fsync が実行されないため、これらのファイルの耐久性は保証されない
- 更新すると、ドキュメントが検索可能になる

###### Flush
- フラッシュ操作は、fsync を使用してファイルをディスクに保存する
- フラッシュにより、トランスログにのみ保存されたデータが Lucene インデックスに記録される
- OpenSearch は、トランスログが大きくなりすぎないように、必要に応じてフラッシュを実行する

###### Merge
- OpenSearch では、シャードはセグメント (またはセグメント ファイル) で構成される Lucene インデックス
- セグメントにはインデックス化されたデータが保存され、変更できない
- 定期的に、小さなセグメントが大きなセグメントにマージされる
- マージすると、各シャード上のセグメントの総数が減り、ディスク領域が解放され、検索パフォーマンスが向上する
- 最終的に、セグメントはマージ ポリシーで指定された最大サイズに達し、それ以上大きなセグメントにマージされなくなる
- マージ ポリシーでは、マージを実行する頻度も指定する


<!--

下記に特徴を整理します。

|特徴|説明|
|:--|:--|
|OpenSearchとは|高速でスケーラブルな全文検索<BR>ユーザが、アプリやWeb、データレイクカタログから適切な情報を見つけられるようにする|
|機能|・Anomaly detection<BR>・SQL<BR>・Index State Management<BR>・Search methods <BR>・Machine learning <BR>・Workflow automation<BR>・Performance evaluation<BR>・Asynchronous search<BR>・Cross-cluster replication|
|Anomaly detection| OpenSearch における異常とは、時系列データにおける異常な動作の変化のこと<BR>異常検出は、ランダム カット フォレスト (RCF) アルゴリズムを使用して、OpenSearch データ内の異常をニアリアルタイムで自動的に検出する|
|インデックス|・検索する前に、インデックスを作成する必要がある<BR>・インデックス作成は、検索エンジンがデータを整理して高速に検索できるようにする方法<BR>・OpenSearch では、データの基本単位は JSON ドキュメント<BR>・インデックス内では、OpenSearch は一意の ID を使用して各ドキュメントを識別する|
|Managing indexes|OpenSearch REST API を使用してデータをインデックスする<BR>API には、index API と _bulk API の 2 つがある|
|インデックス作成方法|・段階的にデータを更新する場合は個別<BR>・更新頻度が低い場合は、ファイルを生成して_bulkで更新<BR>・ドキュメントの数が大きい場合は_bulkを実行するとパフォーマンスに優れる<BR>しかし、ドキュメントが膨大な場合は、個別にインデックスを作成する必要がある場合がある|


# 概要
## OpenSearch and OpenSearch Dashboards
下記を基に整理します。

https://opensearch.org/docs/latest/about/

### Why use OpenSearch?
> Fast, scalable full-text search	
Help users find the right information within your application, website, or data lake catalog.	

- 高速でスケーラブルな全文検索
- ユーザが、アプリやWeb、データレイクカタログから適切な情報を見つけられるようにする

> Application and infrastructure monitoring	
Easily store and analyze log data, and set automated alerts for performance issues.	

- アプリとインフラのモニタリング
- ログをストア、分析し、自動でパフォーマンスの問題のアラートを設定する


> Security and event information management	
Centralize logs to enable real-time security monitoring and forensic analysis.	

- セキュリティとイベント情報管理
- ログを一元管理して、リアルタイムのセキュリティ監視とフォレンジック分析を可能にする

> Operational health tracking
Use observability logs, metrics, and traces to monitor your applications in real time.
- 運用健全性の追跡
- 可観測性ログ、メトリック、トレースを使用してアプリケーションをリアルタイムで監視する

### Key features
> OpenSearch provides several features to help index, secure, monitor, and analyze your data:

- OpenSearch は、データのインデックス作成、保護、監視、分析に役立ついくつかの機能を提供する
- Anomaly detection
- SQL
- Index State Management
- Search methods 
- Machine learning 
- Workflow automation
- Performance evaluation
- Asynchronous search
- Cross-cluster replication

### The secure path forward
> OpenSearch includes a demo configuration so that you can get up and running quickly, but before using OpenSearch in a production environment, you must configure the Security plugin manually with your own certificates, authentication method, users, and passwords. To get started, see Getting started with OpenSearch security.

- OpenSearch にはデモ構成が含まれているため、すぐに起動して実行できる
- 実稼働環境で OpenSearch を使用する前に、下記を使用してセキュリティ プラグインを手動で構成する必要がある
    - 独自の証明書
    - 認証方法
    - ユーザー
    - パスワード

## Anomaly detection
下記を基に整理します。

https://opensearch.org/docs/latest/observing-your-data/ad/index/

> An anomaly in OpenSearch is any unusual behavior change in your time-series data. Anomalies can provide valuable insights into your data. For example, for IT infrastructure data, an anomaly in the memory usage metric can help identify early signs of a system failure.

- OpenSearch における異常とは、時系列データにおける異常な動作の変化のこと
- 異常はデータに関する貴重な洞察を提供する
- IT インフラストラクチャ データの場合、メモリ使用量メトリックの異常は、システム障害の初期兆候を特定するのに役立つ

> Conventional techniques like visualizations and dashboards can make it difficult to uncover anomalies. Configuring alerts based on static thresholds is possible, but this approach requires prior domain knowledge and may not adapt to data with organic growth or seasonal trends.

- 視覚化やダッシュボードなどの従来の手法では、異常を発見することが困難になる可能性がある
- 静的しきい値に基づいてアラートを構成することは可能だが、このアプローチでは事前のドメイン知識が必要であり、有機的な成長や季節的な傾向のあるデータには適応できない可能性がある

> Anomaly detection automatically detects anomalies in your OpenSearch data in near real time using the Random Cut Forest (RCF) algorithm. RCF is an unsupervised machine learning algorithm that models a sketch of your incoming data stream to compute an anomaly grade and confidence score value for each incoming data point. These values are used to differentiate an anomaly from normal variations. For more information about how RCF works, see Robust Random Cut Forest Based Anomaly Detection on Streams.

- 異常検出は、ランダム カット フォレスト (RCF) アルゴリズムを使用して、OpenSearch データ内の異常をほぼリアルタイムで自動的に検出する
- RCF は、受信データ ストリームのスケッチをモデル化し、各受信データ ポイントの異常グレードと信頼スコア値を計算する、教師なし機械学習アルゴリズム
- これらの値は、異常と通常の変動を区別するために使用される

## Managing indexes
> You index data using the OpenSearch REST API. Two APIs exist: the index API and the _bulk API.

- OpenSearch REST API を使用してデータをインデックスする
- API には、index API と _bulk API の 2 つがある

> For situations in which new data arrives incrementally (for example, customer orders from a small business), you might use the index API to add documents individually as they arrive. For situations in which the flow of data is less frequent (for example, weekly updates to a marketing website), you might prefer to generate a file and send it to the _bulk API. For large numbers of documents, lumping requests together and using the _bulk API offers superior performance. If your documents are enormous, however, you might need to index them individually.

- 新しいデータが段階的に到着する状況 (たとえば、中小企業からの顧客注文) では、インデックス API を使用して、到着時にドキュメントを個別に追加することができる
- データフローの頻度が低い場合 (マーケティング Web サイトへの週次更新など) は、ファイルを生成して _bulk API に送信する方が適している場合がある
- ドキュメントの数が多い場合は、リクエストをまとめて _bulk API を使用すると、優れたパフォーマンスが得られる。ただし、ドキュメントが膨大な場合は、個別にインデックスを作成する必要がある場合がある

> When indexing documents, the document _id must be 512 bytes or less in size.

- ドキュメントをインデックスする場合、ドキュメントの _id のサイズは 512 バイト以下である必要がある

### Introduction to indexing
> Before you can search data, you must index it. Indexing is the method by which search engines organize data for fast retrieval. The resulting structure is called, fittingly, an index.

- 検索する前に、インデックスを作成する必要がある
- インデックス作成は、検索エンジンがデータを整理して高速に検索できるようにする方法

> In OpenSearch, the basic unit of data is a JSON document. Within an index, OpenSearch identifies each document using a unique ID.

- OpenSearch では、データの基本単位は JSON ドキュメント
- インデックス内では、OpenSearch は一意の ID を使用して各ドキュメントを識別する
> A request to the index API looks like this:



- インデックス API へのリクエストは下記の通り
```json
PUT <index>/_doc/<id>
{ "A JSON": "document" }
```

> A request to the _bulk API looks a little different, because you specify the index and ID in the bulk data:

- _bulk API へのリクエストは、バルク データでインデックスと ID を指定する

```json
POST _bulk
{ "index": { "_index": "<index>", "_id": "<id>" } }
{ "A JSON": "document" }
```

> Bulk data must conform to a specific format, which requires a newline character (\n) at the end of every line, including the last line. This is the basic format:

- バルク データは特定の形式に準拠する必要があり、最終行を含むすべての行の末尾に改行文字 (\n) が必要
- 基本形式は下記の通り

```json
Action and metadata\n
Optional document\n
Action and metadata\n
Optional document\n
```

> The document is optional, because delete actions don’t require a document. The other actions (index, create, and update) all require a document. If you specifically want the action to fail if the document already exists, use the create action instead of the index action.

- 削除アクションにはドキュメントは必要ないため、ドキュメントはオプション
- その他のアクション (index, create, and update) にはすべてドキュメントが必要
- ドキュメントがすでに存在する場合にアクションを失敗させるようにしたい場合は、index アクションではなくcreate アクションを使用する

> To index bulk data using the curl command, navigate to the folder where you have your file saved and run the following command:

- curl コマンドを使用して大量のデータをインデックスするには、ファイルを保存しているフォルダーに移動し、下記のコマンドを実行する

```bash
curl -H "Content-Type: application/x-ndjson" -POST https://localhost:9200/data/_bulk -u 'admin:admin' --insecure --data-binary "@data.json"
```

> If any one of the actions in the _bulk API fail, OpenSearch continues to execute the other actions. Examine the items array in the response to figure out what went wrong. The entries in the items array are in the same order as the actions specified in the request.

- _bulk API のいずれかのアクションが失敗した場合、OpenSearch は他のアクションの実行を続行する
- 何が問題だったのかを把握するために、応答内の items 配列を調べる
- アイテム配列内のエントリは、リクエストで指定されたアクションと同じ順序になる


> OpenSearch automatically creates an index when you add a document to an index that doesn’t already exist. It also automatically generates an ID if you don’t specify an ID in the request. This simple example automatically creates the movies index, indexes the document, and assigns it a unique ID:

- OpenSearch は、まだ存在していないインデックスにドキュメントを追加すると、自動的にインデックスを作成する
- リクエストで ID を指定しない場合は、ID が自動的に生成される
- この簡単な例では、映画のインデックスを自動的に作成し、ドキュメントにインデックスを付けて、一意の ID を割り当てている

```json
POST movies/_doc
{ "title": "Spirited Away" }
```

> Automatic ID generation has a clear downside: because the indexing request didn’t specify a document ID, you can’t easily update the document at a later time. Also, if you run this request 10 times, OpenSearch indexes this document as 10 different documents with unique IDs. To specify an ID of 1, use the following request (note the use of PUT instead of POST):

- **自動 ID 生成には明らかな欠点がある**
- インデックス作成リクエストでドキュメント ID が指定されていないため、後でドキュメントを簡単に更新できない
- このリクエストを 10 回実行すると、OpenSearch はこのドキュメントを一意の ID を持つ 10 個の異なるドキュメントとしてインデックスする
- ID 1 を指定するには、次のリクエストを使用する (POST ではなく PUT を使用することに注意)

```json
PUT movies/_doc/1
{ "title": "Spirited Away" }
```
> Because you must specify an ID, if you run this command 10 times, you still have just one document indexed with the _version field incremented to 10.

- ID を指定する必要があるため、このコマンドを 10 回実行しても、_version フィールドが 10 に増加した状態でインデックス付けされたドキュメントは 1 つだけになる

> Indexes default to one primary shard and one replica. If you want to specify non-default settings, create the index before adding documents:

- インデックスはデフォルトで 1 つのプライマリ シャードと 1 つのレプリカになる
- デフォルト以外の設定を指定する場合は、ドキュメントを追加する前にインデックスを作成する

```json
PUT more-movies
{ "settings": { "number_of_shards": 6, "number_of_replicas": 2 } }
```

### Naming restrictions for indexes
> OpenSearch indexes have the following naming restrictions:

> - All letters must be lowercase.
> - Index names can’t begin with underscores (_) or hyphens (-).
> - Index names can’t contain spaces, commas, or the following characters:

> - :, ", *, +, /, \, |, ?, #, >, or <


- OpenSearchインデックスには以下の命名制限がある
    - すべての文字は小文字
    - インデックス名はアンダースコア (_) またはハイフン (-) で始めることはできない
    - インデックス名はスペース、カンマ、下記の文字を含められない
        - `- :, ", *, +, /, \, |, ?, #, >, or <`

### Read data
> After you index a document, you can retrieve it by sending a GET request to the same endpoint that you used for indexing:

- ドキュメントのインデックスを作成後、インデックス作成に使用したのと同じエンドポイントに GET リクエストを送信してドキュメントを取得できる

```json
GET movies/_doc/1

{
  "_index" : "movies",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 1,
  "_seq_no" : 0,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "title" : "Spirited Away"
  }
}

```

> You can see the document in the _source object. If the document is not found, the found key is false and the _source object is not part of the response.

- _source オブジェクトでドキュメントを確認できる
- ドキュメントが見つからない場合、found キーは false になり、_source オブジェクトは返されない

> To retrieve multiple documents with a single command, use the _mget operation. The format for retrieving multiple documents is similar to the _bulk operation, where you must specify the index and ID in the request body:

- 1 つのコマンドで複数のドキュメントを取得するには、_mget 操作を使用する
- 複数のドキュメントを取得するための形式は _bulk 操作に似ており、リクエスト本文にインデックスと ID を指定する必要がある

```json
GET _mget
{
  "docs": [
    {
      "_index": "<index>",
      "_id": "<id>"
    },
    {
      "_index": "<index>",
      "_id": "<id>"
    }
  ]
}
```
> To only return specific fields in a document:

- ドキュメント内の特定のフィールドのみを返す
```json
GET _mget
{
  "docs": [
    {
      "_index": "<index>",
      "_id": "<id>",
      "_source": "field1"
    },
    {
      "_index": "<index>",
      "_id": "<id>",
      "_source": "field2"
    }
  ]
}
```

> To check if a document exists:
- ドキュメントが存在するかどうかを確認する

```json
HEAD movies/_doc/<doc-id>
```

- ドキュメントが存在する場合は 200 OK 応答が返される
- 存在しない場合は 404 - Not Found エラーが返される

### Update data
> To update existing fields or to add new fields, send a POST request to the _update operation with your changes in a doc object:

- 既存のフィールドを更新したり、新しいフィールドを追加したりするには、doc オブジェクトの変更内容を _update 操作に POST リクエストを送信する

```json
POST movies/_update/1
{
  "doc": {
    "title": "Castle in the Sky",
    "genre": ["Animation", "Fantasy"]
  }
}
```

> Note the updated title field and new genre field:
- 更新されたタイトルフィールドと新しいジャンルフィールドに注目

```json
GET movies/_doc/1

{
  "_index" : "movies",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 2,
  "_seq_no" : 1,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "title" : "Castle in the Sky",
    "genre" : [
      "Animation",
      "Fantasy"
    ]
  }
}

```

> The document also has an incremented _version field. Use this field to keep track of how many times a document is updated.


- ドキュメントには、増分された _version フィールドもある
- このフィールドを使用して、ドキュメントが更新された回数を追跡する

> POST requests make partial updates to documents. To altogether replace a document, use a PUT request:

- POST リクエストはドキュメントを部分的に更新する
- ドキュメント全体を置き換えるには、PUT リクエストを使用する

```json
PUT movies/_doc/1
{
  "title": "Spirited Away"
}
```

> The document with ID of 1 will contain only the title field, because the entire document will be replaced with the document indexed in this PUT request.

- ID が 1 のドキュメントには、ドキュメント全体がこの PUT リクエストでインデックス付けされたドキュメントに置き換えられるため、タイトル フィールドのみが含まれる

> Use the upsert object to conditionally update documents based on whether they already exist. Here, if the document exists, its title field changes to Castle in the Sky. If it doesn’t, OpenSearch indexes the document in the upsert object.

- upsert オブジェクトを使用して、ドキュメントが既に存在するかどうかに基づいて条件付きで更新する
- 下記では、ドキュメントが存在する場合、そのタイトル フィールドが Castle in the Sky に変更される
- 存在しない場合、OpenSearch は upsert オブジェクトでドキュメントをインデックスする

```json
POST movies/_update/2
{
  "doc": {
    "title": "Castle in the Sky"
  },
  "upsert": {
    "title": "Only Yesterday",
    "genre": ["Animation", "Fantasy"],
    "date": 1993
  }
}
```

Example response
```json
{
  "_index" : "movies",
  "_type" : "_doc",
  "_id" : "2",
  "_version" : 2,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 3,
  "_primary_term" : 1
}
```
> Each update operation for a document has a unique combination of the _seq_no and _primary_term values.

- ドキュメントの各更新操作には、_seq_no 値と _primary_term 値の一意の組み合わせがある

> OpenSearch first writes your updates to the primary shard and then sends this change to all the replica shards. An uncommon issue can occur if multiple users of your OpenSearch-based application make updates to existing documents in the same index. In this situation, another user can read and update a document from a replica before it receives your update from the primary shard. Your update operation then ends up updating an older version of the document. In the best case, you and the other user make the same changes, and the document remains accurate. In the worst case, the document now contains out-of-date information.

- OpenSearch は、まずプライマリ シャードに更新を書き込み、次にこの変更をすべてのレプリカ シャードに送信する
- OpenSearch ベースのアプリケーションの複数のユーザーが同じインデックス内の既存のドキュメントを更新すると、まれな問題が発生する可能性がある
    - このような状況では、プライマリ シャードから更新を受け取る前に、別のユーザーがレプリカからドキュメントを読み取って更新することができる
    - 更新操作を行うと、ドキュメントの古いバージョンが更新される
    - 最良の場合、あなたと他のユーザーが同じ変更を加え、ドキュメントは正確なままになる
    - 最悪の場合、文書に古い情報が含まれることになる

> To prevent this situation, use the _seq_no and _primary_term values in the request header:

- この状況を防ぐには、リクエスト ヘッダーで _seq_no と _primary_term の値を使用する

```json
POST movies/_update/2?if_seq_no=3&if_primary_term=1
{
  "doc": {
    "title": "Castle in the Sky",
    "genre": ["Animation", "Fantasy"]
  }
}
```

> If the document is updated after we retrieved it, the _seq_no and _primary_term values are different and our update operation fails with a 409 — Conflict error.

- ドキュメントを取得後に更新すると、_seq_no と _primary_term の値が異なり、更新操作は 409 — 競合エラーで失敗する

> When using the _bulk API, specify the _seq_no and _primary_term values within the action metadata.

- _bulk API を使用する場合は、アクション メタデータ内で _seq_no 値と _primary_term 値を指定する


### Delete data
> To delete a document from an index, use a DELETE request:

- インデックスからドキュメントを削除するには、DELETE リクエストを使用する

```json
DELETE movies/_doc/1
```

> The DELETE operation increments the _version field. If you add the document back to the same ID, the _version field increments again. This behavior occurs because OpenSearch deletes the document _source, but retains its metadata.

- DELETE 操作により、_version フィールドが増加する
- ドキュメントを同じ ID に再度追加すると、_version フィールドが再び増加する
- この動作は、OpenSearch がドキュメント _source を削除するものの、そのメタデータを保持するため発生するため



-->

# 考察
今回、OpenSearchについて整理してみました。次回はVector Searchについて整理してみたいと思います。


# 参考
https://github.com/opensearch-project

https://opensearch.org/

https://lucene.apache.org/

https://en.wikipedia.org/wiki/Okapi_BM25