pg_vectorsearch:TimescaleのPRISMインデックスがpgvectorのIVFFlatおよびHNSWより高速なベクトル検索を主張

Timescaleは、新しい近似最近傍インデックスであるPRISMを備えたオープンソースのPostgreSQL拡張機能であるpg_vectorsearchをリリースしました。このプロジェクトは、クエリとインデックス構築の両方においてpgvectorのIVFFlatおよびHNSWよりも大幅に高速であると主張しています。この拡張機能は明示的にアルファ版としてラベル付けされており、本番環境ではなくテストを目的としていますが、HNSWのグラフトラバーサルではなく、パーティショニングと圧縮という明確なアーキテクチャ上の選択を導入しています。

pg_vectorsearchとは

pg_vectorsearchは、TimescaleがPostgreSQLライセンスの下で公開した、高性能な近似最近傍(ANN)検索のためのPostgreSQL拡張機能です。その目玉となるコンポーネントは、PRISM(Partitioned Routing Index for Similarity Matching)であり、C言語で実装されたPostgreSQLネイティブのインデックスアクセスメソッドです。

この拡張機能の説明されている機能セットは次のとおりです。

  • PRISMインデックス:1億以上のベクトルに対応。IVFスタイルで、階層的ルーティングを備えています。
  • RaBitQ量子化:2段階検索のための理論的な誤差範囲を備えています。
  • SIMD最適化された距離計算(AVX2、AVX512、NEON)
  • 動的更新:挿入、更新、削除に対応し、prism_rebalanceによるポスティングリストの分割を備えています。
  • pgvector互換性:既存のvector列とhalfvec列をそのままインデックス化できます。

リポジトリには大きなステータス警告が記載されています:「ステータス:アルファ版。テスト用であり、本番用ではありません。プレリリース間のアップグレードはできない場合があります。拡張機能とそのインデックスを削除して再作成することを計画してください。」

PRISMインデックスの仕組み

PRISMは概念的にはpgvectorのIVFFlatに似ていますが、IVFFlatのフラットなセントロイドリストを階層的なセントロイドツリーに置き換え、量子化ベースのフィルタリングを追加しています。Timescaleは結果を「クエリとインデックス構築の両方においてpgvectorのIVFFlatおよびHNSWよりも大幅に高速なインデックス」と説明しています。

このインデックスは、階層的なセントロイドツリーを使用してベクトルをクラスタに分割し、PostgreSQLのバッファキャッシュに依存してそのツリーをメモリ内でウォームに保ちます。ベクトルはRaBitQ量子化され、SIMD距離計算用に最適化されたページレイアウトでポスティングリストに格納されます。RaBitQエンコーディングには誤差範囲が含まれており、検索で最近傍になり得ないベクトルを除外できるため、テーブルに格納されている完全精度の値に対して再ランク付けする必要があるベクトルを大幅に減らせます。

ドキュメントに記載されているクエリフローは次のとおりです。

クエリフロー:
1. セントロイドツリーをトラバースして最近傍クラスタを見つける(バッファキャッシュ)
2. ポスティングリストをスキャンして候補を見つける(バッファキャッシュ、非同期I/O)
3. RaBitQの2段階フィルタリング:推定→誤差範囲→再ランク付け
4. ヒープからの完全精度での再ランク付け
5. k最近傍を返す

このプロジェクトは、RaBitQ(SIGMOD 2024)、SPFreshのLIREプロトコル(SOSP 2023)、SPANN(NeurIPS 2021)、およびGoogleのAlloyDB向けScaNNホワイトペーパーを研究基盤として引用しています。

パフォーマンスの主張

Timescaleの付随する発表ブログ投稿では、具体的なベンチマークの主張がなされています。この拡張機能の作者であるjascha_eng氏は、Hacker Newsでその投稿の要約を引用しました。

TLDR:ベクトル検索を劇的に高速化し、コスト効率を高める新しいオープンソースのPostgreSQL拡張機能であるpg_vectorsearchを発表します。その新しいPRISMインデックスは、HNSWのグラフベースのアプローチの代わりにパーティショニングと圧縮を使用しており、メモリのごく一部でより高速なクエリと大幅に高速なインデックス構築を実現します。1億ベクトルで、PRISMはHNSWの4分の1のメモリを搭載したマシンで6ミリ秒のクエリレイテンシを達成し、インデックス構築は20倍以上高速でした。

