ブログ

Elasticsearchのベクトル検索はOpenSearchの最大8倍高速

OpenSearchとElasticsearchのフィルタリングされたベクトル検索ベンチマークを比較し、コンテキストエンジニアリングシステムにおいてベクトル検索のパフォーマンスが重要な理由を探ります。

AIエージェントとコンテキストエンジニアリングにおいて検索速度が重要な理由

2,000万件の文書コーパスを用いたベンチマークテストの結果、Elasticsearchはフィルタリングされたベクトル検索においてOpenSearchよりも最大8倍高いスループットを実現し、テストしたすべての構成においてより高いRecall@100を達成しました。コンテキストエンジニアリングに必要な要素は高速ベクトル取得だけではありません。ワークフローの反復につれて、チームはハイブリッド検索やフィルタリングなどの強力な関連性制御、操作の簡便性、予測可能なパフォーマンスも必要とするようになります。しかし、エージェントはリクエストごとに取得、推論、取得のループを何度も実行することが多いため、取得の遅延が乗数効果となり、ここでの改善はエンドツーエンドの応答性の向上とコスト削減に直接つながります。

OpenSearchとElasticsearchの比較:フィルタリングされたベクトル検索のスループットベンチマーク

グラフ1:スループット。

コンテキストエンジニアリングにおいて、取得は一度きりのステップではありません。エージェントとアプリケーションは、クエリを洗練させ、事実を検証し、根拠に基づいたコンテキストを構築し、タスクを完了するために、取得 → 推論 → 取得といったループを繰り返し実行します。このパターンは、エージェント型ワークフローや反復型検索拡張生成(RAG)においてよく見られます。検索はユーザーリクエストごとに何度も呼び出される可能性があるため、応答に遅延が生じ、インフラコストが増加します。

コンテキストエンジニアリングは、大規模なコンテキストプールを限定されたLLMコンテキストウィンドウに変換します。

図1:コンテキストエンジニアリングは、繰り返し検索とキュレーションを行うことで、大規模なコンテキストプール(ドキュメント、メモリ、ツール、チャット履歴)を限定された大規模言語モデル(LLM)コンテキストウィンドウに変換します。

コンテキストエンジニアリングの最適な実装は新興の手法であり、反復回数はワークフローによって大きく異なります。これらのベンチマーク結果において最も根本的な概念は、コンテキストエンジニアリングが方向性を持つということです。つまり、反復的な検索によってレイテンシが乗数となります。

ベクトル検索のパフォーマンスが重要な理由

「15インチのノートパソコンが入る、防水性があり、金曜日までに届く60ドル以下の機内持ち込み用バックパックが必要です」という質問に、店員が答える場面を想像してみてください。

実際の運用環境では、アシスタントがベクトルクエリを1回発行して停止することはほとんどありません。適切なコンテキストを構築するために検索ループを実行し、各ステップは通常、在庫状況、地域、出荷約束、ブランドルール、ポリシー適格性などのフィルターによって制約されます。

ステップ1:意図を解釈し、制約に変換する。

エージェントはリクエストを構造化されたフィルタとセマンティッククエリに変換します。例えば、次のようなものです。

  • フィルター:在庫あり、ユーザーの郵便番号に配達可能、金曜日までに配達、価格60ドル未満、有効な出品

  • ベクトルクエリ:「機内持ち込み用バックパック 15インチノートパソコン対応 防水」

ステップ2:候補を取得し、絞り込む。

適切な一致を見逃さないように、しばしばバリエーションを加えて検索を繰り返します。

  • 「旅行用バックパック 機内持ち込み可能 ノートパソコン用スリーブ」

  • 「防水通勤用バックパック 15インチ」

  • 「軽量 機内リュック」

各クエリは同じ適格性フィルターを使用します。なぜなら、無関係な項目や利用できない項目を取得することは、コンテキストの無駄になるからです。

ステップ3:詳細を確認し、リスクを軽減するために展開する。

エージェントは、最終的な回答に影響を与える主要な属性を再度確認するために取得を行います。

  • 素材と耐水性に関する記述

  • 寸法とノートパソコン収納部の適合性

  • 返品ポリシーや保証の制約

  • 在庫が少ない場合の代替オプション

これは、取得、推論、取得、組み立てという複数段階のコンテキストエンジニアリングです。

コンテキストエンジニアリングにおいてレイテンシと再現率が重要な理由

