8.1.4 ベクトルデータベース

この節を終えると、次のことができるようになります。
- RAG でベクトルデータベースがよく使われる理由を理解する
- 「ベクトル」「メタデータ」「類似度検索」の関係を整理する
- 最小限で動くベクトル検索の例を実行する
- ベクトルデータベースを選ぶときに注目すべき観点を知る
一、なぜ普通のデータベースでは不十分なのか?
Section titled “一、なぜ普通のデータベースでは不十分なのか?”RAG で探したいのは「完全一致」ではなく「意味が近いもの」
Section titled “RAG で探したいのは「完全一致」ではなく「意味が近いもの」”従来のデータベースが得意なのは次のような処理です。
- 完全一致
- 条件での絞り込み
- リレーションの検索
でも RAG でよくある問題は、次のようなものです。
ユーザーが 1 文で質問したとき、システムは「意味が最も近い」文章を見つける必要がある。
たとえば、ユーザーがこう質問したとします。
「どうやって受講をキャンセルしますか?」
知識ベースには次のように書かれているかもしれません。
「コース購入後 7 日以内であれば返金を申請できます」
この 2 つは文字通りには同じではありませんが、意味は関連しています。
これがベクトル検索の得意な場面です。
ベクトルデータベースは本質的に「意味の座標」を管理している
Section titled “ベクトルデータベースは本質的に「意味の座標」を管理している”各テキストの embedding は、座標の集まりのように考えられます。
ベクトルデータベースの役割は、次の通りです。
- こうした座標を保存する
- ユーザーの検索時に、質問も座標に変換する
- その座標に近い点を探す
二、ベクトルデータベースには通常何を保存するのか?
Section titled “二、ベクトルデータベースには通常何を保存するのか?”ベクトルだけではなく、テキストやメタデータも保存する
Section titled “ベクトルだけではなく、テキストやメタデータも保存する”1 件のレコードには、通常少なくとも次のような情報が含まれます。
idvectortextmetadata
たとえば、次のように書けます。
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)期待される出力:
r1 0.9983 コース購入後 7 日以内であれば返金を申請できますr3 0.3601 修了テストに合格するとシステムが証明書を発行しますr2 0.218 コース修了プロジェクトを完了すると証明書を取得できますここでの query_vector は、「ユーザーの質問の embedding」と考えてください。
四、メタデータフィルタを追加する
Section titled “四、メタデータフィルタを追加する”なぜフィルタはよく使うのか?
Section titled “なぜフィルタはよく使うのか?”企業の知識ベースは、ただ何でも一気に検索するものではなく、境界を持って使うことが多いからです。
たとえば、次のような条件です。
- HR ポリシーだけを検索する
- 特定の製品ドキュメントだけを検索する
- 2025 年以降のバージョンだけを検索する
実行できる例
Section titled “実行できる例”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 -> 修了テストに合格するとシステムが証明書を発行しますこれが「類似度検索 + 業務フィルタ」の最小形です。
五、目標が「知識ベース駆動の 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 つずつ比較します。
利点:
- 結果が正確
欠点:
- データ量が大きいと遅い
近似最近傍(ANN)
Section titled “近似最近傍(ANN)”実際のベクトルデータベースでは、検索を速くするために近似手法がよく使われます。
これは次のように考えるとわかりやすいです。
すべてを地道に 1 件ずつ比べるのではなく、まず候補を素早く絞ってから近いものを探す。
利点:
- 速い
代償:
- 絶対に最適とは限らないが、たいていは十分良い

