メインコンテンツへスキップ

8.1.4 ベクトルデータベース

ベクトルデータベースの類似度検索図

学習目標

この節を終えると、次のことができるようになります。

  • RAG でベクトルデータベースがよく使われる理由を理解する
  • 「ベクトル」「メタデータ」「類似度検索」の関係を整理する
  • 最小限で動くベクトル検索の例を実行する
  • ベクトルデータベースを選ぶときに注目すべき観点を知る

一、なぜ普通のデータベースでは不十分なのか?

RAG で探したいのは「完全一致」ではなく「意味が近いもの」

従来のデータベースが得意なのは次のような処理です。

  • 完全一致
  • 条件での絞り込み
  • リレーションの検索

でも RAG でよくある問題は、次のようなものです。

ユーザーが 1 文で質問したとき、システムは「意味が最も近い」文章を見つける必要がある。

たとえば、ユーザーがこう質問したとします。

「どうやって受講をキャンセルしますか?」

知識ベースには次のように書かれているかもしれません。

「コース購入後 7 日以内であれば返金を申請できます」

この 2 つは文字通りには同じではありませんが、意味は関連しています。
これがベクトル検索の得意な場面です。

ベクトルデータベースは本質的に「意味の座標」を管理している

各テキストの embedding は、座標の集まりのように考えられます。
ベクトルデータベースの役割は、次の通りです。

  1. こうした座標を保存する
  2. ユーザーの検索時に、質問も座標に変換する
  3. その座標に近い点を探す

二、ベクトルデータベースには通常何を保存するのか?

ベクトルだけではなく、テキストやメタデータも保存する

1 件のレコードには、通常少なくとも次のような情報が含まれます。

  • id
  • vector
  • text
  • metadata

たとえば、次のように書けます。

record = {
"id": "doc_001",
"vector": [0.2, 0.8, 0.1],
"text": "コース購入後 7 日以内であれば返金を申請できます",
"metadata": {"section": "返金ポリシー", "source": "policy.pdf"}
}

print(record)

なぜメタデータが重要なのか?

なぜなら、多くの場合は「意味が近い」だけでなく、「業務上の条件も満たしたい」からです。

たとえば、次のような条件です。

  • section=返金ポリシー のみを検索する
  • 特定の製品バージョンだけを対象にする
  • 特定の部門の文書だけを検索する

つまり、ベクトルデータベースは「ベクトルだけ」を扱うのではなく、「ベクトル + テキスト + メタデータ」を組み合わせて管理します。

ベクトルストアのレコードとメタデータフィルタの図

図の読み方

vector の列だけを見ないようにしましょう。実際の RAG では、text がモデルへの根拠になり、metadata がフィルタ、権限、引用、評価を支えます。どれか 1 つでも欠けると、システムのデバッグが難しくなります。


三、最小限で動くベクトル検索器

ここでは numpy を使って、原理が見えるミニベクトルデータベースを手作りしてみます。

import numpy as np

records = [
{
"id": "r1",
"vector": np.array([0.95, 0.05, 0.10]),
"text": "コース購入後 7 日以内であれば返金を申請できます",
"metadata": {"section": "返金ポリシー"}
},
{
"id": "r2",
"vector": np.array([0.10, 0.95, 0.05]),
"text": "コース修了プロジェクトを完了すると証明書を取得できます",
"metadata": {"section": "証明書の説明"}
},
{
"id": "r3",
"vector": np.array([0.20, 0.80, 0.15]),
"text": "修了テストに合格するとシステムが証明書を発行します",
"metadata": {"section": "証明書の説明"}
}
]

query_vector = np.array([0.90, 0.10, 0.10])

def cosine_similarity(a, b):
return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)))

results = []
for item in records:
score = cosine_similarity(query_vector, item["vector"])
results.append((score, item["id"], item["text"]))

for score, rid, text in sorted(results, reverse=True):
print(rid, round(score, 4), text)

期待される出力:

r1 0.9983 コース購入後 7 日以内であれば返金を申請できます
r3 0.3601 修了テストに合格するとシステムが証明書を発行します
r2 0.218 コース修了プロジェクトを完了すると証明書を取得できます

ここでの query_vector は、「ユーザーの質問の embedding」と考えてください。


四、メタデータフィルタを追加する

なぜフィルタはよく使うのか?

企業の知識ベースは、ただ何でも一気に検索するものではなく、境界を持って使うことが多いからです。

