Elasticsearchのインデックスとは?

info-retrieval-blog-720x420-v2.jpeg

ITの世界では、インデックスという言葉が実にさまざまな意味で使われています。もっとも、開発者に「インデックスとは何ですか?」と聞けば、ほとんどの方が、「一般にはリレーショナルデータベース(RDBMS)の中で使うデータ構造の一種を指し、テーブルに関連付けてデータの取得速度を高めるもの」といったような答えを返してくるのではないでしょうか。

では、Elasticsearch®のインデックスとは何でしょうか?Elasticsearchのインデックスは、さまざまなドキュメントが集まった論理的な名前空間です。各ドキュメントは、フィールドがいくつも集まってできています。そしてそのフィールドは、データを格納したキーバリューペアとなっています。

Elasticsearchのインデックスとリレーショナルデータベースの違い

Elasticsearchのインデックスは、リレーショナルデータベースのインデックスとは異なります。ここで、Elasticsearchクラスターを1件のデータベースだと考えてみましょう。このデータベースには多数のインデックスがあります。インデックスは、それぞれがテーブルに相当します。各インデックスはさらに、内部に多数のドキュメントを格納した構造になっています。   

  • RDBMS => データベース => テーブル => 列/行
  • Elasticsearch => クラスター => インデックス => シャード => キーバリューペアから構成されたドキュメント

Elasticsearchが格納するのはJSONドキュメントですが、インデックスに入力できるデータは信じられないほど柔軟性に富んでいます。また、さまざまな統合機能Beatsを使えば、すぐに運用を始めることができます。さらに、少し手間を掛ければ、インジェストパイプラインLogstash®を使って独自のETLプロセスを定義することもできます(そのためのプロセッサーやプラグインも多数用意されています)。

リレーショナルデータベースと異なる点としてはほかにも、事前にスキーマを定義しなくてもデータをインポートできることが挙げられます。これを実現するのがダイナミックタイプです。ダイナミックタイプを使えば、すぐに運用を開始できるほか、ドキュメントに予期していなかったフィールドが発生する事態にも備えることができます。パフォーマンスを高めたければ、準備が整った時点で固定のスキーマに切り替れば済みます。 

ランタイムフィールドも興味深い機能です。これは、読み書きの際にスキーマを作成できる機能です。ランタイムフィールドは、既存のドキュメントに追加して新しいフィールドを生成することも、クエリ実行時に作成することもできます。ランタイムフィールドは、ドキュメントのソースを読み取るスクリプトを使って計算した値だと考えると良いでしょう。

ここに挙げた違いをその目で確かめてみたいという方は、Elastic Cloudの無料トライアルをご利用ください(トライアルアカウントの作成が必要です)。

Elasticsearchの使いやすいAPIを用いたデータ操作

Elasticsearchには、ドキュメントデータの操作ができるJSONベースのRESTful APIが用意されています。ドキュメントのインデックス、検索、更新、削除は、クラスターエンドポイントにHTTPリクエストを送信して実施します。このCRUD的な機能はいずれも、個々のドキュメントレベルとインデックスレベルのどちらでも利用できます。また、必要に応じてRESTの代わりに言語別のクライアントライブラリを使用することもできます。
以下のコード例は、playwrightsというインデックスにドキュメントを1件作成するものです。document_idとしては1を割り当てています。ご注目いただきたいのは、スキーマや設定を事前に作成していないという点です。つまり、単にデータを挿入しているだけなのです。

POST /playwrights/_doc/1
{
  "firstname": "William",
  "lastname": "Shakespeare"
}

ドキュメントやフィールドは、以下のように必要に応じて好きなだけ追加できます。このようなことは、リレーショナルデータベースでは簡単にはできません。

POST /playwrights/_doc/2
{
  "firstname": "Samuel",
  "lastname": "Beckett",
  "year_of_birth": 1906
}

以下はドキュメントを全件取り出すクエリです。検索エンドポイントを使用している点にご注目ください。

GET /playwrights/_search
{
    "query": {
        "match_all": {}
    }
}

誕生年のような要素を使ってクエリを実行することもできます。

GET /playwrights/_search
{
    "query": {
        “match": {
            “year_of_birth": 1906
        }
    }
}

Elasticsearchが対応しているのは基本的なクエリばかりではありません。ファジーマッチ、ステミング、関連性スコアリング、ハイライト表示、トークン化などの高度な検索機能にも対応しています。このうち、トークン化とは、テキストを"トークン"と呼ばれる小さなかたまりに分割する機能です。トークンは1単語であることが大半ですが、トークナイザーにはさまざまなものがあるので、単語以外のトークンもありえます。

非正規化データがデータの取得高速化の鍵となる理由

リレーショナルデータベースでは、データの重複を排除し、データの一貫性を確保するために、データを正規化するのが一般的です。たとえば、顧客、製品、注文のそれぞれに別個のテーブルを設けるような運用がよくみられます。 

これに対してElasticsearchでは、正規化を実施しない運用が一般的です。データを多数のテーブルに分割するのではなく、関係のある情報をすべて単体のJSONドキュメントに格納しておくのです。注文のドキュメントには顧客と製品のどちらの情報も格納されます。製品や顧客のインデックスを参照する外部キーを、注文のドキュメントに設定するやり方とは対照的です。これこそ、Elasticsearchが検索処理によるデータ取得の速度と効率を高めている秘訣にほかなりません。一般論として、データの結合処理のコンピューティングコストよりも、ストレージの方がコストが少なくて済みます。

