3行でいうと
- キーワード検索は固有名詞や型番に強く、ベクトル検索は言い換えに強い。得意が違うので、合わせる価値がある。
- 2つの点数は単位が違うので、足さずに「順位」で混ぜるRRFがよく使われる。式は 1÷(定数+順位) の合計。
- リランキングは、検索で集めた数十〜数百件を、質問と一緒に読み直して並べ替える追加の段。
- Anthropicの試験では、検索の取りこぼしが5.7%から、文脈つきの併用で2.9%、さらに並べ替えで1.9%になった。
この記事は、実際に使って確かめた記録ではありません。この記事は公式の文書や論文を読んでまとめたものです。
先に結論
- 検索の方式には得意不得意があります。1つに決め打ちせず、両方で候補を取って混ぜるのが、いま広く使われる基本形です。
- 混ぜるときに点数をそのまま足すのは避けます。点数の尺度が違うからです。多くの製品は、順位だけを使うRRFを標準にしています。
- 並べ替え(リランキング)は、混ぜたあとの追加の段です。精度が上がる一方、時間と費用が増えます。
- 数字はAnthropicの2024年の試験と、各社の既定値です。自分の資料で測り直す前提で読んでください。
前提:2つの検索
- キーワード検索(字面の検索) は、質問の言葉が文書に出てくるかで探します。代表の計算方法が BM25(Best Matching 25)です。Anthropicの記事は、BM25を、TF-IDF(ある言葉が、その文書でどれだけ大事かを測る考え方)の改良と説明しています。文書の長さを考慮し、同じ言葉が何度も出ても点数が青天井にならないようにする(飽和)工夫が入っています。
- ベクトル検索(意味の検索) は、文章を数字の並び(埋め込み、ベクトル)にして、質問に近いものを探します。言葉が違っても意味が近ければ見つかります。
- top-K は、上位K件を取ることです。
- API は、アプリから検索やAIを呼び出す窓口です。
なぜ両方か
Pineconeの文書は、キーワード検索(BM25や疎ベクトル)は、商品コード、エラー文字列、名前のような特定の文字列に合い、ベクトル検索は意味に合う、と説明しています。「それぞれが取りこぼすものを、もう片方が拾う」という趣旨です。
Anthropicの記事の例は分かりやすいものです。技術サポートの資料に対し、「Error code TS-999」と聞くと、ベクトル検索はエラーコード全般の資料を見つけても、「TS-999」そのものを見逃すことがある。BM25はその文字列を探すので見つけられる、という説明です。
論文の側では、BEIR(NeurIPS 2021、18のデータセットでの検索方式の比較)が、BM25を「頑健な基準線」と評価し、再ランキング型と遅延相互作用型(質問と文書を細かい単位で突き合わせる方式)が平均で最良だが計算費用が高い、密なベクトル検索は効率が良いが他の方式より劣ることが多い、と報告しています。これは新しい領域に初めて当てたとき(ゼロショット)の結果で、2021年当時のモデルによるものです。
混ぜ方:スコアを足さず、順位を混ぜる(RRF)
2つの検索は点数の尺度が違います。Pineconeの文書は、BM25と密ベクトルの点数は「比べられない尺度」にあり、そのまま足す・平均するのは意味がなく、片方が支配的になりがち、と書いています。そこで RRF(Reciprocal Rank Fusion、逆順位融合)では、点数ではなく順位を使います。
式は、Elasticの文書でもPineconeの文書でも同じです。各検索の結果の中で、その文書が何位だったかを使って、
点数 = 各検索について 1 ÷(定数k + 順位)を合計する
順位は1位から数えます。その検索の結果に出ない文書は、その検索からは0点です。Pineconeの文書は、元の論文はk=60を使っていたと書いており、Elasticの rank_constant の既定値も60です。kを大きくすると、下位の文書の影響が増える、とElasticの文書は説明しています。
僕らの計算です。k=60で、次の3つの文書があるとします(順位は仮の例です)。
| 文書 | キーワード検索の順位 | ベクトル検索の順位 | RRFの点数 |
|---|---|---|---|
| B | 3位 | 1位 | 1/63+1/61=0.03227 |
| A | 1位 | 5位 | 1/61+1/65=0.03178 |
| C | 2位 | 出ない | 1/62=0.01613 |
片方で1位でも、もう片方に出ないCは低くなります。両方の上位に出るBが一番です。BはAより、片方の1位を持たないのに、両方で上位だったので上回ります。
公式文書のRRFの式と設定
公式文書の例です。この記事では、実行していません。Pineconeの文書にあるPythonの関数です。
def reciprocal_rank_fusion(rankings, k=60):
scores = {}
for ranking in rankings:
for rank, doc_id in enumerate(ranking, start=1):
scores[doc_id] = scores.get(doc_id, 0.0) + 1.0 / (k + rank)
return scores
設定の対応は次のとおりです。
| 製品 | 設定 | 内容 |
|---|---|---|
| Elasticsearch | rank_constant |
既定は60。1以上。大きいほど下位の影響が増える |
| Elasticsearch | rank_window_size |
各検索から取る件数。大きいと関連度が上がるが性能は下がる |
| Pinecone(文書のサンプルコード) | k |
サンプル関数の引数で、既定60。大きいと、1つの検索の上位の支配が弱まる |
| Pinecone(文書のサンプルコード) | fetch_k |
APIの引数ではなく、例の中の変数。混ぜる前に各検索から取る深さで、最終のtop_k以上に |
| OpenAI(ファイル検索) | hybrid_search.embedding_weight、text_weight |
RRFで、意味とキーワードの重みを調整。どちらか一方は0より大きく |
Pineconeの文書(10月22日に読んだ版)は、比較表でハイブリッド検索の形を3つ挙げています。Vectors APIの節では、さらに、密と疎を1つの索引に入れる形と、2つの索引にIDでつなぐ形(別々に検索して、手元で結果を混ぜる)に分けて説明しています。以下は、比較表の3つです。
- 絞ってから順位付け:キーワードの条件で候補を絞り、そこをベクトルで並べる。1回の要求で済み、点数の正規化が不要。
- クライアント側で融合:2つを別々に検索し、RRFで混ぜる。
- サーバー側の組み合わせ:1つの索引に密と疎のベクトルを持たせ、重み(alpha)で調整する。疎の点数には上限がないため、正規化が必要。
並べ替え(リランキング)
仕組み
Sentence Transformersの文書が、2段構えの標準形を説明しています。
- 検索(retrieve): 速い方法(バイエンコーダー=質問と文書を別々にベクトル化する方式、またはBM25)で、100件ほどの候補を取る。
- 並べ替え(re-rank): 遅いが精密な方法(クロスエンコーダー=質問と文書をいっしょにモデルに入れて、関連度を0〜1で出す方式)で、候補を採点し直す。
クロスエンコーダーは、質問と文書の間で注意(どの語に注目するか)を働かせるので、精度が高い。ただし、全文書を採点するのは遅すぎるので、検索で絞った候補にだけ使う、と書かれています。
Nogueiraらの論文(2019)は、BERTによる質問と文章の再ランキングが、MS MARCOの文章検索で当時の最高を、MRR@10(上位10件のうち最初の正解の順位の逆数の平均)で相対27%上回った、と報告しています。BEIRの論文でも、再ランキング型が平均で最良、ただし計算費用が高い、とされています。
実際のAPI
CohereのRerank APIの文書では、質問と文書のリストを渡すと、関連が高い順に並べて返します。
top_n:返す件数。指定しなければ全部返る。max_tokens_per_doc:既定4096。長い文書はここで切られる。- 1回に送る文書は、1,000件までに抑えるよう勧められている。
Anthropicの数字
Anthropicの記事(2024年9月19日)の試験は、複数の領域(コード、小説、論文)、埋め込みの組み合わせで、「上位20件に正解が入らなかった割合」を測りました。
| 構成 | 取りこぼし(上位20件) | 基準からの減り方 |
|---|---|---|
| 文脈なしの埋め込み(基準) | 5.7% | ― |
| 文脈つきの埋め込み | 3.7% | 35%減 |
| 文脈つきの埋め込み+文脈つきBM25 | 2.9% | 49%減 |
| 上の構成+並べ替え(上位150件から20件へ) | 1.9% | 67%減 |
並べ替えにはCohereのモデルを使い、Voyageの再ランク器は試していない、と記事にあります。まとめの項では、「埋め込み+BM25は、埋め込み単独より良い」「並べ替えは、しないより良い」「上位20件を渡すのは、10件や5件より良い」と書かれています。
実務での使い分け(見立てです)
見立てです。以下は、読んだ資料からの整理で、検証したものではありません。
| 状況 | 考え方 |
|---|---|
| 型番、人名、エラーコードで探す場面が多い | キーワード検索を必ず入れる |
| 言い換えや質問文で探す場面が多い | ベクトル検索を中心にして、キーワードを補助に |
| 両方ある | RRFで混ぜる。重みの調整は、まず既定のまま始め、測ってから |
| 上位の質が足りない | 検索で多めに取り(例:50〜150件)、並べ替えで絞る |
| 遅延や費用が厳しい | 並べ替えの対象件数を減らす。Anthropicも、件数と性能に損得がある、と書いている |
日本語では、キーワード検索の質が、文章の切り方(分かち書き)に左右されます。Elasticsearchには日本語用の分析プラグイン(kuromoji)があり、空白で区切らない言語向けにはn-gram(文字を重ねて切る方法)の機能もあります。この選び方でRRFの結果がどう変わるかを比べた資料は、読んだ範囲にありません。
つまずきやすい点
- 点数をそのまま足す。 尺度が違い、片方が支配します。
- 各検索から取る件数が少なすぎる。 Pineconeの文書は、片方で上位でもう片方で圏外の文書を拾うために、最終件数より深く取るよう書いています。
- 並べ替えの入力が長すぎる。 Cohereの既定では、長い文書は4096トークンで切られます。
- 評価せずに重みを動かす。 Anthropicも「必ず評価を行う」と書いています。検索の取りこぼしは、正解のある質問の集まりを作って測れます。
気をつけること
- この記事は、実際に使って確かめた記録ではありません。上記は公式文書と論文の記述です。
- Anthropicの数字は2024年の同社の試験で、当時のモデルと埋め込みによる結果です。日本語の資料での結果は確認できていません。
- 基準の5.7%は「文脈を足さない埋め込み」の値と、僕らは記事の文章から読みました。ハイブリッド(埋め込み+BM25)単独の効果の数字は、記事の本文には書かれていません(グラフにはあります)。
- BEIRは2021年の論文で、当時のモデルによる結果です。
- 元のRRF論文の本文は読んでいません。k=60の記述は、PineconeとElasticの文書によります。
- RRFが常に最良とは限りません。各社の文書は「強い既定値」と述べているだけです。
- 出典のうち、Sentence Transformersのページは、10月22日に取得しても本文が読めませんでした(目次だけが返りました)。BEIRとNogueiraの論文、Elasticsearchの日本語2ページ(kuromoji、n-gram)は取り直していません。これらの確認日は10月8日のままです。
- 製品の設定名や既定値は、変わることがあります。2026年10月22日の確認です(読み直せなかった出典は、各行の確認日のとおりです)。
出典
- Introducing Contextual Retrieval(Anthropic、2024年9月19日、2026年10月22日確認)
- Reciprocal rank fusion(Elasticsearch Reference、Elastic、2026年10月22日確認)
- Similarity settings(Elasticsearch Reference、Elastic、2026年10月22日確認)
- Hybrid search overview(Pinecone Docs、Pinecone、2026年10月22日確認)
- Reciprocal rank fusion(Pinecone Docs、Pinecone、2026年10月22日確認)
- Retrieval(OpenAI API docs、OpenAI、2026年10月22日確認)
- Retrieve & Re-Rank(Sentence Transformers documentation、2026年10月8日確認)
- An Overview of Cohere's Rerank Model(Cohere Docs、2026年10月22日確認)
- Rerank API reference(Cohere Docs、2026年10月22日確認)
- BEIR: A Heterogenous Benchmark for Zero-shot Evaluation of Information Retrieval Models(arXiv:2104.08663、NeurIPS 2021、2026年10月8日確認)
- Passage Re-ranking with BERT(arXiv:1901.04085、Nogueiraら、2026年10月8日確認)
- Japanese (kuromoji) analysis plugin(Elasticsearch Reference、Elastic、2026年10月8日確認)
- N-gram tokenizer(Elasticsearch Reference、Elastic、2026年10月8日確認)
更新履歴
-
2026年10月25日 書き方を直しました。
- 前:運営者が使っていないと読める書き方 → いま:「この記事は、実際に使って確かめた記録ではありません」。公式の資料を読んでまとめた記事で、使い心地は書いていない、という意味に直した
-
2026年10月22日 公式の資料を読み直して、次の点を直しました。
- 前:Pineconeの
kは設定名で、既定60 → いま:文書のサンプルコードの関数の引数で、既定60 - 前:Pineconeの
fetch_kは混ぜる前に各検索から取る深さ → いま:APIの引数ではなく、例の中の変数 - 前:Pineconeの文書はハイブリッド検索に3つの形があるとしている → いま:比較表で3つ挙げ、Vectors APIの節では密と疎を1つの索引に入れる形と、2つの索引にIDでつなぐ形に分けて説明
- 前:Pineconeの
- 一部の出典は読めなかったため、その部分は前のままです。
