はじめに
RAG(Retrieval-Augmented Generation)やレコメンドシステムを実装する際、PostgreSQLの拡張機能であるpgvectorを使う機会が増えています。本記事では、pgvectorの基本的な仕組みと、pgvectorが提供する3つの距離演算子(コサイン距離・L2距離・内積)がそれぞれ何を意味しているのかを図解しながら整理します。
pgvectorとは
pgvectorは、PostgreSQLにベクトル検索機能を追加するオープンソースの拡張モジュールです。専用のベクトルデータベース(PineconeやWeaviateなど)を別途構築せずに、既存のリレーショナルデータベースにそのまま組み込んで類似検索を実現できるのが最大の特徴です。
基本的な仕組み
CREATE EXTENSION vector; の一行でPostgreSQLにvectorという新しいデータ型が追加され、通常のテーブルカラムに数百〜数千次元の埋め込み(embedding)ベクトルをそのまま格納できるようになります。OpenAIなどのAPIでテキストや画像をベクトル化したデータを保存し、SQLの中でJOINやフィルタリングと組み合わせながら類似検索を行えます。
インデックス方式
大規模データセットでの検索を高速化するために、2種類の近似最近傍探索インデックスをサポートしています。
- IVFFlat: 中規模データ向け。クラスタリングしてから検索範囲を絞る方式
- HNSW: 高速な近似最近傍探索向け。グラフ構造を使い高精度・高速な検索が可能
なぜ注目されているのか
キーワード検索では捉えられない「意味的な類似性」に基づく検索ニーズがAI・RAGブームで急増しており、既存のPostgreSQL運用ノウハウをそのまま活かせる点が支持されています。専用ベクトルDBを別途運用する必要がなく、メタデータ・元データ・埋め込みベクトルを一括管理できるため構成がシンプルになり、運用コストも抑えられます。
3つの距離指標の違い
pgvectorは類似度を測るための3種類の演算子を提供しています。
| 演算子 | 指標 | 何を測るか | 大きさ(ノルム)の影響 |
|---|---|---|---|
<=> |
コサイン距離 | ベクトルの向きの違い | 無視(正規化して比較) |
<-> |
L2距離(ユークリッド距離) | 実際の空間的な距離 | 受ける |
<#> |
内積(負の内積) | 向き+大きさの複合 | 受ける |
以下の図は、2つのベクトル A と B を例に、3つの指標がそれぞれ「どこ」を見ているかを可視化したものです。
- 左:コサイン距離は、原点から見たAとBの角度θだけを見ます。ベクトルの長さは無視されます。
- 中:L2距離は、AとBの先端同士を結ぶ直線の長さそのものを見ます。角度だけでなく長さの違いにも影響を受けます。
- 右:内積は、BのベクトルをAの方向に射影した長さにAの長さを掛け合わせたイメージで、向きと大きさの両方を反映します。
コサイン距離:意味の近さ
コサイン類似度は2つのベクトルが向いている角度を測る指標で、A・B / (|A||B|)で計算されます。ベクトルの大きさは無視され、方向だけを比較するため、文章やLLM埋め込みの意味的な類似検索でよく使われます。なお、pgvectorではコサイン類似度ではなく「コサイン距離」(1 - コサイン類似度)を返すため、値が小さいほど似ていることになります。
L2距離(ユークリッド距離):実際の距離
L2距離は2点間の直線距離をそのまま測るもので、L2(a,b) = √Σ(aᵢ-bᵢ)²という単純な計算です。コサインが「向き」だけを見るのに対し、L2距離はベクトルの大きさ(ノルム)の違いにも敏感に反応します。そのため、値の絶対的なスケールが意味を持つデータ(センサー値、位置座標、画像特徴量の絶対的な差など)に向いています。
内積(ドット積):向きと大きさの複合
内積はΣ(aᵢ×bᵢ)で計算され、直感的には「ベクトルの向きの近さ」と「ベクトルの大きさ」の両方を同時に測る指標です。数式的にはA・B = |A||B|cosθとなり、ベクトルの大きさとコサインを掛け合わせた値になります。つまり正規化していないベクトル同士では、「向きが近い」だけでなく「両方のベクトルが大きい(重要度が高い)」ほど値が大きくなります。この性質から、推薦システムのようにベクトルの大きさ自体に「重み」や「スコア」の意味を持たせたい場面(Maximum Inner Product Search)でよく使われます。
使い分けのポイント
単位ベクトル(正規化済み、長さ=1)同士であれば、内積とコサイン類似度は数学的に等価になります。OpenAIなどのLLM埋め込みはすでに正規化されているケースが多いため、その場合は内積(<#>)を使うと正規化計算を省略でき、コサイン距離より計算が高速になります。
逆にベクトルが正規化されていない場合、内積を使うと「向きが近いだけ」でなく「両方が大きい」ベクトル同士が過剰に高スコアになりやすい点には注意が必要です。用途に応じて以下のように選ぶとよいでしょう。
- 意味検索・テキスト類似検索 → コサイン距離
- 数値データの絶対的な近さを重視 → L2距離
- 正規化済みベクトルの高速検索、または大きさに意味を持たせたい推薦系タスク → 内積
まとめ
pgvectorはPostgreSQLをそのままベクトルデータベース化できる便利な拡張機能ですが、距離指標の選択はタスクの性質に直結する重要な設計判断です。テキストの意味的類似性を扱うなら基本はコサイン距離、正規化済みベクトルで高速化したいなら内積、絶対的な数値の近さを重視するならL2距離、という基準で選ぶと失敗しにくいと思います。
