PostgreSQL でベクトル検索をやりたい人に向けて、Timescale が pg_vectorsearch という拡張を GitHub で公開しました。いまの生成AI周りでは、埋め込みベクトルを使って近い意味の文書を探す仕組みが当たり前になりつつありますが、その土台をデータベース側でどう作るかはまだ模索が続いています。今回の拡張は、既存の pgvector と競合するというより、PostgreSQL での ANN 検索をさらに速く、しかも既存テーブルにも差し込みやすくしようという提案です。まだ alpha で、本番利用は想定していない点も含めて、かなり野心的な内容です。
pg_vectorsearch が掲げるものと、README が示している設計README によると、pg_vectorsearch は PostgreSQL 用の「high-performance vector search for PostgreSQL」をうたう拡張です。扱うのは ANN、つまり approximate nearest neighbor search で、正確な最近傍を毎回総当たりするのではなく、近そうな候補を素早く拾う方式です。状態は alpha で、テスト向け。本番用途ではなく、プレリリース間のアップグレードでは互換性が崩れて、拡張やインデックスを作り直す必要があるかもしれないと明記しています。
中核になっているのは PRISM index です。これは Partitioned Routing Index for Similarity Matching の略で、100M+ vectors を視野に入れた IVF 系の設計だと説明されています。pgvector の IVFFlat に考え方が似ている一方、階層化された centroid tree でベクトルをクラスタに分け、PostgreSQL の buffer cache を使ってその木をメモリ上に温かく保つ作りです。さらに、ベクトルは RaBitQ で量子化され、posting list に置かれます。RaBitQ は誤差境界を持つため、検索時に「この候補は絶対に近傍になりえない」と早めに排除でき、フル精度のベクトルで再評価する候補数を減らせる、というのが売りです。
README には検索の流れも載っています。まず centroid tree をたどって近いクラスタを探し、次に posting list を走査して候補を集め、RaBitQ の二段階フィルタリングで estimate、error bound、rerank を行います。その後、heap にあるフル精度の値で再ランキングして、最終的な k 件を返します。実装は C で、SIMD も AVX2、AVX512、NEON に対応するとしています。
使い方は大きく二通りです。ひとつは vec32 や vec16 を自前で使う方法で、まっさらな構成ならこちら。もうひとつは、既に pgvector の vector や halfvec を使っているテーブルに、そのまま PRISM index を追加する方法です。後者ではテーブルもクエリも変えずに済み、pg_vectorsearch を pgvector の隣に入れてインデックスだけ作ればよいとされています。オペレーターも <->、<#>、<=> が使えます。L2、inner product、cosine に対応した operator class も用意され、vec32_l2_ops や vec16_cosine_ops のように選びます。
README で特に目を引くのは、HNSW との比較です。Timescale は、PRISM は pgvector の IVFFlat よりかなり速く、グラフベースの HNSW と比べても、100-million-vector dataset で同等の recall なら、メモリが 4 分の 1 の環境でも速いと主張しています。調整項目としては prism.nprobe が中心で、デフォルトは大規模ベンチマークから決めたと書かれています。運用面では、挿入されたベクトルは対応する posting list の末尾に追加されるため、そのままだと list が成長し続けます。そこで prism_rebalance という手続きで oversized な list を分割できる、としています。ビルド要件は PostgreSQL 18+、開発ヘッダ、GNU C11 コンパイラ、Meson です。
このリポジトリでいちばん面白いのは、ゼロからの新規導入よりも、すでに pgvector を使っている人を強く意識している点だと思う。ベクトル検索の話はしばしば「新しいインデックスが速い」で終わりがちだが、実際の現場では「いまあるテーブルを壊さず入れ替えられるか」のほうが重要だ。README はそこをかなり丁寧に押さえていて、vector / halfvec に対してそのまま PRISM index を張れると説明している。これは、導入の心理的ハードルを下げる作戦としてかなり効く。
ただし、そこには別の読み方もある。pgvector の既存資産を取り込めるということは、裏を返せば pg_vectorsearch 単体でエコシステムを作るより、まずは乗り換えや併存をしやすくして布石を打っている、ということでもあるはずだ。ベクトルDBや検索基盤は、性能だけでは勝てない。移行コストをどこまで下げられるかが勝負になる。Timescale はそこをよく分かっているように見える。私は、この「既存の pgvector に寄り添う姿勢」が、技術的な面白さ以上に戦略的だと思う。
README の比較で目立つのは、PRISM は IVFFlat だけでなく HNSW よりも速い、とかなり強く打ち出しているところだ。しかも単に速いだけではなく、同じ recall なら 100-million-vector dataset で、メモリが 4 分の 1 のインスタンスでも HNSW より速いと書く。これはかなり攻めた言い方で、読んだ側はつい性能の数字に目が行く。ただ、実運用ではベンチマーク条件の違いがそのまま結論を左右するので、ここは慎重に見たい。
とはいえ、PRISM が RaBitQ の誤差境界を使って rerank 候補を削る設計は、理屈としては筋が通っている。HNSW はグラフ探索の強さがある一方、メモリ使用量や構築コストが気になるケースも多い。そこに対して、階層 centroid tree と posting list、さらに SIMD 最適化で勝負するのは、PostgreSQL 内で完結する検索としてはかなり現実的な方向だと思う。私は、この拡張は「HNSW を置き換える万能解」ではなく、「HNSW が重すぎる場面で、より扱いやすい選択肢を作る」動きとして見るのが自然ではないかと思う。
README の冒頭で、alpha であり本番向けではないと最初に断っているのは好感が持てる。ベクトル検索の世界では、性能の見栄えがよいと、どうしても「もう使えるのでは」と受け取られやすい。でも、インデックス形式の拡張は、後からの互換性や再構築コストが本当に厄介だ。Timescale はその危うさを隠していない。むしろ、drop and recreate の可能性まで明示して、使う側に慎重さを求めている。
これは少し地味だが重要な態度だと思う。プロダクトとしては派手な速度比較のほうが目に入りやすいが、実際に価値を決めるのは「いつ壊れるか」「どれだけ戻せるか」だ。prism_rebalance のようなメンテナンス手段を用意しているのも、その延長にある。検索インデックスは作って終わりではないし、データが増えれば手入れがいる。そういう運用の現実を、README がかなりはっきり示しているのは評価したい。逆に言えば、この拡張を試す人は、速度だけでなく保守の流れまで含めて検証する必要がある。
pg_vectorsearch は、単なる新機能の追加というより、PostgreSQL をベクトル検索の実行基盤として伸ばそうとする流れの一部に見える。pgvector が先に市場を作り、pgvectorscale のような別案も出てきたなかで、Timescale は「自前の高性能インデックス」で差別化しにきた。ここで重要なのは、みんなが別々の方向を向いているようで、実際には同じ問いに答えていることだ。つまり、ベクトルをどう保存し、どう更新し、どう速く探すか、を PostgreSQL の中でどう成立させるか。
私の見方では、この流れはまだ始まったばかりだ。生成AI の現場では、検索精度だけでなく、既存の SQL、権限管理、バックアップ、運用監視と一緒に扱えることが強く求められる。だからこそ、ベクトル検索がデータベースに寄っていくのは自然だし、Timescale のようにインデックス層から攻める試みは今後も増えるはずだと思う。一方で、pg_vectorsearch が広く使われるかどうかは、ベンチマークの華やかさより、alpha からどれだけ堅く育つかにかかっている。そこがこのプロジェクトの本当の勝負どころだろう。
参考: GitHub - timescale/pg_vectorsearch: High-performance vector search for PostgreSQL