ハイブリッド全文検索とベクトル検索のパターン

このページでは、Spanner で全文検索とベクトル検索のハイブリッド検索を行う方法について説明します。ハイブリッド検索では、キーワード マッチング(全文検索、FTS)の精度とセマンティック マッチング(ベクトル検索)の再現率を組み合わせて、関連性の高い検索結果を生成します。

Spanner は、次のハイブリッド検索パターンをサポートしています。これらは、次の 3 つのメインカテゴリに分類されます。

カテゴリ 説明 主要目標
Fusion Fusion は、キーワード検索とベクトル検索を使用してドキュメントを個別に取得してランク付けし、結果を結合(融合)します。 複数のスコアリング シグナルを組み合わせて、最大の再現率と関連性を実現します。
フィルタ適用 キーワードは検索スペースをフィルタまたは絞り込みます。 セマンティック関連性を活用しながら、キーワードのマッチングが要件であるようにします。
ML の再ランキング ML モデルは、候補の初期セットを絞り込んで、最終的なより正確なランキングを作成します。 最終的な結果の小さなセットで可能な限り高い精度を実現します。

融合検索では、同じデータコーパスで FTS とベクトル検索を個別に実行します。次に、結果を統合して、単一の統一された関連性の高いランキング リストを作成します。

クライアント側で独立したクエリを実行できますが、Spanner のハイブリッド検索には次の利点があります。

  • サーバーで並列リクエストと結果のマージを管理することで、アプリケーション ロジックを簡素化します。
  • 大規模な中間結果セットが生成された場合にクライアントに転送することを回避します。

SQL を使用して、Spanner で融合方法を作成できます。このセクションでは、相互ランク融合相対スコア融合の例を示します。ただし、さまざまなフュージョン戦略を評価して、アプリケーションの要件に最適な戦略を決定することをおすすめします。

ランクベースの融合

異なる検索方法(FTS スコアやベクトル距離など)の関連性スコアが異なる空間で測定されるため、比較や正規化が困難な場合は、ランクベースの融合を使用します。このメソッドは、各リトリーバーの各ドキュメントのランク位置を使用して、最終的なスコアとランキングを生成します。

Reciprocal Rank Fusion(RRF)は、ランクベースの融合関数です。ドキュメントの RRF スコアは、複数のリトリーバーのランクの逆数の合計であり、次のように計算されます。

\[ score\ (d\epsilon D)\ =\ \sum\limits_{r\epsilon R}^{}(1\ /\ (\ 𝑘\ +\ ran{k}_{r}\ (𝑑)\ )\ )\ \]

ここで

  • d はドキュメントです。
  • R はリトリーバー(FTS とベクトル検索)のセットです。
  • k は、ランクが非常に高いドキュメントの影響を緩和するために使用される定数です(通常は 60 に設定されます)。
  • w は、リトリーバー r のドキュメントのランクです。

Spanner クエリで RRF を実装する

ベクトル指標(APPROX_DOT_PRODUCT など)とテキスト検索スコア(SCORE_NGRAMS など)は、互換性のないスケールで動作します。この問題を解決するため、次の例では RRF を実装して、生スコアではなくランク位置に基づいてデータを正規化しています。

