このドキュメントでは、クエリのパフォーマンスを向上させ、レコードの検索精度を高めるためにインデックスをチューニングする方法について説明します。
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 |
database フラグは、スキャンされた候補の近傍をディスクではなくメモリ内でスコアリングまたはランク付けすることで、フィルタされたクエリのパフォーマンスを向上させるために使用されるキャッシュのサイズを指定します。デフォルト値は 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;
指標の一覧の詳細については、ベクトル インデックスの指標をご覧ください。