七、よくあるベクトルデータベース / ツールの役割
Section titled “七、よくあるベクトルデータベース / ツールの役割”軽量なローカル方式
Section titled “軽量なローカル方式”次のような用途に向いています。
- 学習
- プロトタイプ検証
- 小規模プロジェクト
よく使われるもの:
- FAISS
- Chroma
- SQLite + ベクトル拡張
より完成度の高いサービス型方式
Section titled “より完成度の高いサービス型方式”次のような用途に向いています。
- マルチユーザーシステム
- 大規模データ
- オンラインサービス
より重視されるのは次の点です。
- 永続化
- 同時実行
- インデックス管理
- 権限管理
- 運用性
八、選定するときは何を見るべきか?
Section titled “八、選定するときは何を見るべきか?”まず業務規模を見る
Section titled “まず業務規模を見る”確認すべき主な点は次の通りです。
- データ量はどれくらいか?
- 更新頻度は高いか?
- オンラインでの増分書き込みが必須か?
- 強いメタデータフィルタが必要か?
次に、工程上の制約を見る
Section titled “次に、工程上の制約を見る”たとえば、次のような点です。
- 自前でデプロイできるか?
- クラウドホスティングに対応しているか?
- 既存システムと統合しやすいか?
- 保守コストは高くないか?
多くの場合、最適なのは「最も強力なもの」ではなく、「いちばん扱いやすいもの」です。
九、初学者がよくある誤解
Section titled “九、初学者がよくある誤解”ベクトルデータベースが自分で意味を理解していると思う
Section titled “ベクトルデータベースが自分で意味を理解していると思う”違います。
意味の品質をまず左右するのは embedding モデルです。
ベクトルを保存すれば RAG は必ずうまくいくと思う
Section titled “ベクトルを保存すれば RAG は必ずうまくいくと思う”それだけでは不十分です。
前段では文書のクリーニングや分割が必要で、後段では prompt と出力制約も必要です。
取りこぼしだけを見る
Section titled “取りこぼしだけを見る”実際のプロジェクトでは、メタデータフィルタと出典の追跡可能性も同じくらい重要です。
ベクトルストアのデバッグチェックリスト
Section titled “ベクトルストアのデバッグチェックリスト”ベクトルデータベースを接続したら、最初にやるべきことは、すぐに LLM につなぐことではありません。
「書き込み、フィルタ、検索、引用」の 4 つがすべて信頼できるかを確認しましょう。
| チェック項目 | 確認できるべきこと | よくあるリスク |
|---|---|---|
| 書き込み件数 | 元の chunk 数と保存件数が一致、または明確なフィルタ理由がある | 文書解析の失敗、重複書き込み |
| ベクトル次元 | 同じバッチのレコードで次元が一致している | embedding モデル変更後に次元が不一致 |
| メタデータ | source、section、page、topic などのフィールドが揃っている | 後で引用やフィルタができない |
| 類似度結果 | top-k の結果に id、score、text、metadata が出せる | 答えだけ見て、ヒット内容を見ない |
| フィルタ条件 | metadata filter で検索範囲を絞れる | フィールド型が不一致で見つからない |
この表を通過できないなら、すぐに prompt を改善しようとしないでください。多くの RAG 問題は、実はベクトルストアの段階で既に種がまかれています。
最小の入庫レコード確認例
Section titled “最小の入庫レコード確認例”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 okdoc_001_chunk_02 okこの確認は、入庫前に入れておくとよいです。実際のプロジェクトでは、metadata が欠けると、その後の引用、フィルタ、権限、評価がとても難しくなります。
ベクトルデータベースの選定意思決定表
Section titled “ベクトルデータベースの選定意思決定表”| シーン | 推奨の出発点 | 理由 |
|---|---|---|
| 学習、最小デモ | メモリ上のリスト、FAISS、Chroma | シンプルで、見えやすく、デバッグしやすい |
| ローカルの試作で永続化が必要 | Chroma、SQLite ベクトル拡張 | 保存しやすく、再実行しやすい |
| 企業知識ベース | メタデータフィルタと権限に対応したサービス型ベクトル DB | 同時実行、権限、監視、運用が必要 |
| マルチテナント SaaS | マネージドベクトルデータベース、または成熟した検索サービス | 分離、拡張、バックアップ、コストが重要 |
選定は「どれが一番流行っているか」ではなく、データ量、更新頻度、フィルタ要件、デプロイ方法、保守コストから考えましょう。
このページを終えたら、この証拠カードを残します。
- クエリ
- 1つのユーザー質問またはテストケース
- 検索チャンク
- chunk id、スコア、ソースタイトル
- 回答
- 引用または出典メモ付きの最終回答
- 失敗確認
- 証拠不足、誤ったチャンク、古い文書、または裏付けのない主張
- 次の行動
- chunking、embedding、reranking、prompt、または eval の変更
この節で最も大切な理解は次の通りです。
ベクトルデータベースは「魔法のブラックボックス」ではなく、意味ベクトルとその付随情報を効率よく管理する仕組みです。
本当に気にすべきなのは、次の点です。
- ベクトルの品質は十分か
- 検索速度は十分か
- メタデータが業務要件を支えられるか
- ミニベクトルデータベースにさらに 2 件のレコードを追加し、新しい
query_vectorを手動で作って並び順を試してみましょう。 sourceというメタデータフィールドを追加して、2 条件のフィルタを試してみましょう。- 考えてみましょう。もし embedding モデルがよくなかったら、ベクトルデータベースがどれだけ強くても挽回できるでしょうか?
参考実装と解説
- 並び順は、
query_vectorに最も近い record を優先するはずです。Top result が意味的におかしいなら、弱点は database ではなく vector representation にある可能性があります。 - 2 条件フィルタでは、semantic similarity と business constraint を組み合わせます。たとえば
role=internalとsource=policyです。Metadata は、もっともらしいが権限外または無関係な chunk が回答に入るのを防ぎます。 - Vector database は効率よく index、filter、search できますが、embedding model が表現できなかった意味を後から作ることはできません。悪い embedding では、強い基盤でも retrieval は悪くなりがちです。