ベクトル検索のベスト プラクティス

このドキュメントでは、Spanner でベクトル検索のパフォーマンスを最適化するための推奨事項について説明します。

Spanner の基本を理解する

効果的な Spanner ベクトル検索のパフォーマンス テストを実施するには、Spanner の基本を理解する必要があります。たとえば、キャッシュにより、同じクエリをすぐに再実行すると高速になることがあります。主にウォームデータを使用するアプリケーションでパフォーマンスをテストするには、まずウォームアップ読み取りを実行します。

次のガイドをご覧ください。

Spanner は、 データベース分割に基づいてクエリを並列処理します。持続的な本番環境クエリ負荷でテストすると、 負荷ベースの分割 が可能になり、 並列処理の増加によってクエリのパフォーマンスが向上します。今後の負荷に対する並列処理を増やすには、特に KNN の場合は、データベースの事前分割を検討してください。

ベクトル検索のベスト プラクティス

このドキュメントでは、ベクトル検索のベスト プラクティスについて説明します。

エンベディング列にアノテーションを付ける

エンベディング列に vector_lengthアノテーションを付けます。 このアノテーションにより、 K 最近傍(KNN)検索のパフォーマンスを最適化できます。また、 近似最近傍(ANN) 検索の前提条件となります。

上位 k クエリを使用する

最近傍を見つけるには、LIMIT を使用して ORDER BY 句を使用します。上位 k クエリは、ベクトル検索用に高度に最適化されています。WHERE 句で距離のしきい値でフィルタリングしないでください。

たとえば、次のような方法はおすすめしません。

SELECT d.DocId
FROM Documents AS d
WHERE COSINE_DISTANCE(d.DocEmbedding, @vector) < 1;

代わりに、次のようにします。

SELECT d.DocId
FROM Documents AS d
ORDER BY COSINE_DISTANCE(d.DocEmbedding, @vector)
LIMIT 10;

上位 k クエリを使用すると、距離のしきい値の調整が不要になるため、よりシンプルになります。また、ベクトル検索に特化したパフォーマンスの最適化も可能になります。

LIMIT 句に SQL リテラルを使用する

上位 k の上限が固定されている場合は、パラメータではなく SQL リテラルを使用します。たとえば、LIMIT @limit ではなく LIMIT 10 を使用します。これにより、 Spanner クエリ オプティマイザー は、最適な クエリ実行プランを選択するための詳細情報を取得できます。

バッチ指向型スキャンを使用する

ベクトル検索クエリはスキャンが重くなります。KNN クエリの場合は、 バッチ指向型スキャンの使用を検討してください。 scan_method=batch クエリヒントを使用してください。 これは、ANN クエリのデフォルトのスキャン方法です。

小規模なデータセットに KNN を使用する

レイテンシ バジェットに KNN で十分な場合は、ベクトル インデックスを作成しないでください。KNN はより正確で、インデックスの作成とメンテナンスのコストを回避できます。また、フィルタリング後の入力行数が少ない場合は、ANN よりもパフォーマンスが向上します。

セカンダリ インデックスを使用してフィルタされた KNN を高速化する

フィルタされた KNN クエリのパフォーマンスを向上させるには、フィルタリング列に セカンダリ インデックスを作成します。 たとえば、次のクエリについて考えてみます。

SELECT d.DocId
FROM Documents AS d
WHERE Category = 'toy'
ORDER BY COSINE_DISTANCE(d.DocEmbedding, @vector)
LIMIT 10;

カテゴリあたりのドキュメント数が数万件未満で、アプリケーションが 100 ミリ秒のクエリ レイテンシを受け入れられる場合は、Category 列にセカンダリ インデックスを作成します。インデックスに DocEmbedding 列を保存します。

CREATE INDEX ON Documents(Category) STORING (DocEmbedding);

このインデックス作成により、フィルタされたクエリを高速化できます。

大規模なデータセットに ANN を使用する

フィルタの評価後に多くの行がある場合は、ベクトル インデックスを作成して ANN 検索を使用します。ANN を使用したフィルタリングを高速化するには、いくつかの方法があります。

  • フィルタリング列を保存する: ベクトル検索の走査中にフィルタリングを有効にするには、フィルタリング列をベクトル インデックスに保存します。これにより、不適格な行を早い段階で削除できます。

    CREATE VECTOR INDEX ON Documents(DocEmbedding) STORING(Category);
    
  • キー フィルタリング列: 多くの結果を削除する選択性の高い列のフィルタリングを高速化するには、これらの列をベクトル インデックスに追加のキー列として整理します。これらの追加キーに完全一致(= 演算子を使用)を指定するクエリが最も高速化されます。これらの追加キーに IN 句を使用しても、同じレベルの高速化は実現できません。

    CREATE VECTOR INDEX ON Documents(DocEmbedding, Category);
    
  • 大きな列を保存したり、キーとして使用したりしない: これを行うと、エンベディングのデータブロックが希薄になり、読み取り効率が低下する可能性があります。代わりに、インデックスでハッシュ列を使用し、元の大きな列を上位 k の後フィルタとして使用することを検討してください。

  • フィルタされた(部分的な)ベクトル インデックスを作成する:データセットのサブセットのみをクエリし、フィルタリング条件でそのサブセットを定義する場合( Category = "Tech"など)、フィルタされたベクトル インデックスまたは部分的なベクトル インデックスを作成します。