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;