PostgreSQLでのベクトル検索の実践ガイド

PostgreSQLは拡張機能pgvectorを活用することで、高次元ベクトルデータの保存と類似度検索が可能になります。機械学習や自然言語処理、レコメンデーションエンジンなど、ベクトル空間モデルを必要とするアプリケーションに最適です。

拡張のインストールと初期設定

CREATE EXTENSION IF NOT EXISTS vector;

ベクトルカラムを持つテーブルの定義

CREATE TABLE catalog (
    item_id BIGSERIAL PRIMARY KEY,
    label VARCHAR(255),
    vec_data VECTOR(4)  -- 4次元ベクトル
);

サンプルデータの投入

INSERT INTO catalog (label, vec_data) VALUES
    ('Alpha', '[0.5, 1.0, 1.5, 2.0]'),
    ('Beta', '[2.0, 2.5, 3.0, 3.5]'),
    ('Gamma', '[3.5, 4.0, 4.5, 5.0]'),
    ('Delta', '[0.2, 0.2, 0.2, 0.2]');

距離ベースの検索クエリ

L2距離(ユークリッド)による近傍探索

SELECT 
    item_id, 
    label, 
    vec_data <-> '[0.2,0.2,0.2,0.2]' AS euclid_dist
FROM catalog
ORDER BY euclid_dist
LIMIT 3;

内積による関連性スコアリング

SELECT 
    item_id, 
    label, 
    vec_data <#> '[0.2,0.2,0.2,0.2]' AS inner_prod
FROM catalog
ORDER BY inner_prod DESC
LIMIT 3;

コサイン類似度によるランキング

SELECT 
    item_id, 
    label, 
    vec_data <=> '[0.2,0.2,0.2,0.2]' AS cos_sim
FROM catalog
ORDER BY cos_sim
LIMIT 3;

大規模データ向けインデックス構築

-- IVF-Flatインデックス(クラスタ数=150)
CREATE INDEX idx_catalog_ivfflat ON catalog 
USING ivfflat (vec_data vector_cosine_ops) WITH (lists = 150);

-- HNSWインデックス(L2距離最適化)
CREATE INDEX idx_catalog_hnsw ON catalog 
USING hnsw (vec_data vector_l2_ops);

応用例:商品レコメンデーション

CREATE TABLE user_profiles (
    uid BIGINT PRIMARY KEY,
    profile_name TEXT,
    taste_vec VECTOR(8)
);

CREATE TABLE merchandise (
    sku BIGINT PRIMARY KEY,
    product_name TEXT,
    spec_vec VECTOR(8)
);

-- ユーザーID=101にマッチする商品トップ5
SELECT 
    m.sku, 
    m.product_name, 
    m.spec_vec <-> u.taste_vec AS relevance
FROM user_profiles u
JOIN merchandise m ON TRUE
WHERE u.uid = 101
ORDER BY relevance
LIMIT 5;

ベクトル演算の利用例

-- ベクトルの足し算・引き算
SELECT '[1,2,3,4]'::vector + '[0.5,0.5,0.5,0.5]'::vector AS added;
SELECT '[3,3,3,3]'::vector - '[1,1,1,1]'::vector AS subtracted;

-- スカラー倍
SELECT 1.5 * '[2,4,6,8]'::vector AS scaled;

-- 正規化関数の作成と適用
CREATE OR REPLACE FUNCTION unit_normalize(v_input vector)
RETURNS vector AS $$
BEGIN
    RETURN v_input / |/ (v_input <#> v_input);
END;
$$ LANGUAGE plpgsql;

SELECT item_id, unit_normalize(vec_data) FROM catalog;

パフォーマンス最適化のポイント

  • データ量が少ない場合はフルスキャンでも十分
  • 数十万件以上ではhnswまたはivfflatインデックス必須
  • 1000次元を超える場合は専用ベクトルDBの検討を推奨
  • 大量INSERT時はCOPYコマンドで一括投入

統合検索の実装例

-- 商品テーブルとベクトルフィールド
CREATE TABLE inventory (
    prod_id BIGSERIAL PRIMARY KEY,
    title TEXT,
    cost DECIMAL(10,2),
    traits VECTOR(6)
);

-- サンプルデータ挿入
INSERT INTO inventory (title, cost, traits) VALUES
    ('UltraBook X1', 1299.00, '[0.8,0.6,0.9,0.7,0.5,0.3]'),
    ('Phone Pro Max', 899.00, '[0.7,0.8,0.6,0.9,0.4,0.5]'),
    ('MediaPad Lite', 299.00, '[0.5,0.4,0.7,0.6,0.8,0.2]');

-- HNSWインデックス作成
CREATE INDEX idx_inv_hnsw ON inventory USING hnsw (traits vector_l2_ops);

-- 類似商品検索(予算制限付き)
SELECT 
    prod_id, 
    title, 
    cost,
    traits <-> '[0.7,0.8,0.6,0.9,0.4,0.5]' AS match_score
FROM inventory
WHERE cost <= 1000
ORDER BY match_score
LIMIT 4;

タグ: PostgreSQL pgvector ベクトル検索 類似度検索 HNSW

5月21日 07:06 投稿