中級 11 分Stack

pgvector : ベクトル検索 PostgreSQL

端的な回答

pgvectorはPostgreSQLのオープンソース拡張機能で、制約の少ないPostgreSQLライセンスで提供されています。すでに管理しているデータベースにベクトルの保存と検索機能を追加し、最大2,000次元(半精度では4,000次元)の列にインデックスを作成できます。数十万個のチャンクからなるローカルのコーパスでは、運用するサービスを一つ減らせるうえ、SQLフィルターが機能し、リレーショナルデータとの同期を維持する必要もありません。

pgvectorはPostgreSQLの拡張機能で、すでに管理しているデータベースにベクトルの保存と検索の機能を追加します。ほとんどのローカル文書検索プロジェクトでは、稼働させるサービスと管理するバックアップをそれぞれ1つ減らせます。また、アクセス権による絞り込みも含め、SQLフィルターがきちんと機能します。このプロジェクトはPostgreSQLライセンスのもとで保守され、GitHubでホストされています。2026年9月末時点でスター数は23,000を超え、バージョンは0.8.6で、PostgreSQL 13以降に対応していました。

著者 Mohamed Meguedmi·更新 2026-09-28·Windows・macOS・Linuxでテスト済み

#採用する理由:サービスを追加せずに済む

ローカルの文書処理システムでは、すでにモデルサーバー、エンコーディング処理、文書ストレージが動いています。専用のベクトルデータベースを追加すると、コンテナ、ポート、バックアップがそれぞれ1つずつ増えます。さらに、文書を削除したときにリレーショナルデータとの同期がずれる可能性のある要素も1つ増えることになります。

PostgreSQL が既に存在する場合——業務アプリケーションではほぼ常にそうなります——pgvector はこの種の問題をすべて解消します。テキストのチャンクは、その出典であるドキュメントの隣にあるテーブルに格納され、外部キーによって整合性が保たれます。削除は期待通りに伝播し、別途クリーンアップタスクを作成したり監視したりする必要はありません。プロジェクトはまた、完全一致および近似検索、単一精度・半精度・バイナリ・スパースベクトル、5 種類の距離(L2、内積、コサイン、L1、ハミング、ジャカード)を追加し、PostgreSQL の ACID 準拠、時点復旧、結合を無料で継承します。

#実際にはどのように動作するか

ローカルRAGキット

あなたのドキュメント、あなたのAI:あなたのPDF、メモ、メールを扱う信頼性の高いローカルRAG。何もクラウドに送信しません。

  • 永久に利用できるオンラインスペース
  • PDF + ファイル
  • 30日間返金対応

通常の列に加えて、ベクトルを格納する列を用意します。クエリは、質問のベクトルからの距離に基づいて行を並べ替え、最も近い行を返します。一般的な用途には3つの距離演算子で対応できますが、選ぶ演算子は埋め込みモデルの規約に合わせる必要があります。この不一致が、一見気付きにくい検索品質の低下を招く最もよくある原因です。長さが1に正規化されたベクトル(OpenAI および最近の埋め込みモデルの大半が該当)では、内積の計算が最も速く、コサイン類似度と同じ順位になります。

パズルのピース
項目概要注目すべき点
ベクトル列次元数が固定された浮動小数点数の配列次元数は埋め込みモデルによって決まり、変更するにはすべてを再エンコードする必要があります。
距離計算演算子コサイン、スカラー積、またはユークリッド(L2)距離モデルと一致している必要があります
HNSWインデックスグラフインデックス、高速クエリ構築に時間がかかり、メモリ消費も多いものの、バージョン0.5以降では標準的な選択肢として妥当です
IVFFlatインデックス分割方式のインデックスで、構築コストが低い代表的なデータが揃ってから作成する
インデックスなしすべての行を対象とする厳密なスキャン数万行程度までは十分に実用的

#開始に必要な最小SQL

  1. 01
    拡張機能を有効化
    CREATE EXTENSION IF NOT EXISTS vector; — 一度だけ実行する単一のコマンドです。
  2. 02
    列を追加
    ALTER TABLE chunks ADD COLUMN embedding vector(1024); — 次元数は、使用する埋め込みモデルの次元数と完全に一致する必要があります。
  3. 03
    インデックス化前にデータをロードする
    COPYによる一括読み込みは、既存のインデックスがない方が高速です。代表的なデータ量に相当する行数が揃ってから、インデックスを作成してください。
  4. 04
    インデックスを作成
    CREATE INDEX CONCURRENTLY ON chunks USING hnsw (embedding vector_cosine_ops); — CONCURRENTLY オプションは、インデックス作成中に書き込みをブロッキングしないようにします。大きなテーブルでは長時間かかります。
  5. 05
    問い合わせる
    SELECT contenu FROM chunks WHERE document_id IN (SELECT id FROM documents WHERE utilisateur_autorise($1)) ORDER BY embedding <=> $2 LIMIT 5; — アクセス権限によるフィルタリングと類似度による並べ替えを、同じクエリで行います。

#次元数の制限を具体的に見る

