コンテンツにスキップ

8.1.4 ベクトルデータベース

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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 titled “なぜメタデータが重要なのか?”

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

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

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

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

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


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

Section titled “三、最小限で動くベクトル検索器”

ここでは 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)

期待される出力:

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

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


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

Section titled “四、メタデータフィルタを追加する”

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

Section titled “なぜフィルタはよく使うのか?”

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

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

  • 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)

期待される出力:

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

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


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

Section titled “五、目標が「知識ベース駆動の SOP 文書アシスタント」なら、メタデータには最低でも何を持たせるべきか?”

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

  • テーマごとに絞る
  • ポリシー / ケース / チェックリストで絞る
  • 内部資料 / 外部資料で絞る
  • 最後に出典をたどれるようにする

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

フィールド何を助けるか
topic現在のテーマへのルーティング
content_typeポリシー / 対応ケース / チェックリストを区別する
source_origin内部資料 / 外部資料を区別する
page_or_slide生成時の出典として使う
teamサポートチームや対象者を絞る

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

record = {
"id": "doc_001_chunk_03",
"text": "返金期限後でも重複請求が確認された場合は、取引証拠を添えて billing support にエスカレーションする。",
"metadata": {
"topic": "返金エスカレーション",
"content_type": "case",
"source_origin": "internal",
"page_or_slide": 3,
"team": "support ops",
},
}
print(record)

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

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

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

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

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

利点:

  • 結果が正確

欠点:

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

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

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

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

利点:

  • 速い

代償:

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

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


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

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

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

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

よく使われるもの:

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

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

Section titled “より完成度の高いサービス型方式”

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

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

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

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

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

Section titled “八、選定するときは何を見るべきか?”

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

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

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

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

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


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

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

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

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

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

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

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


ベクトルストアのデバッグチェックリスト

Section titled “ベクトルストアのデバッグチェックリスト”

ベクトルデータベースを接続したら、最初にやるべきことは、すぐに 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")

期待される出力:

Terminal window
doc_001_chunk_01 ok
doc_001_chunk_02 ok

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

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

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

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

このページを終えたら、この証拠カードを残します。

クエリ
1つのユーザー質問またはテストケース
検索チャンク
chunk id、スコア、ソースタイトル
回答
引用または出典メモ付きの最終回答
失敗確認
証拠不足、誤ったチャンク、古い文書、または裏付けのない主張
次の行動
chunking、embedding、reranking、prompt、または eval の変更

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

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

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

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

  1. ミニベクトルデータベースにさらに 2 件のレコードを追加し、新しい query_vector を手動で作って並び順を試してみましょう。
  2. source というメタデータフィールドを追加して、2 条件のフィルタを試してみましょう。
  3. 考えてみましょう。もし embedding モデルがよくなかったら、ベクトルデータベースがどれだけ強くても挽回できるでしょうか?
参考実装と解説
  1. 並び順は、query_vector に最も近い record を優先するはずです。Top result が意味的におかしいなら、弱点は database ではなく vector representation にある可能性があります。
  2. 2 条件フィルタでは、semantic similarity と business constraint を組み合わせます。たとえば role=internalsource=policy です。Metadata は、もっともらしいが権限外または無関係な chunk が回答に入るのを防ぎます。
  3. Vector database は効率よく index、filter、search できますが、embedding model が表現できなかった意味を後から作ることはできません。悪い embedding では、強い基盤でも retrieval は悪くなりがちです。