このクエリでは、UNNEST(ARRAY(...) WITH OFFSET を使用して、各メソッドの上位 100 件の候補にランクを割り当てます。次に、これらのランキングの逆数を使用して標準化されたスコアを計算し、結果を集計して上位 5 件の一致を返します。

SELECT SUM(1 / (60 + rank)) AS rrf_score, key
FROM (
  (
    SELECT rank, x AS key
    FROM UNNEST(ARRAY(
      SELECT key
      FROM hybrid_search
      WHERE embedding IS NOT NULL
      ORDER BY APPROX_DOT_PRODUCT(@vector, embedding,
        OPTIONS => JSON '{"num_leaves_to_search": 50}') DESC
      LIMIT 100)) AS x WITH OFFSET AS rank
  )
  UNION ALL
  (
    SELECT rank, x AS key
    FROM UNNEST(ARRAY(
      SELECT key
      FROM hybrid_search
      WHERE SEARCH_NGRAMS(text_tokens_ngrams, 'foo')
      ORDER BY SCORE_NGRAMS(text_tokens_ngrams, 'foo') DESC
      LIMIT 100)) AS x WITH OFFSET AS rank
  )
)
GROUP BY key
ORDER BY rrf_score DESC
LIMIT 5;

スコアベースの融合

スコアベースの融合は、さまざまな方法で得られた関連性スコアを比較できる場合や、正規化できる場合に有効です。これにより、各方法の実際の関連性の重みを組み込んだ、より正確なランキングが可能になる可能性があります。

相対スコア融合(RSF)は、スコアベースのメソッドであり、通常は、MIN() 関数と MAX() 関数を使用して、各メソッド内の最高スコアと最低スコアを基準に、さまざまなメソッドのスコアを正規化します。一連のリトリーバーによって取得されたドキュメントの RSF スコアは、次のように計算されます。

\[ score(d\epsilon D)\ =\ \sum\limits_{r\epsilon R}^{}({w}_{r}*(scor{e}_{r}(d)\ -\ mi{n}_{r})\ /\ (ma{x}_{r\ }-mi{n}_{r})\ ) \]

ここで

  • d はドキュメントです。
  • R はリトリーバー(FTS とベクトル検索)のセットです。
  • w は、特定のリトリーバーに割り当てられた重みです。

Spanner クエリで RSF を実装する

RSF を実装するには、ベクトルと FTS のスコアを共通のスケールに正規化する必要があります。次の例では、個別の WITH 句で最小スコアと最大スコアを計算して、正規化係数を導出します。次に、FULL OUTER JOIN を使用して結果を結合し、近似最近傍(ANN)検索(cosine_distance から変換)と FTS の正規化されたスコアを合計します。

WITH ann AS (
  SELECT key, APPROX_COSINE_DISTANCE(@vector, embedding,
    OPTIONS => JSON '{"num_leaves_to_search": 50}') AS cosine_distance,
  FROM hybrid_search
  WHERE embedding IS NOT NULL
  ORDER BY cosine_distance
  LIMIT 100
),
fts AS (
  SELECT key, SCORE_NGRAMS(text_tokens_ngrams, 'Green') AS score,
  FROM hybrid_search
    WHERE SEARCH_NGRAMS(text_tokens_ngrams, 'Green')
    ORDER BY score DESC
    LIMIT 100
),
ann_min AS (
  SELECT MIN(1 - cosine_distance) AS min
  FROM ann
),
ann_max AS (
  SELECT MAX(1 - cosine_distance) AS max
  FROM ann
),
fts_min AS (
  SELECT MIN(score) AS min
  FROM fts
),
fts_max AS (
  SELECT MAX(score) AS max
  FROM fts
)
SELECT IFNULL(ann.key, fts.key),
       IFNULL(((1 - ann.cosine_distance) - ann_min.min) /
               (ann_max.max - ann_min.min), 0) +
       IFNULL((fts.score - fts_min.min) /
               (fts_max.max - fts_min.min), 0) AS score
FROM ann
FULL OUTER JOIN fts
ON ann.key = fts.key
CROSS JOIN ann_min
CROSS JOIN ann_max
CROSS JOIN fts_min
CROSS JOIN fts_max
ORDER BY score DESC
LIMIT 5;

フィルタされた検索では、FTS を使用して、k 近傍法(KNN)ベクトル検索で考慮されるドキュメントのセットを削減するフィルタを作成します。必要に応じて、事前ソートを使用して結果セットのサイズを制限できます。

このセクションの検索例では、次の手順でベクトル検索空間をキーワードに一致するデータのサブセットに絞り込みます。

  • SEARCH (text_tokens, 'Green') を使用して、text_tokens 列にテキスト Green が含まれている行を検索します。上位 1,000 行は、検索インデックスで定義された並べ替え順序で返されます。
  • ベクトル関数 DOT_PRODUCT(@vector, embedding) を使用して、クエリベクトル(@vector)と保存されたドキュメント ベクトル(エンベディング)の類似度を計算します。次に、結果を並べ替えて、最終的な上位 10 件の一致を返します。
SELECT key
FROM (
  SELECT key, embedding
  FROM hybrid_search
  WHERE SEARCH (text_tokens, 'Green')
  ORDER BY presort
  LIMIT 1000)
ORDER BY DOT_PRODUCT(@vector, embedding) DESC
LIMIT 10;

ML の再ランキング

ML ベースの再ランキングは、計算負荷が高いものの、精度が高いアプローチです。FTS、ベクトル検索、またはそれらの両方の組み合わせによって絞り込まれた小さな候補セットに、ML モデルを適用します。Spanner Vertex AI インテグレーションの詳細については、Spanner Vertex AI インテグレーションの概要をご覧ください。

Spanner の ML.PREDICT 関数とデプロイされた Vertex AI モデルを使用して、ML の再ランキングを統合できます。

ML ベースの再ランキングを実装する

  1. リランカー モデルHuggingFace のモデルなど)を Vertex AI エンドポイントにデプロイします。
  2. Vertex AI エンドポイントを参照する Spanner MODEL オブジェクトを作成します。たとえば、次の Reranker モデルの例では、

    • text ARRAY<string(max)> はドキュメントです。
    • text_pair ARRAY<string(max)> は、例のクエリテキストです。
    • score は、ML モデルによって割り当てられた、テキストの入力ペアの関連性スコアです。
    CREATE MODEL Reranker
    INPUT (text ARRAY<string(max)>, text_pair ARRAY<string(max)>)
    OUTPUT (score FLOAT32)
    REMOTE
    OPTIONS (
    endpoint = '...'
    );
    
  3. サブクエリを使用して最初の候補(ANN 検索の上位 100 件の結果など)を取得し、ML.PREDICT に渡します。この関数は、最終的な順序付けのための新しいスコア列を返します。

    SELECT key
    FROM ML.PREDICT(
        MODEL Reranker, (
          SELECT key, text, "gift for 8-year-old" AS text_pair
          FROM hybrid_search
          WHERE embedding IS NOT NULL
          ORDER BY APPROX_DOT_PRODUCT(@vector, embedding, options=>JSON '{"num_leaves_to_search": 50}') DESC
          LIMIT 100)
    )
    ORDER BY score DESC
    LIMIT 3;
    

次のステップ