🔎

Azure AI Searchの検索手法とスコアリングについて

2024/03/31に公開

背景

Azure OpenAI Serviceを使ったRAGシステムを作るとなった場合、基本的にインデックスの作成と検索はAzure AI Searchを使うことになります。

検索を実行すると、@search.scoreや@search.rerankerScoreに数値が返ってくるのですが、
検索アルゴリズムによって算出方法が違うので、その辺をまとめました。

インデックス検索の際には、大きく分けると3つの検索方法とリランキングするセマンティックランク付けの有無で、4つのスコアがあるため、それぞれどんなものか、概要を説明します。

検索方法とスコア概要

検索方法 概要 検索結果スコアリング スコア範囲 参照
フルテキスト検索 単語の出現頻度 (TF) と逆文書頻度 (IDF) が変数として使用され、ドキュメントとクエリの組みごとに関連スコアが計算される。
BM25は確率論的情報取得に根ざしており、ユーザーの調査で測定した場合のように、より直感的な一致が生成される。
データインデックス全体での語句の出現頻度は低いがドキュメント内ではよく使用されている場合、検索スコアは高くなる
BM25アルゴリズム 無制限(1~10くらいのイメージ) Link
ベクトル検索 ベクトル コンテンツのインデックス付け方法に応じて、関連する一致の検索は網羅的であるか、ニアネイバーに制限されて処理が高速化されます。 候補が見つかると、類似性メトリックを使用して、一致の強度に基づいて各結果のスコアが付けられます。
つまりKNNかHNSWのいずれかで絞られて、cosine、dotProduct、euclideanでスコア計算がされランキングが決まる
1 / (1 + cosine_distance) Cosine: 0.333 - 1.00 Link
ハイブリッド検索 複数の方法から検索結果を取得し、結果の各ドキュメントに逆順位スコアを割り当て、スコアを組み合わせて新しいランク付けを作成する
スコアはΣ1/(rank + k) として計算される
rank はリスト内のドキュメントの位置であり、k は定数で文書の順位が最終的な順位に与える影響を決めており、60 などの小さな値に設定されている場合に最適に実行されることが実験で確認されている
このk値はRRFアルゴリズムの定数であり、ベクター検索で使用される近傍の数kとは完全に別の定数である
RRFアルゴリズム Σ1/(rank + k)(0.03くらいのイメージ) Link
セマンティック ランク付け セマンティック ランク付けには、サマライゼーションとスコアリングという2つの手順があります。 出力が再スコアリングされた結果、キャプション、および回答で構成されます。
1つ目として、BM25 または RRF を使用してスコア付けされた、最初の結果セットに対する二次ランク付けが追加されます。 この二次ランク付けでは多言語の、Microsoft Bing から変化したディープ ラーニング モデルが使用されて、セマンティック的に最も関連性の高い結果が奨励されます。
2つ目として、キャプションと回答が抽出されて応答で返されます。これを検索ページにレンダリングして、ユーザーの検索エクスペリエンスを向上させることができます。
要は、コンテキストを加味した回答、スコアがつくられるみたいな感じかと。
セマンティック ランク付け 0 - 4 Link

まとめ

基本的には関連ドキュメントを検索したいのであれば、ハイブリッド検索 + セマンティック ランク付の精度が高いイメージです。

ただし、テキストだけのドキュメントであれば、フルテキスト検索で十分であるとか、
マルチモーダルなRAGの場合、インデックスにテキストと画像ベクトルが
入っている場合にはハイブリッド検索が有効であるとか、検索対象のドキュメントと求める検索精度、コストでどの検索アルゴリズムを利用するかが決まるのかなと。

参考

ハイブリッド検索 + セマンティック ランク付のワークフロー

前のワークフローを生成するクエリは、次のようになります。

POST https://{{search-service-name}}.search.windows.net/indexes/{{index-name}}/docs/search?api-version=2023-11-01
Content-Type: application/json
api-key: {{admin-api-key}}
{
   "queryType":"semantic",
   "search":"hello world",
   "searchFields":"field_a, field_b",
   "vectorQueries": [
       {
           "kind":"vector",
           "vector": [1.0, 2.0, 3.0],
           "fields": "field_c, field_d"
       },
       {
           "kind":"vector",
           "vector": [4.0, 5.0, 6.0],
           "fields": "field_d, field_e"
       }
   ],
   "scoringProfile":"my_scoring_profile"
}

ちなみに、ハイブリッド+セマンティック検索だと@search.scoreと@search.rerankerScoreがどちらも返却されますが、@search.rerankerScoreの順で返ってきます。

@search.scoreでも検索方法で全然意味が違うので、別の検索方法でのスコアの比較は意味がないのと、
同じ検索方法内でもスコアの順序は意味がありますが、スコア差の大小みたいなのはあまり参考にならないと思いました。(特に画像のベクトル検索の場合)

ヘッドウォータース

Discussion