これらのやり取りには、ユーザーセッションごとに数十回のフィルタリングされたデータ取得呼び出しが含まれる場合があります。それにより、呼び出しごとのレイテンシがエンドツーエンドの応答時間に直接的な乗数となり、低い再現率は追加の再試行を強制したり、エージェントが対象アイテムを見逃す原因となり、回答の質を低下させます。

要点:コンテキストエンジニアリングされたシステムでは、フィルタリングされた近似最近傍法(ANN)は単一のルックアップではありません。これは制約下での反復処理であるため、大規模言語モデル(LLM)が最も目立つ要素である場合でも、ベクトル検索のパフォーマンスはレイテンシ、スループット、コストにすぐに現れます。

ベンチマーク

成果

グラフ2では、各点が1つのテスト構成を表しています。最も良い結果は左上に表示され、これは低いレイテンシで高い再現率が得られることを意味します。Elasticsearchの結果はOpenSearchよりも常に左上に近く、同じワークロード設定下でより優れた速度と精度を示しています。

 グラフ2:再現率対平均レイテンシ(再スコア1)。

グラフ2:再現率対平均レイテンシ、再スコアは1。

いくつかの重要な洞察

  • s_n_r_value: size_numCandidates_rescoreOversampleの省略形(これらのテストではkとnumCandidatesはnumCandidatesと等しく設定されます)。例えば、 100_500_1 size=100、numCandidates=500、k=500、再スコアオーバーサンプル=1 を意味します。

  • 再現率:その構成における測定Recall@100

  • 平均レイテンシ(ミリ秒):クエリごとの平均エンドツーエンドレイテンシ

  • スループット:1秒あたりのクエリ数

  • 再現率(%):ElasticsearchとOpenSearchの相対的な再現率向上率(Elasticsearch - OpenSearch)/OpenSearch

  • レイテンシXs:OpenSearchの平均レイテンシをElasticsearchの平均レイテンシで割った値

  • スループットX:Elasticsearchのスループットをオープンサーチのスループットで割った値

エンジン

`s_n_r_value`

リコール

平均レイテンシ(ミリ秒)

スループット

再現率(%)

レイテンシ Xs

スループット Xs

Elasticsearch

100_250_1

0.7704

25

534.75

9.70%

2.28

1.91

OpenSearch

100_250_1

0.7023

57.08

279.58

Elasticsearch

100_500_1

0.8577

25.42

524.14

7.20%

2.4

2

OpenSearch

100_500_1

0.8001

60.9

262.12

Elasticsearch

100_750_1

0.8947

29.67

528.09

5.72%

2.25

2.21

OpenSearch

100_750_1

0.8463

66.76

239.11

Elasticsearch

100_1000_1

0.9156

29.65

534.5

4.66%

2.46

2.44

OpenSearch

100_1000_1

0.8748

72.88

219.01

Elasticsearch

100_1500_1

0.9386

31.84

497.3

3.38%

2.71

2.68

OpenSearch

100_1500_1

0.9079

86.16

185.4

Elasticsearch

100_2000_1

0.9507

34.69

457.2

2.57%

2.98

2.96

OpenSearch

100_2000_1

0.9269

103.36

154.55

Elasticsearch

100_2500_1

0.9582

37.9

418.43

1.99%

3.28

3.26

OpenSearch

100_2500_1

0.9395

124.29

128.53

Elasticsearch

100_3000_1

0.9636

41.86

379.4

1.62%

3.46

3.44

OpenSearch

100_3000_1

0.9482

144.67

110.34

Elasticsearch

100_4000_1

0.9705

50.28

316.21

1.06%

3.87

3.85

OpenSearch

100_4000_1

0.9603

194.36

82.22

Elasticsearch

100_5000_1

0.9749

58.77

270.91

0.73%

4.43

4.41

OpenSearch

100_5000_1

0.9678

260.33

61.38

Elasticsearch

100_6000_1

0.9781

66.75

238.59

0.52%

4.91

4.89

OpenSearch

100_6000_1

0.973

327.44

48.81

Elasticsearch

100_7000_1

0.9804

74.64

213.49

0.38%

5.28

5.27

OpenSearch

100_7000_1

0.9767

394.24

40.53

Elasticsearch

100_8000_1

0.9823

82.28

193.59

0.27%

6.86

6.83

OpenSearch

100_8000_1

0.9797

564.14

28.33

Elasticsearch

100_9000_1

0.9837

90.08

176.96

0.16%

7.63

7.61

OpenSearch

100_9000_1

0.9821

687.25

23.25

Elasticsearch

100_10000_1

0.9848

97.64

