このドキュメントでは、インデックスをチューニングしてクエリ パフォーマンスを高速化し、再現率を向上させる方法を説明します。
ScaNN
インデックスをチューニングする
ScaNN インデックスは、木量子化ベースのインデックスを使用します。木量子化手法では、インデックスは量子化(ハッシュ化)関数とともに検索ツリーを学習します。クエリを実行すると、検索ツリーを使用して検索空間がプルーニングされ、量子化を使用してインデックス サイズが圧縮されます。このプルーニングにより、クエリベクトルとデータベース ベクトルの類似性(距離)のスコアリングが高速化されます。
高速な秒間クエリ数(QPS)と最近傍クエリでの高い再現率の両方を実現するには、データとクエリに最も適した方法で ScaNN
インデックスのツリーをパーティショニングする必要があります。
ScaNN
インデックスを作成する前に、次の操作を行います。
- データを含むテーブルがすでに作成されていることを確認します。
- インデックスの生成中に問題が発生しないように、
maintenance_work_mem
フラグとshared_buffers
フラグに設定する値がマシンのメモリの合計より小さいことを確認してください。
調整パラメータ
次のインデックス パラメータとデータベース フラグを組み合わせて使用することで、再現率と QPS の適切なバランスを見つけることができます。すべてのパラメータは、両方の ScaNN
インデックス タイプに適用されます。
チューニング パラメータ | 説明 | パラメータのタイプ。 |
---|---|---|
num_leaves |
このインデックスに適用するパーティションの数。インデックスの作成時に適用するパーティションの数は、インデックスのパフォーマンスに影響します。設定された数のベクトルのパーティションを増やすと、よりきめ細かいインデックスが作成され、再現率とクエリ パフォーマンスが向上します。ただし、インデックスの作成時間が長くなります。 3 レベルのツリーは 2 レベルのツリーよりも構築が速いため、3 レベルのツリー インデックスを作成するときに num_leaves_value を増やすと、パフォーマンスを向上させることができます。
|
インデックスの作成 |
quantizer |
K 平均法ツリーに使用する量子化ツールのタイプ。デフォルト値は SQ8 であり、クエリのパフォーマンスが向上します。より高い再現率を得るには、 FLAT に設定します。 |
インデックスの作成 |
enable_pca |
主成分分析(PCA)を有効にします。これは、可能な場合はエンベディングのサイズを自動的に縮小するために使用されるディメンションの削減手法です。このオプションはデフォルトで有効になっています。 再現率の低下が観察された場合は、 false に設定します。 |
インデックスの作成 |
scann.num_leaves_to_search |
データベース フラグは、再現率と QPS のトレードオフを制御します。デフォルト値は、num_leaves で設定された値の 1% です。設定値を大きくすると再現率は高まりますが、QPS は低下します。その逆も同様です。 |
クエリ ランタイム |
scann.max_top_neighbors_buffer_size |
データベース フラグは、スキャンされた近傍候補をディスクではなくメモリ内でスコアリングまたはランク付けすることで、フィルタされたクエリのパフォーマンスを向上させるために使用されるキャッシュのサイズを指定します。デフォルト値は 20000 です。設定値を大きくすると、フィルタされたクエリの QPS は向上しますが、メモリ使用量は増加します。その逆も同様です。 |
クエリ ランタイム |
scann.pre_reordering_num_neighbors |
データベース フラグを設定すると、最初の検索で候補のセットが特定された後の並べ替えステージで検討する近傍候補の数を指定できます。このパラメータは、クエリで返される近傍の数よりも大きい値に設定します。 値セットを大きくすると再現率は高くなりますが、QPS は低くなります。 |
クエリ ランタイム |
max_num_levels |
K 平均法クラスタリング ツリーの最大レベル数。
|
インデックスの作成 |
ScaNN
インデックスをチューニングする
2 レベルと 3 レベルの ScaNN
インデックスの次の例では、チューニング パラメータを設定する方法を示します。
2 レベル インデックス
SET LOCAL scann.num_leaves_to_search = 1;
SET LOCAL scann.pre_reordering_num_neighbors=50;
CREATE INDEX my-scann-index ON my-table
USING scann (vector_column cosine)
WITH (num_leaves = [power(1000000, 1/2)]);
3 レベル インデックス
SET LOCAL scann.num_leaves_to_search = 10;
SET LOCAL scann.pre_reordering_num_neighbors=50;
CREATE INDEX my-scann-index ON my-table
USING scann (vector_column cosine)
WITH (num_leaves = [power(1000000, 2/3)], max_num_levels = 2);
ScaNN
インデックスがすでに生成されているテーブルに対して挿入オペレーションまたは更新オペレーションが発生すると、学習済みツリーがインデックスを最適化する方法に影響します。テーブルの更新や挿入が頻繁に発生する場合は、再現率の精度を高めるために、既存の ScaNN
インデックスを定期的に再作成することをおすすめします。
インデックス指標をモニタリングすることで、インデックスの作成後に作成されたミューテーションの量を特定し、必要に応じてインデックスを再作成できます。各指標の詳細については、ベクトル インデックス指標をご覧ください。
チューニングのベスト プラクティス
使用する ScaNN
インデックスのタイプに応じて、インデックスのチューニングに関する推奨事項は異なります。このセクションでは、再現率と QPS の最適なバランスを得るための、インデックス パラメータの調整に関する推奨事項について説明します。
2 レベル ツリー インデックス
推奨事項を適用して、データセットに最適な num_leaves
と num_leaves_to_search
の値を見つけるには、次の手順に沿って操作します。
num_leaves
をインデックス対象テーブルの行数の平方根に設定して、ScaNN
インデックスを作成します。- 目標とする再現率の範囲(95% など)に達するまで、テストクエリを実行し、
scann.num_of_leaves_to_search
の値を増やします。クエリの分析の詳細については、クエリを分析するをご覧ください。 scann.num_leaves_to_search
とnum_leaves
の比率は、以降のステップで使用するのでメモしておきます。この比率は、目標の再現率を達成するために役立つデータセットの近似値を提供します。
高次元ベクトル(500 次元以上)を扱っていて、再現率を改善したい場合は、scann.pre_reordering_num_neighbors
の値をチューニングしてみてください。最初は、値を100 * sqrt(K)
に設定します。ここで、K
はクエリで設定した上限です。- クエリによって目標の再現率が達成された後、QPS が低すぎる場合は、次の操作を行います。
- インデックスを再作成し、次のガイダンスに従って
num_leaves
とscann.num_leaves_to_search
の値を増やします。num_leaves
を、行数の平方根に対するより大きな係数に設定します。たとえば、インデックスのnum_leaves
が行数の平方根に設定されている場合は、平方根の 2 倍に設定してみてください。値がすでに 2 倍になっている場合は、平方根の 3 倍に設定してみてください。- 必要に応じて
scann.num_leaves_to_search
を増やし、ステップ 3 でメモしたnum_leaves
との比率を維持します。 num_leaves
は、行数を 100 で除した値以下の値に設定します。
- テストクエリをもう一度実行します。テストクエリを実行しながら、
scann.num_leaves_to_search
を減らしてみて、高い再現率を維持しつつ QPS を高める値を見つけます。インデックスを再ビルドせずに、scann.num_leaves_to_search
の値を変更してみてください。
- インデックスを再作成し、次のガイダンスに従って
- QPS と再現率の範囲の両方が許容値に達するまで、手順 4 を繰り返します。
3 レベル ツリー インデックス
2 レベル ツリーの ScaNN
インデックスに関する推奨事項に加えて、次のガイダンスと手順を使用してインデックスをチューニングします。
max_num_levels
を 2 レベル ツリーの1
から 3 レベル ツリーの2
に増やすと、インデックスの作成時間が大幅に短縮されますが、再現率の精度は低下します。次の推奨事項を使用してmax_num_levels
を設定します。- ベクトルの行数が 1 億行を超える場合は、値を
2
に設定します。 - ベクトル行数が 1,000 万行未満の場合は、値を
1
に設定します。 - ベクトル行数が 1,000 万~1 億行の場合は、インデックスの作成時間と必要な再現率のバランスに基づいて、
1
または2
に設定します。
- ベクトルの行数が 1 億行を超える場合は、値を
推奨事項を適用して、num_leaves
インデックス パラメータと max_num_levels
インデックス パラメータの最適な値を見つける手順は、次のとおりです。
データセットに基づき、次の
num_leaves
とmax_num_levels
を組み合わせてScaNN
インデックスを作成します。- ベクトル行数が 1 億行を超える場合:
max_num_levels
を2
に、num_leaves
をpower(rows, ⅔)
に設定します。 - ベクトル行数が 1 億行未満の場合:
max_num_levels
を1
に、num_leaves
をsqrt(rows)
に設定します。 - ベクトル行数が 1,000 万~1 億行の場合: まず、
max_num_levels
を1
に、num_leaves
をsqrt(rows)
に設定します。
- ベクトル行数が 1 億行を超える場合:
テストクエリを実行します。クエリの分析の詳細については、クエリを分析するをご覧ください。
インデックスの作成時間が十分であれば、
max_num_levels
値を保持し、num_leaves
値をテストして、最適な再現率を実現できます。インデックスの作成時間が長すぎる場合は、次の操作を行います。
max_num_levels
の値が1
の場合、インデックスを削除します。max_num_levels
値を2
に設定してインデックスを再ビルドします。クエリを実行し、
num_leaves
値を調整して、再現率を最適化します。max_num_levels
値が2
の場合、インデックスを削除します。同じmax_num_levels
値でインデックスを再ビルドし、num_leaves
値をチューニングして、再現率を最適化します。
IVF
インデックスをチューニングする
lists
、ivf.probes
、quantizer
パラメータに設定した値をチューニングすると、アプリのパフォーマンスを最適化できます。
チューニング パラメータ | 説明 | パラメータのタイプ。 |
---|---|---|
lists |
インデックスの構築中に作成されたリストの数。この値の設定の開始点は、最大 100 万行の場合は (rows)/1000 、100 万行を超える場合は sqrt(rows) です。 |
インデックスの作成 |
quantizer |
K 平均法ツリーに使用する量子化ツールのタイプ。デフォルト値は SQ8 で、クエリのパフォーマンスが向上します。FLAT に設定すると、再現率が向上します。 |
インデックスの作成 |
ivf.probes |
検索時に探索する最近傍リストの数。この値の出発点は sqrt(lists) です。 |
クエリ ランタイム |
チューニング パラメータが設定された IVF
インデックスを示す次の例について考えてみましょう。
SET LOCAL ivf.probes = 10;
CREATE INDEX my-ivf-index ON my-table
USING ivf (vector_column cosine)
WITH (lists = 100, quantizer = 'SQ8');
IVFFlat
インデックスをチューニングする
lists
パラメータと ivfflat.probes
パラメータに設定した値を調整すると、アプリケーションのパフォーマンスを最適化できます。
チューニング パラメータ | 説明 | パラメータのタイプ。 |
---|---|---|
lists |
インデックスの構築中に作成されたリストの数。この値の設定の開始点は、最大 100 万行の場合は (rows)/1000 、100 万行を超える場合は sqrt(rows) です。 |
インデックスの作成 |
ivfflat.probes |
検索時に探索する最近傍リストの数。この値の出発点は sqrt(lists) です。 |
クエリ ランタイム |
IVFFlat
インデックスを作成する前に、データベースの max_parallel_maintenance_workers
フラグが、大規模なテーブルのインデックス作成を迅速化できる値に設定されていることを確認します。
チューニング パラメータが設定された IVFFlat
インデックスを示す次の例について考えてみましょう。
SET LOCAL ivfflat.probes = 10;
CREATE INDEX my-ivfflat-index ON my-table
USING ivfflat (vector_column cosine)
WITH (lists = 100);
HNSW
インデックスをチューニングする
m
、ef_construction
、hnsw.ef_search
パラメータに設定した値を調整すると、アプリケーションのパフォーマンスを最適化できます。
チューニング パラメータ | 説明 | パラメータのタイプ。 |
---|---|---|
m |
グラフ内のノードからの最大接続数。デフォルト値の 16 (デフォルト)から始めて、データセットのサイズに応じて値を大きくしてテストできます。 |
インデックスの作成 |
ef_construction |
グラフの構築中に維持される動的候補リストのサイズ。このリストでは、ノードの最近傍の現在の最良の候補が常に更新されます。この値は、m 値の 2 倍を超える値に設定します。例: 64 (デフォルト)。 |
インデックスの作成 |
ef_search |
検索時に使用される動的候補リストのサイズ。この値は最初は m または ef_construction に設定し、その後は再現率を監視しながら変更できます。デフォルト値は 40 です。 |
クエリ ランタイム |
チューニング パラメータが設定された hnsw
インデックスを示す次の例について考えてみましょう。
SET LOCAL hnsw.ef_search = 40;
CREATE INDEX my-hnsw-index ON my-table
USING hnsw (vector_column cosine)
WITH (m = 16, ef_construction = 200);
クエリを分析する
次の SQL クエリの例に示すように、EXPLAIN ANALYZE
コマンドを使用してクエリ分析情報を分析します。
EXPLAIN ANALYZE SELECT result-column FROM my-table
ORDER BY EMBEDDING_COLUMN ::vector
USING INDEX my-scann-index
<-> embedding('textembedding-gecko@003', 'What is a database?')
LIMIT 1;
レスポンスの例 QUERY PLAN
には、所要時間、スキャンまたは返された行数、使用されたリソースなどの情報が含まれます。
Limit (cost=0.42..15.27 rows=1 width=32) (actual time=0.106..0.132 rows=1 loops=1)
-> Index Scan using my-scann-index on my-table (cost=0.42..858027.93 rows=100000 width=32) (actual time=0.105..0.129 rows=1 loops=1)
Order By: (embedding_column <-> embedding('textgecko@003', 'What is a database?')::vector(768))
Limit value: 1
Planning Time: 0.354 ms
Execution Time: 0.141 ms
ベクトル インデックスの指標を表示する
ベクトル インデックスの指標を使用すると、ベクトル インデックスのパフォーマンスを確認して改善できる領域を特定し、必要に応じて指標に基づいてインデックスをチューニングできます。
すべてのベクトル インデックス指標を表示するには、pg_stat_ann_indexes
ビューを使用する次の SQL クエリを実行します。
SELECT * FROM pg_stat_ann_indexes;
指標の一覧については、ベクトル インデックスの指標をご覧ください。