メタデータフィルタとルーティング — 検索する前に範囲を絞る
類似度だけに頼る検索の限界を、構造化された条件で補えるようになる。事前フィルタと事後フィルタの違い、権限による絞り込み、複数コーパスへの振り分けを設計できる。
- 「最新版の」「自分が見てよい」「この製品の」といった条件は、意味の近さでは表現できない。ベクトル検索の外側に構造化された絞り込みが要る。
- 事後フィルタはk件引いてから条件で捨てるため、条件が厳しいと結果がゼロになる。事前フィルタは条件を満たす集合の中だけを探すので件数が保証されるが、索引側の対応が要る。
- 権限フィルタは精度の話ではなく情報漏洩の話。事後フィルタで実装すると、条件が厳しいユーザーほど結果が減るという形で他人の文書の存在が漏れうる。
ベクトル検索は「意味が近いもの」を返しますが、実務の質問にはそれだけでは表現できない条件が必ず付きます。
「v3の仕様では」 → バージョンによる絞り込み
「先月の議事録から」 → 期間による絞り込み
「自分が見てよい範囲で」 → 権限による絞り込み
「製品Aについて」 → 製品による絞り込み
これらは意味の近さではなく、構造化された属性の一致です。「v3」という語がクエリに入っていれば v3 の文書がやや上に来る、という確率的な効果は期待できますが、v2 の文書が混ざるのを防げません。仕様の質問で古いバージョンの記述が混ざるのは、実用上は誤答と同じです。
横にスクロール
事前フィルタと事後フィルタ
絞り込みをどの段階でかけるかで、挙動が大きく変わります。
| 事後フィルタ | 事前フィルタ | |
|---|---|---|
| やり方 | 上位k件を引いてから条件で捨てる | 条件を満たす集合の中だけを探索する |
| 実装 | アプリ側で簡単に書ける | ベクトルDBの対応が要る |
| 結果件数 | 保証されない(ゼロもありうる) | 条件を満たす件数まで確実に返る |
| 条件が厳しいとき | 破綻する | 問題なく動く |
| 索引の性能 | 影響なし | 実装によっては探索効率が落ちる |
事後フィルタの破綻は具体的です。上位100件を引いてから「製品Aのみ」で絞ると、コーパスの大半が製品Bなら、100件中1件しか残らない、あるいはゼロ件になります。「引く件数を増やせばよい」と考えて1000件引くと、今度はレイテンシが悪化します。条件を満たす文書がコーパス全体で少数派であるほど、事後フィルタは成立しません。
事前フィルタは条件を満たす集合の中を探すので、この問題が原理的に起きません。多くのベクトルDBが対応していますが、近似最近傍索引との相性には注意が要ります。HNSWのようなグラフ索引は近傍グラフを辿って探索するため、条件で大半のノードが除外されるとグラフが分断され、探索が途中で行き詰まって再現率が落ちることがあります。条件が非常に厳しい場合は、フィルタ後の集合に対する総当たり検索へ切り替える実装が有利です。
「自分が見てよい文書だけ」を事後フィルタで実装すると、権限の狭いユーザーほど結果が少なくなるという観測可能な差が生じます。同じ質問で結果件数が人によって違えば、そこから見えない文書の存在が推測できます。さらに危険なのは、フィルタの実装漏れが即座に情報漏洩になる点です。権限は必ず事前フィルタで、検索基盤の側で強制し、アプリ側の後処理に依存させないでください。テナント分離が要るなら、フィルタではなくコーパス自体を分けるのが最も安全です。
メタデータの設計
フィルタは、取り込み時に何を保存したかで決まります。あとから足すには再インデックスが要るので、最初に多めに持たせておくのが正解です。
必ず持たせたいもの
文書ID / チャンクID … 重複排除、親子の解決
ソースURL・ファイルパス … 出典表示
タイトル・見出しパス … 出典表示と、本文への前置
更新日時 … 鮮度フィルタと新しい版の優先
権限スコープ … アクセス制御
文書種別 … ルーティングと絞り込み
用途に応じて
プロダクト / バージョン / 言語 / 部署 / 顧客ID
更新日時は特に重要です。同じ内容の新旧2版がコーパスにあると、埋め込みはほぼ同じなのでどちらが返るか制御できません。古い版が返れば誤答です。対策は、古い版を索引から削除するか、更新日時でフィルタするか、スコアに新しさの重みを乗せるかのいずれかです。取り込みパイプラインが更新版を追加するだけで古い版を消していないのは非常によくある不具合で、「たまに古い情報を答える」の主因になります。
ルーティング:どのコーパスを引くか
コーパスが複数に分かれている場合、質問に応じてどれを引くかを選ぶのがルーティングです。
質問 → 分類 → 適切な検索先へ
「APIの使い方」 → APIリファレンス索引
「先月の売上」 → 構造化データ(SQL)
「障害の対応履歴」 → インシデント記録索引
「就業規則」 → 社内規程索引
分類は LLM に選ばせるのが手軽です。選択肢とそれぞれの説明を与え、どれを使うか答えさせます。ルールベース(キーワードや正規表現)でも十分な場面は多く、確実に判定できるものはルールで先に捌き、残りをLLMに回す構成がコストと精度のバランスに優れます。
ルーティングの価値は3つあります。検索空間が小さくなって精度が上がる、無関係なコーパスのノイズが混ざらない、そしてベクトル検索が向かない質問を別の手段へ逃がせることです。3つ目が特に効きます。「先月の売上は?」に対して文書検索を試みるのは筋が悪く、SQLを組み立てて実データを引くべきです。この判断はツール使用(Function Calling)の枠組みそのものです。
まとめ
- 「最新版の」「自分が見てよい」「この製品の」といった条件は意味の近さでは表現できない。構造化された絞り込みが要る。
- 事後フィルタは条件が厳しいと破綻する(結果ゼロ)。条件を満たす文書が少数派なほど成立しない。事前フィルタは件数が保証される。
- 事前フィルタは近似最近傍索引との相性に注意。条件が厳しいときはフィルタ後の総当たりへ切り替える実装が有利。
- 権限フィルタは精度ではなくセキュリティ。事後フィルタは結果件数の差から見えない文書の存在を推測させうる。検索基盤側で強制し、テナント分離はコーパスを分ける。
- メタデータはあとから足すと再インデックスが要るので最初に多めに持たせる。更新日時の欠落と古い版の消し忘れが「たまに古い情報を答える」の主因。
- ルーティングの最大の価値は、ベクトル検索が向かない質問を別の手段へ逃がせること。分類に賭けきらず、失敗時に回復できる形にする。
RAG設計パターンの記事ガイド
メタデータフィルタとルーティング — 検索する前に範囲を絞るを実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
RAG
比較で見る軸
難易度: advanced / カテゴリ: RAG設計パターン / タグ数: 5
導入後に効く点
事後フィルタはk件引いてから条件で捨てるため、条件が厳しいと結果がゼロになる。事前フィルタは条件を満たす集合の中だけを探すので件数が保証されるが、索引側の対応が要る。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- RAG設計パターン
- タグ数
- 5
判断チェックリスト
- 自社の用途が「RAG / メタデータ」に近いか確認する。
- 強みである「「最新版の」「自分が見てよい」「この製品の」といった条件は、意味の近さでは表現できない。ベクトル検索の外側に構造化された絞り込みが要る。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。