GitHubのREADMEには、「グラフベースのHNSWと比較して、PRISMは1億ベクトルのデータセットで同等の再現率で高速であり、メモリが4分の1のインスタンス上で実行されます」と記載されています。

Hacker Newsのコメンテーターであるesafak氏は、それらの数値の提示方法に反対し、ベンチマークを先頭に出すべきだと主張しました:「高速なら、ベンチマークを先頭に出すべきではないですか? QPSと精度/再現率を、お願いします。」 リポジトリ自体には、スクレイピングされたコンテンツに完全なQPS対再現率テーブルは再現されておらず、発表投稿とチューニングガイドへのリンクが含まれています。

インストールと使用法

pg_vectorsearchには、開発ヘッダーを備えたPostgreSQL 18以上、GNU C11コンパイラ(GCC 11+またはClang 14+)、およびMesonビルドシステムが必要です。CBLASはオプションですが、RaBitQエンコーディングを高速化します。

# リリースビルド
meson setup builddir --buildtype=release

# PostgreSQLにビルドしてインストール
meson install -C builddir

使用法には2つのパスがあり、両方とも同じインデックスを構築し、同じ演算子(<->、<#>、<=>)とチューニングノブを使用します。

ネイティブ型

新しく始める場合、またはpgvectorを使用しない場合は、ベクトルをpg_vectorsearch独自のvec32(float32)またはvec16(float16)列に格納します。他の拡張機能は必要ありません。

CREATE EXTENSION pg_vectorsearch;

-- PLAINはベクトルをインラインで保持します。EXTERNAL(デフォルト)は約2 kBを超える値をトーストし、
-- 再ランク付けはプランナーがコスト計算しない余分なフェッチを支払います。
CREATE TABLE items (
    id serial PRIMARY KEY,
    embedding vec32(3) STORAGE PLAIN
);

-- 最初にロードします。インデックスはCREATE INDEX時の行数からサイズ設定されます。
-- プランナーがインデックスを使用するには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 = 自動(約0.95再現率)。再現率を上げるには増やし、速度を上げるには減らします。
SET prism.nprobe = 40;

SELECT * FROM items
ORDER BY embedding <-> '[3,1,2]'
LIMIT 5;

既存のpgvectorテーブル

pgvectorのvector列またはhalfvec列を持つテーブルがすでにある場合、テーブルやクエリを変更せずに、その上にPRISMインデックスを直接構築できます。vec32とvec16はpgvectorのvectorおよびhalfvecとバイナリ互換ですが、名前が異なるため、両方の拡張機能を同じスキーマでもサイドバイサイドでインストールできます。

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);

-- pg_vectorsearchをpgvectorの隣にインストールし、既存の列にインデックスを構築します。
-- 列は書き換えられたりコピーされたりしません。
CREATE EXTENSION pg_vectorsearch;

CREATE INDEX documents_embedding_prism
    ON documents USING prism (embedding vec32_l2_ops);

READMEは、PRISMは通常高速であるため、両方が存在する間はプランナーがHNSWインデックスよりもPRISMを優先するはずであり、古いインデックスを削除する前にEXPLAINで確認することを推奨しています。

演算子クラス

距離メトリックと列タイプに合わせて演算子クラスを選択します。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のみを調整すると記載されています。prism.nprobe = 0を設定すると、約0.95の再現率を目標とする自動値が選択されます。

メンテナンスについて、READMEは、挿入はベクトルがルーティングされるポスティングリストに追加されるため、行が到着するとリストが大きくなり、それ自体では分割されないと説明しています。REINDEXに加えて、prism_rebalanceプロシージャがサイズの大きいリストをその場で分割します。

コミュニティによって提起された導入の制約