Elasticsearchが分散システムでスケーラビリティを実現するしくみ

インデックスにはそれぞれ固有の名前が付いており、一意に特定できるようになっています。また、各インデックスはいくつかの"シャード"に分かれています。シャードとは、インデックスを細かく分割した単位で、これがElasticsearchノードから成るクラスターで並列処理や分散ストレージを可能にしています。 シャードにはプライマリシャードとレプリカシャードがあります。レプリカは、ハードウェアの障害に備えてデータをコピーして冗長化を図るとともに、各種の読み取りリクエスト(ドキュメントの検索や取得など)に対する処理能力を高める役割を果たします。

クラスターにノードを追加するほど、インデックスや検索の機能が強化されていきます。このようなことをリレーショナルデータベースで実現するのは簡単ではありません。

先ほどのplaywrightsの例に戻りましょう。以下のコマンドを実行すると、Elasticsearchが自動で推測したタイプマッピングのほか、インデックスのシャードとレプリカの数が表示されます。

GET /jp/playwrights/

Elasticsearchでインデックスできるデータの種類

Elasticsearchでは、テキストや数字から位置情報データに至るまで、さまざまなデータをインデックスできます。また、類似検索で使う密ベクトルを格納することもできます。では、1つずつ見ていきましょう。

倒置インデックスを使ったテキスト/語彙検索

Elasticsearchには、フィールドのタイプに応じて最善のデータ構造を選択する機能も備わっています。たとえば、テキストであればトークン化したうえで倒置インデックスに格納されます。倒置インデックスはデータ構造の一種で、ドキュメントに出現するトークンの1つひとつをリスト化し、各単語が出現するドキュメントをすべて特定できるようにしたものです。

以下のテーブルは、倒置インデックスの構成を大まかに示したものです。"ロンドン"という語句を検索すると、インデックス内の6件のドキュメントに出てくることがわかります。この倒置インデックスが、非常に高速なテキストクエリを実現します。

トークン

ドキュメントID

ロンドン

1,3,8,12,23,88

パリ

1,12,88

マドリッド3,8,12
ベルリン12,23

数字検索と位置情報検索による効率的な空間分析

数値データや位置情報データは、BKDツリー(ブロックKDツリーインデックス)に格納します。BKDツリーは、エンジニアリングアプリケーションで使われるデータ構造で、多次元データを対象に効率的な空間インデックスやクエリが可能になります。BKDツリーでは、データポイントをブロック単位に整理します。大規模なデータセットを対象とした高速範囲検索や最近傍クエリが可能になるため、空間データの分析や最適化に携わるエンジニアには非常に有益なツールとなっています。

NLPによるベクトル検索/セマンティック検索

ベクトル検索という言葉を聞いたことがある方もいるかもしれませんが、具体的にはいったいどんなものでしょうかベクトルデータベース、セマンティック、またはコサイン検索とも呼ばれるベクトル検索エンジンは、特定の(ベクトル化された)クエリに対して最近傍を検出します。ベクトル検索の魅力は、検索テキストが(上に挙げた倒置インデックスの例のように)完全に一致していなくても、入力に近いドキュメントを検出できるという点です。ベクトル検索では、類似性を表現したベクトルを使用します。 

自然言語処理(NLP)のコミュニティでは、テキスト埋め込みと呼ばれるテクニックの開発が行われてきました。これは、単語と文章を数的ベクトルでエンコード化する技術です。こうしたベクトル表現はテキスト中の言語学的コンテンツをとらえる目的で設計されており、クエリとドキュメントの間の類似性を評価するために使用することができます。

ベクトル検索のよくある用途を以下にいくつか紹介します。 

  • 質問に対する回答
  • 以前に答えた質問に対する回答の検索(テキストとしては完全に同じではないものの、質問内容が似ている場合に使用) 
  • 提案(音楽アプリケーションでユーザーの好みに応じてよく似た曲を見つけるなど)  

いずれも、類似性を正確に評価したり、ターゲットに合った提案をしたりするために、何万次元にもなるベクトルを使って データを包括的に表現しています。 

Elasticsearchでは、ベクトル検索に対応するために、dense_vectorというドキュメントタイプのほか、ドキュメント内のベクトルと、ベクトルに変換した検索語句とを比較できる類似検索の機能をご用意しています。 

生成的AIに関心をお持ちの方には、ほかにもESRE(Elasticsearch Relevance Engine™)をご用意しています。こちらは、人工知能ベースの検索アプリケーションの原動力となることを目指して設計したエンジンです。洗練された検索アルゴリズムスイートと、大規模言語モデルとの統合機能を開発者にお届けします。

試してみる

Elasticsearchインデックスは、Elasticの共同創業者で最高技術責任者のシェイ・バノンが妻のためにレシピ検索エンジンを開発したことから始まり、長い歴史を経て今に至ります。Elasticsearchインデックスの魅力は、今回紹介したものだけにとどまりません。まずはぜひ、Elastic Cloudでトライアルアカウントを作成してください。わずか数分で試用を始められます。また、ウェビナー「Elasticsearchのデータ操作入門」のご視聴もお待ちしております。

2013年2月24日初稿公開、2023年7月17日更新。