4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

この記事は ミライトデザイン Advent Calendar 2025 の 16 日目の記事となっています。

初めに

最近 OpenSearch に入門したいモチベがあったので、入門のついでにアドカレを書くことにしました。
筆者が気になることを気の向くままに調べた記事になります。
筆者自体が入門者なので、間違いなどあればご指摘いただけると嬉しいです。

OpenSearch とは

OpenSearchは、Apache Luceneをベースにしたオープンソースの分散型検索・分析エンジンです。
ElasticsearchのフォークとしてAWSが開発しており、JSON形式のドキュメント指向データベースとして、RESTful APIで操作可能です。

OpenSearch の基本

OpenSearch と RDBMS の違いのイメージ

RDBMS に対しての、対応と各 OpenSearch の要素の簡単な説明は次のようになります。

RDBMS OpenSearch 説明
データベース クラスター 複数のノードで構成されるシステム全体
テーブル インデックス データの集合体
行(レコード) ドキュメント 個々のデータ
列(カラム) フィールド ドキュメント内の項目
スキーマ マッピング データ構造の定義

クラスターについては、ちょっと複雑なので、先にインデックスから説明します。

インデックスとは

インデックス は、 OpenSearch におけるデータの集合です。RDBMSの「テーブル」に相当します。

例えば、 EC サイトを構築している場合であれば、次のようなインデックスが作成されることになります。

- products インデックス ... 商品情報を格納
- users インデックス ... ユーザー情報を格納
- orders インデックス ... 注文情報を格納

ただし、 RDBMS と同じように インデックス の設計ができるわけではないので注意が必要です。
RDBMS は、正規化して検索時に join するような設計をするかと思いますが、
OpenSearch の場合は、基本的にはインデックス間の join ができず、非正規化の構成になります。

例えば、 orders インデックスに、 products id と users id が保存されている場合は、 アプリケーション側での join が必要になります。
(orders インデックスをそもそも作成する必要があるのかというのも、インデックス設計の場合は議論となるところなのかもしれません。)

RDBMS は、エンティティ(実体)単位で設計してから、検索方法を考える、
OpenSearch のような全文検索エンジンは、データへの検索方法を設計してから、インデックス設計を考える。のような違いがあると思っています。

ドキュメントとは

ドキュメントとは、 OpenSearch での最小のデータのまとまり、
RDBMS で言うところのレコードになり、 JSON 形式で表現されています。

先ほどの、 EC サイトの例で再度考えると、商品ドキュメントの例は次のようになります。

{
  "product_id": "PROD-001",
  "product_name": "ワイヤレスイヤホン",
  "price": 5980,
  "category": "electronics",
  "stock": 50,
  "is_available": true
}

フィールドとは

フィールドは、ドキュメント内の個々の項目です。 RDBMSのカラムに相当します。

上記の例では、次の項目それぞれが、フィールドとなります。

product_id
product_name
price
category

マッピングとは

マッピングは、 RDBMS でいうところの、スキーマ定義に相当します。

次のように定義を行います。

{
  "mappings": {
    "properties": {
      "product_id": { "type": "keyword" },
      "product_name": { "type": "text" },
      "price": { "type": "float" },
      "category": { "type": "keyword" },
      "stock": { "type": "integer" },
      "is_available": { "type": "boolean" }
    }
  }
}

マッピングでは次のようなことを定義します。
()の中は、 mappings に定義するパラメータ名です。

  • 検索対象にする?(index)
  • どう単語分割する?(analyzer)
  • 集計・ソートする?(doc_values)
  • 個別保存する?(store)
  • データ型は?(type)

それぞれについて簡単に確認していきます。

▫️検索対象にする?(index)

{
  "description": {
    "type": "text",
    "index": true  // 検索できる(デフォルト)
  },
  "internal_memo": {
    "type": "text",
    "index": false  // 検索できない(保存のみ)
  }
}

index: true → 検索可能にする
index: false → 検索不可(データは保存されるが検索対象外)

▫️どう単語分割する?(analyzer)

text型の場合、どのように単語分割するかを指定します。

{
  "product_name": {
    "type": "text",
    "analyzer": "japanese"  // 日本語形態素解析
  },
  "english_description": {
    "type": "text",
    "analyzer": "english"  // 英語用アナライザー
  }
}

アナライザーの役割:

  • "ワイヤレスイヤホン" → ["ワイヤレス", "イヤホン"] に分割
  • 検索時にも同じ方法で分割するため、部分一致検索が可能

アナライザーと形態素解析についてよくわからなかったので、ざっと調べてみました。

アナライザーは次の3つの要素で構成されでいるらしいです。

  1. Character Filters(文字フィルター)
    テキストストリームの前処理を行う
    例: HTMLタグの除去、特定文字の置換

  2. Tokenizer(トークナイザー)
    テキストをトークン(単語)に分割
    例: 空白で分割、特定のパターンで分割

  3. Token Filters(トークンフィルター)
    トークンの変換・追加・削除を行う
    例: 小文字化、ストップワード除去、同義語追加