163.31

0.08%

8.38

8.36

OpenSearch

100_10000_1

0.984

818.64

19.53

例えば、100_9000_1では、OpenSearchの平均取得時間687ミリ秒に対してElasticsearchは90ミリ秒であり、10ステップの取得ループでは約10×(687-90)=6秒の追加待機時間となります。

全ての結果をご覧ください。

調査手法

Pythonを使ってクエリを送信し、対応タイミングやその他の統計を追跡し、以下のクエリをエンジンに送信しました。ベクター検索エンジンのパフォーマンスは、そのコアパラメータ(考慮する候補の数、再スコアリングの積極性、返されるコンテキストの量など)をどのように調整するかによって決まることを覚えておいてください。これらの設定は、再現率(正解を見つける可能性)とレイテンシ(結果を得るまでの速さ)の両方に直接影響します。

ベンチマークでは、エージェント検索ループで通常調整するのと同じ候補、再スコア、結果サイズの設定を使用し、そのワークロード下でElasticsearchがどのように機能するかを測定しました。その後、同じ設定でOpenSearchをリファレンスとして実行しました。

OpenSearch

GET <INDEX_NAME>/_search
{
  "query": {
    "knn": {
      "<DENSE_VECTOR_FIELD_NAME>": {
        "vector": [...],
        "k": <NUMBER_OF_CANDIDATES>,
        "method_parameters": {
          "ef_search": <NUMBER_OF_CANDIDATES>
        },
        "rescore": {
          "oversample_factor": <OVERSAMPLE>
        },
        "filter": {
          <SOME_FILTER>
        }
      }
    }
  },
  "size": <RESULT_SIZE>,
  "_source": {
    "excludes": [
      "<DENSE_VECTOR_FIELD_NAME>"
    ]
  }
}
  • "size": <RESULT_SIZE>: クライアントに返されたヒット数。このベンチマークでは、Recall@100を計算するために、結果のサイズは100です。

  • "k": <NUMBER_OF_CANDIDATES>: 最近傍候補の数。

  • "ef_search": <NUMBER_OF_CANDIDATES>: 検査するベクトルの数。

  • "oversample_factor": <OVERSAMPLE>: 再スコアリングを行う前に取得される候補ベクトルの数。

Elasticsearch

GET <INDEX_NAME>/_search
{
  "query": {
    "knn": {
      "field": "<DENSE_VECTOR_FIELD_NAME>",
      "query_vector": [...],
      "k": <NUMBER_OF_CANDIDATES>,
      "num_candidates": <NUMBER_OF_CANDIDATES>,
      "rescore_vector": {
        "oversample": <OVERSAMPLE>
      },
      "filter": {
        <SOME_FILTER>
      }
    }
  },
  "size": <RESULT_SIZE>,
  "_source": {
    "excludes": [
      "<DENSE_VECTOR_FIELD_NAME>"
    ]
  }
}
  • "size": <RESULT_SIZE>: クライアントに返されたヒット数。このベンチマークでは、Recall@100を計算するために、結果のサイズは100です。

  • "k": <NUMBER_OF_CANDIDATES>: 各シャードから返す最近傍の数。

  • "num_candidates": <NUMBER_OF_CANDIDATES>: knn検索を実行する際にシャードごとに考慮する最近傍候補の数。

  • "oversample": <OVERSAMPLE>: 再スコアリングを行う前に取得される候補ベクトルの数。

Knn クエリ( 100_500_1 )は次のようになります。

OpenSearch

GET search_catalog_128/_search
{
  "query": {
    "knn": {
      "search_catalog_embedding": {
        "vector": [...],
        "k": 500,
        "method_parameters": {
          "ef_search": 500
        },
        "rescore": {
          "oversample_factor": 1
        },
        "filter": {
          "term": {
            "valid": true
          }
        }
      }
    }
  },
  "size": 100,
  "_source": {
    "excludes": [
      "search_catalog_embedding"
    ]
  }
}

Elasticsearch

GET search_catalog_128/_search
{
  "query": {
    "knn": {
      "field": "search_catalog_embedding",
      "query_vector": [...],
      "k": 500,
      "num_candidates": 500,
      "rescore_vector": {
        "oversample": 1
      },
      "filter": {
        "term": {
          "valid": true
        }
      }
    }
  },
  "size": 100,
  "_source": {
    "excludes": [
      "search_catalog_embedding"
    ]
  }
}