pgvectorは4つの列型を定義しており、それぞれにインデックス付け可能な独自の次元上限があります。標準的なvector型(単一精度、要素あたり4バイト)は最大2,000次元までインデックス付け可能であり、これは一般的なオープンソースの埋め込みモデルの大部分(384次元から1,024次元)をカバーします。OpenAIのtext-embedding-3-largeのようにデフォルトで3,072次元というより広いモデルは、この上限を超えます。文書化された対策は、埋め込み生成時に次元を削減すること(APIで可能)か、halfvec型に切り替えることです。halfvecは半精度で保存し(要素あたり2バイト、容量は半分)、最大4,000次元までインデックス付け可能です。bit型(バイナリベクトル、ハミング距離またはジャカード距離)は最大64,000次元までインデックス付け可能であり、sparsevec(スパースベクトル)は最大1,000個の非ゼロ要素までインデックス付け可能です。これを超えると、PostgreSQLは列を依然として保存しますが(vector、halfvec、sparsevecは最大16,000次元まで)、インデックス付けはできず、完全なスキャンに頼ることになります。

→
量子化は保存方法の細かな違いにとどまらない
vectorからhalfvecに変更すると、各行のサイズが半分になります。そのため、より多くのインデックスをメモリに収められ、埋め込みモデルを変えずに、大規模な環境でのクエリを高速化できます。バイナリ量子化(bit型)は、さらに圧縮を進める方法です。検索用のインデックスを圧縮し、その後、完全なベクトルを使って検索結果を再順位付けすることで、失われた精度を回復します。これは、大容量のインデックスをディスクにあふれさせず、すべてメモリに保持するために、プロジェクト自身が文書化している方法です。

#フィルタリングおよびアクセス権限

実際の質問がコーパス全体を対象とすることはまれです。求めているのは、特定のサービスに関する、特定の日付より後の記述で、しかもそのユーザーに閲覧権限がある文書内の箇所です。専用のベクトルデータベースでは、独自の構文や境界条件を持つメタデータフィルターでこれを指定します。PostgreSQLでは、類似度による並べ替えとともにWHERE句で指定し、必要に応じてユーザーテーブルと結合します。

プロジェクト自体が文書化している落とし穴があり、本番環境で遭遇する前に知っておくとよいでしょう。近似インデックス(HNSWまたはIVFFlat)では、フィルターはインデックスの走査前ではなく、走査後に適用されます。条件に合う行が全体の10%しかなく、hnsw.ef_searchがデフォルト値の40の場合、返されるのは平均4行だけで、要求した10行には届きません。公式の対策は、バージョン0.8.0から利用できる反復インデックス走査(SET hnsw.iterative_scan = strict_order)です。結果が不足したまま何の通知もなく返すのではなく、十分な数の結果が見つかるまで自動的に走査を再開します。

!
アクセス権限はプロンプトでは管理できません
複数の人が同じインデックスに問い合わせる場合、アクセス権限に基づくフィルターが、閲覧権限のない人にモデルがドキュメントを引用して提示するのを防ぎます。どのようなプロンプトの指示も、このフィルターの代わりにはなりません。既存の認可モデルに基づいてこのフィルターをSQLで記述するほうが、認可モデルを再実装するよりもはるかに安全です。

#どこまでが限界か

大規模メモリ
数百万のベクトルをフル精度で保存すると、多くの容量が必要になります。halfvecとバイナリ量子化で使用容量は減らせますが、専用エンジンは標準機能としてさらに高い圧縮率を実現します。これが最も明確な違いです。
インデックスの構築時間
非常に大きなテーブルに対して HNSW インデックスを構築すると、時間がかかり、リソースを多く消費します。本番環境では、CREATE INDEX CONCURRENTLY を使用することで、インデックス作成中に書き込み操作をブロッキングせずに済みます。
リソースの競合
負荷の重いベクトル検索をトランザクション処理と並行して行うと、両方の負荷が同じサーバーにかかります。読み取り専用レプリカも役立ちますが、役割を分離するほうがさらに効果的です。
ベクトルの次元
インデックスを作成できるベクトルの次元数には、型ごとに上限があります(vectorは2,000、halfvecは4,000)。一般的なモデルはこの範囲に収まりますが、次元数が非常に多いモデルでは、次元削減または量子化が必要です。
ハイブリッド検索
PostgreSQLは全文検索(tsvector)に対応しており、ベクトル距離と組み合わせることもできます。ただし、使い勝手を整えるのは利用者側の仕事です。単一のクエリでネイティブなハイブリッドスコアを取得するのではなく、2つのクエリを別々に実行してから、例えば相互順位融合(Reciprocal Rank Fusion)でランキングを統合する必要があります。
水平スケーリング
単一サーバーでは対応しきれない規模になると、文書化されている方法は、読み取り用のPostgreSQLレプリカや、CitusやPgDogのような分散ツールを利用することです。つまり、当初の主張とは逆に、追加の構成要素が必要になります。
i
HNSWインデックス上のVACUUMは遅くなる可能性があります。
公式ドキュメントには明記されています。HNSW方式のベクトルインデックスを持つテーブルのクリーンアップ(VACUUM)は、データ量が多いと時間がかかることがあります。高速化するには、メンテナンス処理だけをそのまま実行させるのではなく、VACUUMの前にREINDEX INDEX CONCURRENTLYを実行します。これは運用上の注意点ですが、夜間メンテナンスが予定された時間枠を超えてしまう前に、この点に触れるチュートリアルはほとんどありません。