たとえば、次のような条件です。

  • HR ポリシーだけを検索する
  • 特定の製品ドキュメントだけを検索する
  • 2025 年以降のバージョンだけを検索する

実行できる例

import numpy as np

records = [
{
"id": "r1",
"vector": np.array([0.95, 0.05, 0.10]),
"text": "コース購入後 7 日以内であれば返金を申請できます",
"metadata": {"section": "返金ポリシー"}
},
{
"id": "r2",
"vector": np.array([0.10, 0.95, 0.05]),
"text": "コース修了プロジェクトを完了すると証明書を取得できます",
"metadata": {"section": "証明書の説明"}
},
{
"id": "r3",
"vector": np.array([0.20, 0.80, 0.15]),
"text": "修了テストに合格するとシステムが証明書を発行します",
"metadata": {"section": "証明書の説明"}
}
]

query_vector = np.array([0.15, 0.90, 0.10])

def cosine_similarity(a, b):
return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b)))

target_section = "証明書の説明"

filtered_results = []
for item in records:
if item["metadata"]["section"] != target_section:
continue
score = cosine_similarity(query_vector, item["vector"])
filtered_results.append((score, item["text"]))

for score, text in sorted(filtered_results, reverse=True):
print(round(score, 4), "->", text)

期待される出力:

0.9966 -> コース修了プロジェクトを完了すると証明書を取得できます
0.9944 -> 修了テストに合格するとシステムが証明書を発行します

これが「類似度検索 + 業務フィルタ」の最小形です。


五、目標が「知識ベース駆動の教材生成アシスタント」なら、メタデータには最低でも何を持たせるべきか?

この種のプロジェクトでは、ベクトルデータベースは単に「意味が近いものを探す」ためだけではありません。
その後の処理を支えるためにも使われます。

  • テーマごとに絞る
  • 概念 / 例題 / 練習問題で絞る
  • 内部資料 / 外部資料で絞る
  • 最後に出典をたどれるようにする

そのため、初心者向けの最小メタデータセットは、通常次のようになります。

フィールド何を助けるか
topic現在のテーマへのルーティング
content_type概念 / 例題 / 練習問題を区別する
source_origin内部資料 / 外部資料を区別する
page_or_slide生成時の出典として使う
grade対象学年や対象者を絞る

小さなレコードは、次のように書けます。

record = {
"id": "doc_001_chunk_03",
"text": "商品の元値が 100 円で、2 割引きした後の価格はいくらですか?",
"metadata": {
"topic": "割引の文章題",
"content_type": "example",
"source_origin": "internal",
"page_or_slide": 3,
"grade": "小学高学年",
},
}

print(record)

この例で、初心者が特に気をつけるべき点は次の通りです。

  • ベクトルストアのこの層が、後の教材を安定して組み立てられるかどうかを実は左右している

六、厳密検索と近似検索の違いは何か?

厳密検索

検索クエリのベクトルを、すべてのベクトルと 1 つずつ比較します。

利点:

  • 結果が正確

欠点:

  • データ量が大きいと遅い

近似最近傍(ANN)

実際のベクトルデータベースでは、検索を速くするために近似手法がよく使われます。

これは次のように考えるとわかりやすいです。

すべてを地道に 1 件ずつ比べるのではなく、まず候補を素早く絞ってから近いものを探す。

利点:

  • 速い

代償:

  • 絶対に最適とは限らないが、たいていは十分良い

厳密検索と ANN のトレードオフ図

図の読み方

厳密検索はクラス全員を 1 人ずつ比べるようなもの、ANN はまずエリアで候補を絞ってから近所を探すようなものです。初心者はまず 1 つ覚えましょう。ANN は「絶対最適の保証」を少し犠牲にして、大規模検索の速度を得ます。


七、よくあるベクトルデータベース / ツールの役割

軽量なローカル方式

次のような用途に向いています。

  • 学習
  • プロトタイプ検証
  • 小規模プロジェクト

よく使われるもの:

  • FAISS
  • Chroma
  • SQLite + ベクトル拡張

より完成度の高いサービス型方式

次のような用途に向いています。

  • マルチユーザーシステム
  • 大規模データ
  • オンラインサービス

より重視されるのは次の点です。

  • 永続化
  • 同時実行
  • インデックス管理
  • 権限管理
  • 運用性

八、選定するときは何を見るべきか?

まず業務規模を見る

確認すべき主な点は次の通りです。

  • データ量はどれくらいか?
  • 更新頻度は高いか?
  • オンラインでの増分書き込みが必須か?
  • 強いメタデータフィルタが必要か?

