プログラミング
Pg_vectorsearch: pgvectorのIVFFlatおよびHNSWよりも高速なインデックス
Pg_vectorsearch: An index that is faster than pgvector's IVFFlat and HNSW (github.com)
要約
pg_vectorsearchは、PostgreSQL向けの高性能な近似最近傍(ANN)検索拡張機能です。PRISMインデックスは、最先端の量子化、ルーティング、パーティショニング技術をC言語で実装しており、pgvectorのIVFFlatやHNSWよりもクエリとインデックス構築の両方で大幅に高速であることを謳っています。既存のpgvectorテーブルとも互換性があり、シームレスに移行・併用が可能です。
全文翻訳
pg_vectorsearch PostgreSQL拡張機能、高性能な近似最近傍(ANN)検索用。ステータス:アルファ。テスト用であり、本番環境向けではありません。プレリリース間のアップグレードはできない可能性があります。拡張機能とそのインデックスを削除して再作成することを計画してください。既知の問題については変更履歴を参照してください。
PRISMインデックス(1億ベクトル以上) — IVFスタイル、階層ルーティング付き
理論的な誤差境界を持つRaBitQ量子化による2段階検索
SIMD最適化された距離計算(AVX2、AVX512、NEON)
動的更新 — 挿入、更新、削除。prism_rebalanceによる投稿リスト分割(メンテナンス参照)
pgvector互換 — 既存のvectorおよびhalfvecカラムをそのままインデックス化(既存のpgvectorテーブル参照)
PRISMインデックス
PRISM(Partitioned Routing Index for Similarity Matching)は、PostgreSQLネイティブのインデックスアクセス方式です。概念的にはpgvectorのIVFFlatに似ていますが、最先端の量子化、ルーティング、パーティショニング技術を中心に構築されています。高性能とPostgreSQLとのシームレスな統合のためにC言語で実装されています。その結果、クエリとインデックス構築の両方において、pgvectorのIVFFlatおよびHNSWよりも大幅に高速なインデックスが実現しました。実際、グラフベースのHNSWと比較して、同等のリコール率で1億ベクトルのデータセットにおいて、PRISMはメモリ使用量が4分の1のインスタンスでより高速です。このパフォーマンスを達成するために、PRISMは階層的なセントロイドツリーを使用してベクトルをクラスターにパーティション分割し、PostgreSQLのバッファキャッシュを利用してそのツリーをメモリ内でウォームに保ちます。ベクトルはRaBitQで量子化され、SIMD距離計算用に最適化されたページレイアウトを持つ投稿リストに格納されます。RaBitQエンコーディングは誤差境界を持つため、検索は近傍になり得ないベクトルを除外でき、テーブルに格納されているフルプレシジョンのベクトルに対して再ランク付けする必要があるベクトルがはるかに少なくなります。
クエリフロー:
1. セントロイドツリーをトラバースして最も近いクラスターを見つける(バッファキャッシュ)
2. 投稿リストをスキャンして候補を見つける(バッファキャッシュ、非同期I/O)
3. RaBitQ 2段階フィルタリング:推定 → 誤差境界 → 再ランク付け
4. ヒープからのフルプレシジョン再ランク付け
5. k個の最近傍を返す
詳細なアーキテクチャについては、docs/architecture.mdを参照してください。
使用方法
まず拡張機能をインストールします。ビルドを参照してください。PRISMインデックスの使用方法には2つの方法があります。ベクトルの保存場所に合わせて選択してください:
ネイティブ型。新規開始、またはpgvectorを使用しない場合。pg_vectorsearch独自のvec32(float32)またはvec16(float16)カラムにベクトルを格納します。他の拡張機能は不要です。
既存のpgvectorテーブル。すでにvectorまたはhalfvecカラムがありますか?pgvectorの隣にpg_vectorsearchをインストールし、それらのカラムにPRISMインデックスを構築します。テーブルとクエリは変更されません。
どちらのパスも同じインデックスを構築し、同じ演算子(<->, <#>, <=>)とチューニングノブを使用します。
ネイティブ型
CREATE EXTENSION pg_vectorsearch;
-- PLAINはベクトルをインラインで保持します。EXTERNAL(デフォルト)は約2kBを超える値をTOASTし、その後の再ランク付けはプランナーがコスト計算しない追加フェッチを発生させます。
CREATE TABLE items ( id serial PRIMARY KEY, embedding vec32(3) STORAGE PLAIN );
-- まずロードします。インデックスは行数からサイズが決定されます。
-- プランナーがインデックスを使用するには500行で十分です。
INSERT INTO items (embedding) SELECT ARRAY[i::real, (i % 7)::real, (i % 5)::real]::vec32 FROM generate_series(1, 1000) i;
-- 内積またはコサインについては、以下の演算子クラスを参照してください。
CREATE INDEX ON items USING prism (embedding vec32_l2_ops);
-- 0 = auto(約0.95リコール)。リコールを上げるには高く、速度を上げるには低くします。
SET prism.nprobe = 40;
SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;
vec32の代わりにvec16を使用すると、テーブル内のベクトルのスペースを半分にできます。対応するvec16_*演算子クラスを使用します。
既存のpgvectorテーブル
すでにpgvectorのvectorまたはhalfvecカラムを持つテーブルがある場合、それに直接PRISMインデックスを構築できます。テーブルやクエリの何も変更する必要はありません。vec32とvec16はpgvectorのvectorとhalfvecとバイナリ互換ですが、名前が異なるため、2つの拡張機能は同じスキーマ内でも並べてインストールできます。
-- 例が単独で実行できるように、既存のテーブルを含めます。
CREATE EXTENSION vector;
CREATE TABLE documents ( id bigserial PRIMARY KEY, body text, embedding vector(384) );
CREATE INDEX documents_embedding_hnsw ON documents USING hnsw (embedding vector_l2_ops);
-- pgvectorの隣にpg_vectorsearchをインストールし、既存のカラムにインデックスを構築します。
-- カラムは書き換えられたりコピーされたりしません。
CREATE EXTENSION pg_vectorsearch;
CREATE INDEX documents_embedding_prism ON documents USING prism (embedding vec32_l2_ops);
-- クエリは以前と同様に機能します。PRISMは通常高速なので、両方のインデックスが存在する場合、プランナーはHNSWインデックスよりもPRISMを優先するはずです。
-- EXPLAINで確認します:
-- EXPLAIN (COSTS OFF) SELECT id, body FROM documents ORDER BY embedding <-> (SELECT embedding FROM documents WHERE id = 42) LIMIT 10;
-- Limit
-- InitPlan 1
-- -> Index Scan using documents_pkey on documents documents_1
-- Index Cond: (id = 42)
-- -> Index Scan using documents_embedding_prism on documents
-- Order By: (embedding <-> (InitPlan 1).col1)
-- これで問題がなければ、HNSWインデックスを削除します。
DROP INDEX documents_embedding_hnsw;
HNSWインデックスを置き換える場合は、HNSWインデックスと同じ距離メトリックのPRISM演算子クラスを使用してください。
演算子クラス
距離メトリックとカラムタイプに対応する演算子クラスを選択してください。L2はデフォルトです。
距離 演算子 vec32 / vector vec16 / halfvec
L2 <-> vec32_l2_ops vec16_l2_ops
内積 <#> vec32_ip_ops vec16_ip_ops
コサイン <=> vec32_cosine_ops vec16_cosine_ops
HNSWインデックスを置き換える場合、pgvectorのvector_<metric>_opsはvec32_<metric>_opsに、halfvec_<metric>_opsはvec16_<metric>_opsに対応します。
チューニング
デフォルトは大規模ベンチマークからチューニングされており、ほとんどのデプロイメントではprism.nprobeのみを調整します。すべてのインデックスパラメータとGUC、それらのトレードオフ、および変更が意味をなす場合については、チューニングガイドを参照してください。
メンテナンス
挿入は、ベクトルがルーティングされる投稿リストに追加されるため、行が到着するとリストは成長し、独自に分割されることはありません。REINDEXに加えて、prism_rebalanceプロシージャは、大きすぎるリストをインプレースで分割します。その仕組みと現在の制限については、メンテナンスガイドを参照してください。
ビルド
要件:
PostgreSQL 18+(開発ヘッダー付き)
GNU C11コンパイラ(GCC 11+またはClang 14+)
Mesonビルドシステム
オプション:CBLAS、RaBitQエンコーディングを高速化するため。開発を参照してください。
# リリースビルド
meson setup builddir --buildtype=release
# ビルドしてPostgreSQLにインストール
meson install -C builddir
ビルドオプションについては、開発ガイドを参照してください。
ドキュメント
チューニング - インデックスパラメータ、GUC、トレードオフ、デフォルト
メンテナンス - リバランスと投稿リストの分割
アーキテクチャ - 高レベル設計とデータ構造
SIMD - SIMDビルドオプションと距離計算
開発 - ビルドオプション、テスト、CIスクリプト
参考文献
研究
RaBitQ - 理論的誤差境界を持つバイナリ量子化(SIGMOD 2024)
SPFresh - インクリメンタル更新のためのLIREプロトコル(SOSP 2023)
SPANN - 境界レプリケーションによる数十億規模のANN(NeurIPS 2021)
ScaNN for AlloyDB - 階層クラスタリング(Google)
関連プロジェクト
pgvector - PostgreSQL用のベクトル型と演算子
pgvectorscale - PostgreSQL用のDiskANNベースベクトルインデックス
ライセンス
PostgreSQLライセンス