Hacker Newsのコメンテーターであるdevy氏は、既存のpgvector HNSWインデックスを置き換えることを検討している人にとっての3つの実用的な障害を列挙しました。

  • pg_vectorsearchは、PRISMと呼ばれる量子化されたIVFインデックスを使用します。PRISMはベクトルの次元を1968に制限しています。以前のHNSWインデックスがそれ以上の次元を持つ場合、あなたはお手上げです(少なくとも彼らがそれを修正するまでは)。
  • pg_vectorsearchにはPostgresバージョン18以上が必要です。それ未満のPGバージョンを実行している場合は、まずデータベースを移行する必要があります。多くのレガシーなPG本番環境はPG 14または15にかなり遅れており、これを試すだけでも移行コストが法外に高いです。
  • pg_vectorsearchは昨日リリースされたばかりで、明らかにアルファ版です。Timescale以外の本番環境でバトルテストされていません。また、非常に新しいため、Azureの許可された拡張機能リストや他のHyperscaleのマネージドPGインスタンスの許可された拡張機能リストには含まれていません。

その3番目の点はswe_dima氏によって繰り返されました:「残念ながら、クラウドプロバイダーがマネージドPostgresでそれを提供しなければ、多くの人がそれを使用することはできません...」

フィルタリング、量子化、および未解決の質問

複数のコメンテーターが、READMEが宣伝していない機能を提起しました。Rapzid氏は、インデックスがフィルタリングをサポートしているかどうか尋ね、ドキュメントからポストフィルタリングのみであると結論付けました:「フィルタリングをサポートしていますか? 編集:ポストフィルタリングのみ。これらのインデックスを使用してテナント/ユーザー/権限スコープを効率的に実装する方法がわかりません。」

potomushto氏は、バイナリ量子化とハミング距離サポートの欠如に言及しました:「興味深い、ビット精度とハンマー距離演算子のサポートについての言及が見当たりません。それははるかに高速でストレージ効率が良いはずです。」

他の人々は、プロジェクトが公開していない比較を求めました。thomasahle氏はPRISMがRoarグラフとどう比較するか尋ね、dmix氏はParadeDBのpg_searchとどう比較するか尋ね、jakobedding氏はpgvectorscaleとどう比較するか尋ねました。arunmu氏はさらに進んで、戦略に疑問を呈しました:「これらの人々は、現在メンテナンスされていないように見えるpgvectorscaleも書きませんでしたか? pgvectorscaleに追加または改善するのではなく、なぜ新しいインデックスなのですか?」

競合コンテキスト

コメンテーターのEgregiousCube氏は、本番環境でVectorChordを実行していると報告し、このリリースをメモリ効率の高いインデックスへの広範なトレンドの一部として位置付けました:「現在VectorChordを実行していますが、とても気に入っています。高速なバッキングディスクを使用すると、Postgresのコストが半分になりました。低RAMベクトルインデックスツールでの競争が見られて興奮しています。RAMageddonは、最新のNVMeドライブの速さを活用する方法をさらに見つけるためのインセンティブを生み出しているようです!」

ilumanty氏は反対の願いを表明しました。同じクラスのインデックスがPostgreSQLの外に存在することです:「SQLiteがこれに沿ったものをサポートしていたら、とても素晴らしいでしょう。」

より軽い観察がalexpadula氏からあり、彼はリポジトリのPRISMロゴ画像に言及しました:「PRISMのダークサイド! リポジトリの画像は100%ピンク・フロイドの『狂気の扉』(Dark Side of The Moon)に触発されています。」

持ち帰るべきこと

pg_vectorsearchは、PostgreSQL 18+拡張機能であり、HNSWのグラフ構造を階層的なIVFスタイルのパーティションツリーと、エラーバウンドフィルタリングを備えたRaBitQ量子化に置き換えます。Timescale自身の数値は、HNSWの4分の1のメモリを搭載したマシンで1億ベクトルで6ミリ秒のクエリレイテンシ、インデックス構築は20倍以上高速であると主張しています。それに対して、この拡張機能はアルファ版であり、PostgreSQL 18が必要で、マネージドクラウドの許可リストにはまだなく、コミュニティの報告によると1968次元で上限があり、フィルタリングされた検索ではなくポストフィルタリングをサポートしています。このプロジェクトは列レベルでpgvector互換であるため、テーブルやクエリを書き換えることなく、既存のHNSWインデックスと一緒に評価できます。

Sources