pgvector

作成日:
PostgreSQL vector-search database machine-learning

概要

pgvectorは、PostgreSQLでベクトル(埋め込み / Embedding)を保存し、類似性検索を行うための拡張機能です。AIや機械学習アプリケーションでセマンティック検索(意味的な検索)を実現するために使用されます。

pgvectorの特徴:

  • PostgreSQLの拡張機能として動作
  • ベクトルデータ型と類似性検索演算子を提供
  • 既存のPostgreSQLインフラに統合可能
  • Supabase、Amazon RDS、Cloud SQLなど主要なマネージドサービスでサポート

ベクトル検索の基礎概念については 検索技術の基礎 を参照。

なぜpgvectorを使うのか?

専用ベクトルDBとの比較

観点pgvector専用ベクトルDB(Pinecone等)
学習コストPostgreSQLの知識で対応可能新しいAPI・概念の学習が必要
運用既存のPostgreSQL運用に統合別途運用が必要
コストPostgreSQLのコストのみ追加のサービス料金
スケーラビリティ中規模まで(数百万ベクトル)大規模対応(数十億ベクトル)
機能基本的な類似性検索高度なフィルタリング、メタデータ管理

pgvectorが適しているケース:

  • 既存のPostgreSQLを使用している
  • ベクトル数が数百万件以下
  • シンプルな類似性検索で十分
  • 追加のインフラを増やしたくない

専用ベクトルDBが適しているケース:

  • 数十億規模のベクトル
  • 高度なフィルタリングが必要
  • 超低レイテンシが求められる

基本的な使い方

拡張機能の有効化

-- pgvector拡張を有効化
CREATE EXTENSION IF NOT EXISTS vector;

テーブルの作成

-- ベクトルカラムを持つテーブルを作成
CREATE TABLE articles (
  id SERIAL PRIMARY KEY,
  title TEXT NOT NULL,
  content TEXT NOT NULL,
  embedding VECTOR(1536)  -- OpenAI text-embedding-3-small の次元数
);

VECTOR(n)n は埋め込みモデルの次元数に合わせます:

モデル次元数
OpenAI text-embedding-3-small1536
OpenAI text-embedding-3-large3072
OpenAI text-embedding-ada-0021536
Cohere embed-multilingual-v3.01024
intfloat/multilingual-e5-large1024

データの挿入

-- ベクトルデータを挿入
INSERT INTO articles (title, content, embedding)
VALUES (
  'Dockerの基本',
  'Dockerはコンテナ仮想化のプラットフォームです...',
  '[0.1, 0.2, 0.3, ...]'::vector  -- 実際には1536次元のベクトル
);

類似性検索

pgvectorは3種類の距離関数を提供します:

演算子距離関数説明
<->L2距離(ユークリッド距離)幾何学的な距離
<#>内積の負値正規化されたベクトル向け
<=>コサイン距離方向の類似性(最も一般的)
-- コサイン距離で類似検索(距離が小さいほど類似)
SELECT 
  id,
  title,
  1 - (embedding <=> '[0.1, 0.2, ...]'::vector) AS similarity
FROM articles
ORDER BY embedding <=> '[0.1, 0.2, ...]'::vector
LIMIT 10;

コサイン類似度への変換:

-- コサイン距離 → コサイン類似度
-- 類似度 = 1 - 距離
SELECT 
  title,
  1 - (embedding <=> query_embedding) AS similarity
FROM articles
WHERE 1 - (embedding <=> query_embedding) > 0.7  -- 類似度70%以上
ORDER BY similarity DESC;

インデックスの作成

大量のデータに対して高速な検索を行うには、インデックスの作成が必要です。

IVFFlat インデックス

近似最近傍探索(ANN)のためのインデックス。データをクラスタに分割し、検索対象を絞り込みます。

-- IVFFlatインデックスの作成
CREATE INDEX ON articles 
USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);

パラメータ:

  • lists: クラスタ数(推奨: 行数の平方根、または行数/1000)
  • vector_cosine_ops: コサイン距離用の演算子クラス
データ量推奨lists値
〜10,000行100
〜100,000行300
〜1,000,000行1000

HNSW インデックス

Hierarchical Navigable Small World。IVFFlatより高精度だが、インデックス構築が遅い。

-- HNSWインデックスの作成
CREATE INDEX ON articles 
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);

パラメータ:

  • m: グラフの接続数(デフォルト: 16)
  • ef_construction: 構築時の探索範囲(デフォルト: 64)

インデックスの選択指針

観点IVFFlatHNSW
構築速度速い遅い
検索精度良好優秀
メモリ使用量少ない多い
更新への対応再構築が必要な場合あり動的更新可能

RPC関数の作成

検索ロジックをデータベース関数としてカプセル化すると便利です。

-- 類似記事検索関数
CREATE OR REPLACE FUNCTION search_articles(
  query_embedding VECTOR(1536),
  match_threshold FLOAT DEFAULT 0.7,
  match_count INT DEFAULT 10
)
RETURNS TABLE (
  id INT,
  title TEXT,
  content TEXT,
  similarity FLOAT
)
LANGUAGE plpgsql
AS $$
BEGIN
  RETURN QUERY
  SELECT
    articles.id,
    articles.title,
    articles.content,
    1 - (articles.embedding <=> query_embedding) AS similarity
  FROM articles
  WHERE 1 - (articles.embedding <=> query_embedding) > match_threshold
  ORDER BY articles.embedding <=> query_embedding
  LIMIT match_count;
END;
$$;

使用例:

-- 関数を呼び出して検索
SELECT * FROM search_articles(
  '[0.1, 0.2, ...]'::vector,
  0.7,   -- 類似度閾値
  10     -- 最大件数
);

パフォーマンスのヒント

1. 適切なインデックスを選択

  • 数万件以下: インデックスなしでも可
  • 数十万件: IVFFlat
  • 数百万件以上: HNSW

2. probes パラメータの調整(IVFFlat)

-- 検索時に探索するクラスタ数を増やす(精度向上、速度低下)
SET ivfflat.probes = 10;

3. ef_search パラメータの調整(HNSW)

-- 検索時の探索範囲を広げる(精度向上、速度低下)
SET hnsw.ef_search = 100;

4. 部分インデックス

特定の条件に絞ったインデックスを作成:

-- カテゴリが 'topics' の記事のみインデックス
CREATE INDEX ON articles 
USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100)
WHERE category = 'topics';

制限事項

  • 次元数の上限: 2000次元まで(pgvector 0.5.0以降は16000次元)
  • インデックスの再構築: IVFFlatは大量のデータ追加後に再構築が推奨
  • メモリ使用量: HNSWは特にメモリを消費

関連トピック

参考リンク