#pgvectorまたは専用データベース

問うべきなのは、どちらが客観的に優れているかではなく、どちらが今の状況に合うかです。請求処理、アカウント、元の文書など、アプリケーションの正本となるデータをすでにPostgreSQLで管理しているなら、pgvectorが有利です。ベクトルの量やクエリの処理量が、アプリケーションの他の部分の性能を低下させずに単一のトランザクション処理サーバーで対応できる範囲を超える場合は、専用エンジンが有利です。また、純粋な性能上の理由よりも運用上の理由から、チームがAIコンポーネントを情報システムの他の部分から分離したい場合も、専用エンジンが有利です。

状況に応じて選ぶ
状況選択
PostgreSQLを導入済みで、チャンク数が数十万未満pgvectorで余裕を持って対応
ベクトルとリレーショナルデータの整合性を保つ必要があるpgvector:トランザクションは無料で提供されます
既存の許可に基づく精密フィルタリングpgvector
4,000次元を超え、次元削減ができない埋め込みモデルsparsevec 型、またはこの用途向けに設計された専用データベースを確認する
数百万のベクトル、多数のクエリ専用エンジン(Qdrant、Milvus)
ノートブック内のプロトタイプどれでも構いません。後から変更できます

#FAQ

pgvector は RAG に十分な速度を提供しますか?+
典型的なローカルコーパス(数十から数万件程度)では、HNSW インデックスを使用すればよいです。この範囲の下限ではインデックスを用いなくてもよく、ローカルチェーンにおける検索は、実際の応答時間の主な要因とは言えません。モデルの生成処理が応答時間を支配しています。
pgvector か Qdrant か?+
PostgreSQL をすでに使っていて、データがリレーショナルな構造なら、pgvector が適しています。サービス数を減らせ、トランザクションの整合性とネイティブの SQL フィルターを利用でき、バックアップも 1 つだけ管理すれば済みます。一方、単一のデータベースを運用する手軽さよりも、規模への対応、メモリ使用量を大幅に抑える量子化、あるいはベクトル処理を全面的に想定した専用サービスを重視するなら、Qdrant が適しています。数十万ベクトル規模までは、どちらも同じニーズに十分応えられます。
インデックスはHNSWとIVFFlatのどちらを選べばよいですか?+
HNSWは数バージョン前からデフォルトになっています。クエリ性能は優れていますが、その分、構築に時間がかかり、メモリ使用量も増えます。IVFFlatは構築コストが低いものの、代表的なデータを読み込んだ後に作成する必要があります。そうしないと、パーティションの分布が偏ってしまいます。
メタデータでフィルタリングは可能ですか?+
はい。通常のSQLで、結合も含めてフィルタリングできます。これはpgvectorを選ぶ最も大きな理由の一つで、特にアクセス権による絞り込みに有用です。ただし、近似インデックスでは、フィルターはインデックスの走査後に適用されます。そのため、反復走査を行わないと、想定より少ない結果しか返されないことがあります。
埋め込みモデルを変更すると、どうなりますか?+
すべてを再エンコードする必要があります。ベクトルの次元数と幾何学的構造は、データベースではなくモデルによって決まります。これはGPU上で行うバッチ処理であり、スキーマの移行ではありません。新しい次元数が列に定義された次元数を超える場合は、列を再作成する必要があります。再エンコードが完了するまでは旧インデックスが有効なままなので、切り替えのための時間枠を確保してください。
埋め込みモデルの次元が2000を超える場合、どうすればよいですか?+
標準のvector型では、最大2,000次元までインデックスを作成できます。それを超える場合は、halfvec型(半精度で最大4,000次元)に切り替えるか、プロバイダーが対応していれば生成時に次元数を減らしてください。OpenAIはtext-embedding-3-largeでこの機能を提供しています。インデックスなしでも、PostgreSQLは最大16,000次元を保存できますが、検索は全件走査による厳密検索になります。
遅いベクトルクエリを診断する方法は?+
ドキュメントでは、クエリの先頭にEXPLAIN (ANALYZE, BUFFERS)を付けて、インデックスが実際に使われているか、何個のブロックが読み込まれるかを確認することを推奨しています。インデックスを使わない厳密検索のクエリでは、max_parallel_workers_per_gatherを増やすと性能が向上します。近似検索のクエリが遅い場合は、インデックスがまだ構築中であるか、インデックスをキャッシュに保持するためのメモリが不足していることが原因である場合が多いです。
このガイドは役に立ちましたか?

ご意見、誤りのご指摘、補足はありますか?ぜひお知らせください。皆さんにとってより良いガイドにするために役立ちます。