次に、工程上の制約を見る

たとえば、次のような点です。

  • 自前でデプロイできるか?
  • クラウドホスティングに対応しているか?
  • 既存システムと統合しやすいか?
  • 保守コストは高くないか?

多くの場合、最適なのは「最も強力なもの」ではなく、「いちばん扱いやすいもの」です。


九、初学者がよくある誤解

ベクトルデータベースが自分で意味を理解していると思う

違います。
意味の品質をまず左右するのは embedding モデルです。

ベクトルを保存すれば RAG は必ずうまくいくと思う

それだけでは不十分です。
前段では文書のクリーニングや分割が必要で、後段では prompt と出力制約も必要です。

取りこぼしだけを見る

実際のプロジェクトでは、メタデータフィルタと出典の追跡可能性も同じくらい重要です。


ベクトルストアのデバッグ Checklist

ベクトルデータベースを接続したら、最初にやるべきことは、すぐに LLM につなぐことではありません。
「書き込み、フィルタ、検索、引用」の 4 つがすべて信頼できるかを確認しましょう。

チェック項目確認できるべきことよくあるリスク
書き込み件数元の chunk 数と保存件数が一致、または明確なフィルタ理由がある文書解析の失敗、重複書き込み
ベクトル次元同じバッチのレコードで次元が一致しているembedding モデル変更後に次元が不一致
メタデータsource、section、page、topic などのフィールドが揃っている後で引用やフィルタができない
類似度結果top-k の結果に id、score、text、metadata が出せる答えだけ見て、ヒット内容を見ない
フィルタ条件metadata filter で検索範囲を絞れるフィールド型が不一致で見つからない

この表を通過できないなら、すぐに prompt を改善しようとしないでください。多くの RAG 問題は、実はベクトルストアの段階で既に種がまかれています。

最小の入庫レコード確認例

records = [
{
"id": "doc_001_chunk_01",
"vector": [0.95, 0.05, 0.10],
"text": "コース購入後 7 日以内であれば返金を申請できます",
"metadata": {"source": "policy.md", "section": "返金ポリシー", "page": 1},
},
{
"id": "doc_001_chunk_02",
"vector": [0.10, 0.90, 0.05],
"text": "コース修了プロジェクトを完了すると証明書を取得できます",
"metadata": {"source": "policy.md", "section": "証明書の説明", "page": 2},
},
]

required_meta = {"source", "section", "page"}
vector_dim = len(records[0]["vector"])

for record in records:
problems = []
if len(record["vector"]) != vector_dim:
problems.append("vector_dim_mismatch")
missing = required_meta - set(record["metadata"])
if missing:
problems.append(f"missing_metadata={sorted(missing)}")
if not record["text"].strip():
problems.append("empty_text")
print(record["id"], problems or "ok")

期待される出力:

doc_001_chunk_01 ok
doc_001_chunk_02 ok

この確認は、入庫前に入れておくとよいです。実際のプロジェクトでは、metadata が欠けると、その後の引用、フィルタ、権限、評価がとても難しくなります。

ベクトルデータベースの選定意思決定表

シーン推奨の出発点理由
学習、最小 Demoメモリ上のリスト、FAISS、Chromaシンプルで、見えやすく、デバッグしやすい
ローカルの試作で永続化が必要Chroma、SQLite ベクトル拡張保存しやすく、再実行しやすい
企業知識ベースメタデータフィルタと権限に対応したサービス型ベクトル DB同時実行、権限、監視、運用が必要
マルチテナント SaaSマネージドベクトルデータベース、または成熟した検索サービス分離、拡張、バックアップ、コストが重要

選定は「どれが一番流行っているか」ではなく、データ量、更新頻度、フィルタ要件、デプロイ方法、保守コストから考えましょう。

まとめ

この節で最も大切な理解は次の通りです。

ベクトルデータベースは「魔法のブラックボックス」ではなく、意味ベクトルとその付随情報を効率よく管理する仕組みです。

本当に気にすべきなのは、次の点です。

  • ベクトルの品質は十分か
  • 検索速度は十分か
  • メタデータが業務要件を支えられるか

練習

  1. ミニベクトルデータベースにさらに 2 件のレコードを追加し、新しい query_vector を手動で作って並び順を試してみましょう。
  2. source というメタデータフィールドを追加して、2 条件のフィルタを試してみましょう。
  3. 考えてみましょう。もし embedding モデルがよくなかったら、ベクトルデータベースがどれだけ強くても挽回できるでしょうか?