形態素解析は 2 で利用され、次のように文章を分割します。

"私は速く走っています"
↓
["私", "速く", "走る", "て", "いる"]

3 でストップワード(「て」、「いる」などの、検索時にあまり意味を持たない単語)を除外したりしているらしいです。

OpenSearch では、形態素解析に使用する辞書や同義語検索で利用される辞書をユーザーが追加することが可能らしいです。

▫️集計・ソートする?(doc_values)

{
  "price": {
    "type": "float",
    "doc_values": true  // 集計・ソート可能(デフォルト)
  },
  "search_keyword": {
    "type": "keyword",
    "doc_values": false  // 検索のみ、集計不要
  }
}
  • doc_values: true → 集計、ソート、スクリプトで使用可能
  • doc_values: false → メモリ節約(検索のみに使う場合)

OpenSearch では検索以外にも、集計、ソート、スクリプト(商品の金額に消費税をかけて、消費税込みでソートするなど)があります。
そこから高速で参照できるようにする。みたいなイメージをしています。

▫️個別保存(storeパラメータ)

通常、全フィールドは_sourceに保存されますが、store: trueにすると個別にアクセス可能になります。

どういう意味かと言うと。

OpenSearchは、ドキュメントを保存する際に2つの方法でデータを管理しています。

  1. _sourceフィールド(デフォルト)
    ドキュメント全体のオリジナルJSONが、_sourceという特別なフィールドに保存されます。
// 投入したドキュメント
{
  "product_id": "PROD-001",
  "product_name": "ワイヤレスイヤホン",
  "description": "高音質Bluetooth対応のワイヤレスイヤホン。ノイズキャンセリング機能搭載で、クリアな音質を実現...",
  "price": 5980
}

// OpenSearch内部
{
  "_source": {  //  ここに元のJSON全体が保存される
    "product_id": "PROD-001",
    "product_name": "ワイヤレスイヤホン",
    "description": "高音質Bluetooth対応の...",
    "price": 5980
  },
  // + 検索用の転置インデックス(別領域)
}
  1. 検索用の転置インデックス(別領域)
    検索を高速化するために、各フィールドは「転置インデックス」という別の形式で保存されるらしいです(これは_sourceとは別)。

通常、フィールドの値を取得するには_source全体を読み込む必要があります。しかし、store: trueを設定すると、そのフィールドだけを個別に取り出せるようになります。

{
  "mappings": {
    "properties": {
      "product_name": {
        "type": "text",
        "store": false  // デフォルト:_sourceから取得
      },
      "large_description": {
        "type": "text",
        "store": true  // このフィールドは個別保存
      }
    }
  }
}

これにより、例えば、長文の説明文があるドキュメントなどで、全てのフィールドを取得するのではなく、
特定のフィールドのみを取得できるというメリットがあります。

▫️データ型(typeパラメータ)

こちらは、想像しやすいかなと思います。
フィールドのデータの型定義になります。

{
  "product_name": { "type": "text" },      // 全文検索
  "product_id": { "type": "keyword" },     // 完全一致
  "price": { "type": "float" },            // 数値
  "created_at": { "type": "date" },        // 日付
  "is_active": { "type": "boolean" }       // 真偽値
}

データ型の詳しい種類はこちら

マッピングで注意しておくべき点

マッピングは、 RDBMS でいうところの、スキーマ定義に相当すると記載しましたが、当然違いはあるようです。
RDBMS とは違う点について簡単に調べました。

▫️text vs keyword の使い分け

同じ文字列型でも、データ型によって、検索方法などに違いがあります。

text はアナライズの対象となる全文検索用の型で、部分一致で検索が可能です。
keyword はアナライズの対象とならず、部分一致の検索ができません。完全一致の検索が可能です。
そのため、 ID などは keyword で、部分一致で検索したい商品名などは text に設定します。

text + keyword のようなマルチタイプ型も定義することもできるようです。

▫️動的マッピングの挙動

動的マッピングが有効になっていると、最初に投入されたデータの値によって、自動的に型が決まります。

明示的にマッピングをしていても、未定義のフィールドがあると自動的にマッピングされてしまいます。

動的マッピングは dynamic パラメータの設定で変更できるらしく、次のように挙動を変更できるようです。

  • 未定義フィールドを自動的にマッピングする
  • 未定義フィールドを無視する(保存はされるが、検索はできない)
  • 未定義フィールドがあるとエラーになる

クラスターについて

クラスターは今までのものとは少し毛色が違ってきます。
今までは OpenSearch の論理的な仕組みについての話でしたが、ここからは具体的なサーバー構成のような話になります。

終わり

急に終わります。

この後は、具体的なサーバー構成についての話を調べて、ローカルに環境構築して触ってみる。みたいなことをしたいのですが、
記事が長くなりそうなのと、アドカレの期日になってしまったので別記事にしたいと思います(モチベが続けば)。

明日は mozumasu さんの記事になります!

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?