ベクトルデータベースとは?意味の近さで引く仕組みを整理

ベクトルデータベースとは?意味の近さで引く仕組みを整理

RAGの説明を読んでいると、必ず「ベクトルデータベースに入れておく」という一文が出てきます。

ところが、そこに何が入っていて、普通のデータベースと何が違うのかは、意外と飛ばされがち。

ベクトルデータベースは「意味が近いものを速く取り出す」ことに特化した保管庫です。

文章を数値の並びに変えたあと、その数値の近さで検索するための道具、と言い換えてもいいかもしれません。

その仕組みと選び方は、pgvector のドキュメントが示す挙動を追うと見通しがよくなります。

「一致」ではなく「近さ」で引く

普通のデータベースは、値が一致する行を探すのが得意です。

WHERE title = '確定申告'と書けば、その文字列を持つ行だけが返ってくる。

一方でベクトル検索が答えるのは、「この文とだいたい同じことを言っている行はどれか」という問いになります。

そのために必要なのが、文章を数値の並び(ベクトル)に変換する工程。

変換そのものはエンベディングの役割で、仕組みは別の記事に書きました。

エンベディングとは?AIが言葉を数値ベクトルに変換する仕組み

ベクトルデータベースは、その出力を受け取って並べておく側にあたります。

PostgreSQL の拡張である pgvector を例にすると、列の定義はこんな形。

CREATE TABLE items (id bigserial PRIMARY KEY, embedding vector(3));

検索は、距離が近い順に並べて上から数件取るだけです。

SELECT * FROM items ORDER BY embedding <-> '[3,1,2]' LIMIT 5;

<->はユークリッド距離を表す演算子で、ほかに内積の<#>、コサイン距離の<=>などが用意されています。

距離の測り方は1種類ではなく、使うモデルの推奨に合わせて選ぶことになる。

速くするために「だいたい合っている」を許す

ここまでの検索は、全件と距離を計算して並べる素朴なやり方でした。

pgvector の既定もこの厳密な検索で、完全な再現率が得られると説明されています。

そのかわり、件数が増えれば1件ずつ距離を測る負担もそのまま増えていく。

そこで登場するのが、近似最近傍探索(ANN)と呼ばれる索引です。

pgvector には HNSW と IVFFlat の2種類があり、性格がはっきり分かれている。

  • HNSW:多層のグラフを作る方式。検索は速いが、構築が遅くメモリを食う
  • IVFFlat:ベクトルをリストに分けて近いリストだけ探す方式。構築が速くメモリも軽いが、検索性能は劣る

索引の作り方は、次のように演算子クラスとパラメータを指定します。

CREATE INDEX ON items USING hnsw (embedding vector_cosine_ops) WITH (m = 16, ef_construction = 64);

見落としやすいのは、索引を足すと検索結果そのものが変わりうるという点。

公式ドキュメントも「近似索引を追加すると、同じクエリでも違う結果が見えるようになる」とはっきり書いています。

普通の索引は速度だけを変えるものなので、ここは通常のデータベース感覚が通用しない場所でした。

専用サービスか、慣れたDBの拡張か

置き場所の選択肢は、大きく2つに分かれます。

ひとつは、ベクトル検索に特化した専用のデータベースやマネージドサービスを使う道。

もうひとつが、いま使っている PostgreSQL に pgvector のような拡張を入れる道になります。

後者の利点は、本文・メタデータ・ベクトルを同じトランザクションで扱えること。

「公開済みの記事だけ」「この部署のドキュメントだけ」といった絞り込みを、素直にWHEREで書けます。

制約もあって、pgvector のvector型は最大16,000次元まで持てる一方、索引を張れるのは2,000次元まで。

モデルの出力次元がここを超えるなら、次元を落とすか別の型を検討するという判断が要ります。

規模がさらに大きくなったときに専用サービスへ移す、という順番でも遅くはないはず。

詳しい仕様はpgvector の公式リポジトリにまとまっています。

GitHub - pgvector/pgvector: Open-source vector similarity search for Postgres

入れる前に決まってしまうこと

ベクトルデータベースの話を追っていくと、精度を決めているのはDBより手前の設計だと分かってくる。

まず、どのモデルでベクトル化したかを揃えないと、距離の比較そのものが成り立たない。

モデルを変えたら保管済みのベクトルは全部作り直しになる、というのが最初の落とし穴です。

次に効いてくるのが、文書をどこで区切って入れるかという分け方の設計。

区切りが粗いと関係のない話が混ざり、細かすぎると前後の文脈が失われます。

区切り方の考え方は、チャンキングの記事で詳しく扱いました。

チャンキングとは?RAGの精度を決める文書の分け方

そして忘れがちなのが、取り出した結果をどう使うかという後段の設計でした。

検索した文書をそのままプロンプトへ流し込む流れ全体は、RAGの記事で整理しています。

RAGとは?AIに外部の知識を後から渡す仕組みを整理

ベクトルデータベースは仕組み全体の一部品であって、入れれば賢くなる箱ではありませんでした。

最後に

ベクトルデータベースは、意味の近さで行を引くための保管庫でした。

厳密に全件を比べるか、索引で近似して速さを取るか、という選択がその中心にあります。

まずは使い慣れた PostgreSQL に pgvector を入れて、厳密検索のまま小さく試すのが分かりやすいはず。

速度が足りなくなってから索引を足すと、近似で結果が変わる感覚も体験として掴めます。

道具の性格を知っておくと、精度が出ないときに疑う場所を間違えずに済みますよ。

以上です。