Terraformスクリプト、Kubernetesマニフェスト、ベンチマークコードとともに、完全な構成はこのリポジトリes-9.3-vs-os-3.5-vector-searchフォルダで入手可能です。

クラスターの設定

私たちは、16 vCPUと64 GB RAMを備えた6台のe2-standard-16クラウドサーバーでテストを実行しました。各サーバーにおいて、検索エンジンノードを実行する各Kubernetesポッドに15個のvCPUと56GBのRAMを割り当て、そのうち28GBをJVMヒープ用に確保しました。

クラスターはElasticsearch 9.3.0とOpenSearch 3.5.0(Lucene 10.3.2)で実行しました。このベンチマークでは両方のシステムが同じLuceneバージョンを使用しているため、観測されたスループットとレイテンシの違いはLucene単独に起因するものではなく、各エンジンがフィルタリングされたk近傍法(kNN)による検索と再スコアリングをどのように統合し実行するかの違いを反映します。私たちは、3つのプライマリシャードと1つのレプリカ(合計6つのシャード、ノードごとに1つ)を持つ単一のインデックスを使用しました。

我々はまた、同じリージョン内の別のサーバーを使用してベンチマーククライアントを実行し、タイミング統計を収集しました。

ElasticsearchとOpenSearchのベンチマーク用のクラスター設定

図2:クラスターの構成図。

データセット

このベンチマークでは、2,000万件のドキュメントを含む大規模なeコマーススタイルのカタログ埋め込みデータセットを使用しました。これは、実世界のフィルタリングされたベクトル検索を大規模なスケールで反映するように設計されています。

各ドキュメントはカタログ項目を表し、以下を含みます。

  • 近似kNN検索に使用される128次元の密なベクトル埋め込み。

  • 構造化されたメタデータフィールドを使用してフィルタリング(例:アイテムの有効性と可用性、およびその他のカタログ制約)を行うことで、適格なサブセット内でのみ最近傍を取得するという一般的な本番パターンを可能にします。

このデータセットを選んだ理由は、本番環境におけるエージェント型システムやRAG型システムで見られる主要なパフォーマンス上の課題を捉えているからです。つまり、ベクトル類似性だけでは不十分であり、検索はフィルタによって制約されることが多く、システムはこれらの制約の下で高い再現率を維持しながらレイテンシを低く抑える必要があるということです。より小規模なQAスタイルのデータセットと比較すると、2000万件の文書コーパスは、フィルタリングされたANNシステムが実際に直面する規模と候補数によるプレッシャーをより適切に反映しています。

まとめ

現代のAIアーキテクチャー、特にコンテキストエンジニアリングを中心としたアーキテクチャーにおいては、ベクトル探索の速度は些細な実装上の問題ではなく、乗数です。エージェントとワークフローが取得 → 推論 → 取得を繰り返す際、検索パフォーマンスはエンドツーエンドのレイテンシ、スループット、モデルに供給されるコンテキストの品質を直接形作ります。

当社のベンチマークでは、Elasticsearchは、OpenSearchと比べて、より低いレイテンシで一貫して高い再現率を達成しました。これは、類似ベクトルの取得だけでなく、正確性が「適切なドキュメントを取得できること」に左右されるシナリオで顕著でした。制御されたデータセットではその差は明確であり、本番環境では、大量の検索呼び出しを通じてそれらの利点が蓄積され、応答性が向上し、容量余裕が増加し、インフラストラクチャーコストが削減されます。

参考資料

  1. コンテキストエンジニアリングとは何ですか?

  2. ハイブリッド検索とコンテキストエンジニアリングの進化

  3. AIエージェント向けコンテキストエンジニアリングにおける関連性の影響

関連記事

LINQ to Elasticsearch ES|QL:C#を記述してElasticsearchをクエリ

Florian Bernd

Elasticsearch の NLP とベクトル検索によるチャットボット機能の強化

Priscilla Parodi

OpenSearchとElasticsearchの違い:ベクトル検索のパフォーマンス比較

Ugo Sangiorgi

AI盗作:Elasticsearchによる盗作検出

Priscilla Parodi

高度なRAGテクニックパート2:クエリとテスト

Han Xiang Choong

最先端の検索体験を構築する準備はできましたか?

十分に高度な検索は 1 人の努力だけでは実現できません。Elasticsearch は、データ サイエンティスト、ML オペレーター、エンジニアなど、あなたと同じように検索に情熱を傾ける多くの人々によって支えられています。ぜひつながり、協力して、希望する結果が得られる魔法の検索エクスペリエンスを構築しましょう。

はじめましょう