<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Search on M1KE BL0G</title><link>https://www.m1ke.org/tags/search/</link><description>Recent content in Search on M1KE BL0G</description><generator>Hugo -- gohugo.io</generator><language>ja-jp</language><copyright>mike</copyright><lastBuildDate>Mon, 28 Sep 2026 08:00:00 +0900</lastBuildDate><atom:link href="https://www.m1ke.org/tags/search/index.xml" rel="self" type="application/rss+xml"/><item><title>BM25とLLMを使った検索システムの再考</title><link>https://www.m1ke.org/p/bm25%E3%81%A8llm%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F%E6%A4%9C%E7%B4%A2%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%AE%E5%86%8D%E8%80%83/</link><pubDate>Mon, 28 Sep 2026 08:00:00 +0900</pubDate><guid>https://www.m1ke.org/p/bm25%E3%81%A8llm%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%9F%E6%A4%9C%E7%B4%A2%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E3%81%AE%E5%86%8D%E8%80%83/</guid><description>&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;最近の検索システムは、BM25のような古典的な手法と、LLM・埋め込みモデルのような手法を組み合わせて作ることが多い&lt;/li&gt;
&lt;li&gt;その前提として、まずBM25という手法自体がBag-of-Wordsとどう違うのかを整理する&lt;/li&gt;
&lt;li&gt;その上で、BM25とLLMをどう組み合わせるかというアーキテクチャを再整理する&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bag-of-wordsbowとは"&gt;Bag-of-Words（BoW）とは&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;文書を、単語の出現頻度だけで表現するモデル&lt;/li&gt;
&lt;li&gt;単語の並び順や文法構造は無視し、「どの単語が何回出たか」だけを見る&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;例えば、次の2文をBoWで表現すると、以下のようなベクトルになる。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;文書A: &amp;#34;猫が魚を食べる&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;文書B: &amp;#34;魚が猫を食べる&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;どちらも{猫:1, 魚:1, 食べる:1, が:1, を:1}という同じベクトルになり、語順の違い（誰が誰を食べたか）はBoW表現からは区別できない。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;検索においては、クエリと文書のBoWベクトルの内積やコサイン類似度を取ることで、素朴な関連度スコアを作れる&lt;/li&gt;
&lt;li&gt;ただし、このままでは「は」「が」「の」のような、どの文書にも高頻度で出る単語（ストップワード）が支配的になり、意味のある単語の重みが埋もれてしまう&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tf-idfという改良"&gt;TF-IDFという改良&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Term Frequency（TF）: その文書内での単語の出現頻度&lt;/li&gt;
&lt;li&gt;Inverse Document Frequency（IDF）: その単語が、全文書の中でどれだけ稀かを表す重み&lt;/li&gt;
&lt;li&gt;TF-IDFは、この2つを掛け合わせることで、「この文書に頻出するが、他の文書にはあまり出ない単語」を重視するようにする&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以下のような式で表される。&lt;/p&gt;
$$
\text{tf-idf}(t, d) = \text{tf}(t, d) \times \log\frac{N}{n(t)}
$$&lt;ul&gt;
&lt;li&gt;$\text{tf}(t, d)$：単語$t$の文書$d$内での出現回数&lt;/li&gt;
&lt;li&gt;$N$：全文書数&lt;/li&gt;
&lt;li&gt;$n(t)$：単語$t$を含む文書数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これでストップワード問題はかなり改善するが、TFの部分は依然、出現回数に比例して線形に増加する。つまり、ある単語を10回書いた文書は、1回しか書いていない文書より単純に10倍関連度が高いと評価されてしまう。&lt;/p&gt;
&lt;h2 id="bm25とは"&gt;BM25とは&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;BM25（Okapi BM25）は、TF-IDFをさらに発展させた、Probabilistic Relevance Framework（確率的関連性モデル）に基づくランキング関数&lt;/li&gt;
&lt;li&gt;検索エンジンやElasticsearch・Lucene系のデフォルトスコアリング関数として、実務で広く使われている&lt;/li&gt;
&lt;li&gt;SQLiteに組み込みの全文検索エンジンFTS5も、&lt;code&gt;bm25()&lt;/code&gt;という補助関数でBM25ベースのランキングを提供しており、外部の検索エンジンを立てずに手軽にBM25検索を試せる選択肢になる&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;スコアは、クエリ$Q$に含まれる各単語$q_i$について、次の式の合計として計算される。&lt;/p&gt;
$$
\text{score}(D, Q) = \sum_{i=1}^{n} \text{IDF}(q_i) \cdot \frac{f(q_i, D) \cdot (k_1 + 1)}{f(q_i, D) + k_1 \cdot \left(1 - b + b \cdot \dfrac{|D|}{\text{avgdl}}\right)}
$$&lt;ul&gt;
&lt;li&gt;$f(q_i, D)$：単語$q_i$の文書$D$内での出現回数（TFと同じ）&lt;/li&gt;
&lt;li&gt;$|D|$：文書$D$の長さ、$\text{avgdl}$：コーパス内の文書の平均長&lt;/li&gt;
&lt;li&gt;$k_1$：TFの飽和度を決めるパラメータ（通常1.2〜2.0程度）&lt;/li&gt;
&lt;li&gt;$b$：文書長による正規化の強さを決めるパラメータ（通常0.75程度）&lt;/li&gt;
&lt;li&gt;$\text{IDF}(q_i)$：BM25版のIDF&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;BM25版のIDFは、以下のように定義される。&lt;/p&gt;
$$
\text{IDF}(q_i) = \ln\left(\frac{N - n(q_i) + 0.5}{n(q_i) + 0.5} + 1\right)
$$&lt;h3 id="tfの飽和の役割"&gt;TFの飽和（$k_1$の役割）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;BoW・単純なTFでは、出現回数がそのままスコアに比例する&lt;/li&gt;
&lt;li&gt;BM25では、$f(q_i, D)$が分母にも登場するため、出現回数が増えるほどスコアの増加が徐々に緩やかになる（飽和する）&lt;/li&gt;
&lt;li&gt;直感的には、「同じ単語を1回書くのと2回書くのとの差」は大きいが、「50回書くのと51回書くのとの差」はほとんど意味がない、という考え方を反映している&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="文書長の正規化の役割"&gt;文書長の正規化（$b$の役割）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;長い文書は、単語の出現回数がただ長いという理由だけで多くなりやすい&lt;/li&gt;
&lt;li&gt;$b$は、文書長が平均より長い場合にスコアを下げ、短い場合に相対的に有利にしすぎないよう調整する&lt;/li&gt;
&lt;li&gt;$b=0$なら文書長による補正なし、$b=1$なら文書長に完全に比例した補正になる&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bowとbm25の違い"&gt;BoWとBM25の違い&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;観点&lt;/th&gt;
&lt;th&gt;Bag-of-Words（生TF）&lt;/th&gt;
&lt;th&gt;BM25&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;出現回数の扱い&lt;/td&gt;
&lt;td&gt;線形に増加&lt;/td&gt;
&lt;td&gt;$k_1$により飽和する&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;文書長の補正&lt;/td&gt;
&lt;td&gt;なし&lt;/td&gt;
&lt;td&gt;$b$により正規化する&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;単語の重み&lt;/td&gt;
&lt;td&gt;均一（IDFなし）&lt;/td&gt;
&lt;td&gt;IDFで単語の稀さを重視&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;理論的基盤&lt;/td&gt;
&lt;td&gt;特になし&lt;/td&gt;
&lt;td&gt;確率的関連性モデルに基づく&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="具体例で比較する"&gt;具体例で比較する&lt;/h2&gt;
&lt;p&gt;クエリを「猫」とし、次の2つの文書を考える。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;文書A: 「猫」を5回繰り返した、長さ5の文書&lt;/li&gt;
&lt;li&gt;文書B: 「猫が座っている机の上」のような、長さ6で「猫」が1回だけ出る文書&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$k_1=1.5$、$b=0.75$、コーパスの平均文書長$\text{avgdl}=5.5$とし、IDFは共通なのでTFの部分だけを比較する。&lt;/p&gt;
&lt;p&gt;生TF（BoW）で比較すると、文書Aは文書Bの5倍のスコアになる。&lt;/p&gt;
$$
\text{文書A（生TF）} = 5, \qquad \text{文書B（生TF）} = 1
$$&lt;p&gt;一方、BM25のTF部分を計算すると、次のようになる。&lt;/p&gt;
$$
\text{文書A} = \frac{5 \times (1.5+1)}{5 + 1.5\left(1-0.75+0.75\times\frac{5}{5.5}\right)} \approx \frac{12.5}{6.40} \approx 1.95
$$$$
\text{文書B} = \frac{1 \times (1.5+1)}{1 + 1.5\left(1-0.75+0.75\times\frac{6}{5.5}\right)} \approx \frac{2.5}{2.60} \approx 0.96
$$&lt;ul&gt;
&lt;li&gt;BoWでは5倍だった差が、BM25では約2倍に縮まっている&lt;/li&gt;
&lt;li&gt;「猫」を5回連呼した文書が、1回しか言及していない文書より多少有利にはなるが、5倍も関連度が高いわけではない、という直感をBM25が反映している&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bm25の限界-語彙のミスマッチ問題"&gt;BM25の限界: 語彙のミスマッチ問題&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;BM25はあくまで、クエリと文書の間で単語が一致するかどうかに基づくスパース検索（lexical retrieval）&lt;/li&gt;
&lt;li&gt;「車」と「automobile」、「猫」と「ネコ」のような同義語・表記の違い・言い換えには対応できない&lt;/li&gt;
&lt;li&gt;クエリの単語が文書に一字一句含まれていなければ、意味的には関連していてもスコアが付かない&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ここでLLM・埋め込みモデルの出番になる。&lt;/p&gt;
&lt;h2 id="llmによる密検索dense-retrieval"&gt;LLMによる密検索（Dense Retrieval）&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;クエリと文書を、LLMベースの埋め込みモデル（bi-encoder）でベクトル化し、ベクトル空間上の距離（コサイン類似度など）で関連度を測る&lt;/li&gt;
&lt;li&gt;単語の一致ではなく、意味的な近さで検索できるため、同義語や言い換えにも対応できる&lt;/li&gt;
&lt;li&gt;代表的な手法としてDense Passage Retrieval（DPR）などがある&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;BM25（スパース検索）とDense Retrieval（密検索）は、得意なものが対照的になる。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;観点&lt;/th&gt;
&lt;th&gt;BM25（スパース）&lt;/th&gt;
&lt;th&gt;Dense Retrieval（密）&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;得意なこと&lt;/td&gt;
&lt;td&gt;固有名詞・専門用語の完全一致&lt;/td&gt;
&lt;td&gt;同義語・言い換え・意味的な近さ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;弱いこと&lt;/td&gt;
&lt;td&gt;語彙のミスマッチ&lt;/td&gt;
&lt;td&gt;稀な固有名詞・数値などの厳密な一致&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;計算コスト&lt;/td&gt;
&lt;td&gt;軽い（転置インデックス）&lt;/td&gt;
&lt;td&gt;埋め込み計算・ベクトル検索が必要&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="ハイブリッド検索"&gt;ハイブリッド検索&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;BM25とDense Retrieialを両方使い、それぞれのスコア・順位を統合するのがハイブリッド検索&lt;/li&gt;
&lt;li&gt;統合方法の一つがReciprocal Rank Fusion（RRF）で、各手法での順位の逆数を合計してスコアにする&lt;/li&gt;
&lt;/ul&gt;
$$
\text{RRF}(d) = \sum_{r \in \text{ランキング群}} \frac{1}{k + \text{rank}_r(d)}
$$&lt;ul&gt;
&lt;li&gt;$\text{rank}_r(d)$：ランキング手法$r$における文書$d$の順位、$k$は定数（60程度がよく使われる）&lt;/li&gt;
&lt;li&gt;スコアのスケールが違う手法同士でも、順位ベースなので単純に統合できるのが利点&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="llmによるリランキング"&gt;LLMによるリランキング&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;BM25・Dense Retrievalで絞り込んだ上位数十〜数百件の候補に対し、より高精度だが計算コストの高いモデルで再順位付けするのがリランキング&lt;/li&gt;
&lt;li&gt;クエリと候補文書のペアをまとめて入力するCross-Encoderや、LLMに直接「どちらがより関連しているか」を判断させるLLM-as-a-judge方式などがある&lt;/li&gt;
&lt;li&gt;候補全件に適用するのは計算コストが高いため、まず軽量なBM25・Dense Retrievalで絞り込み、上位のみをリランキングするという2段構成が一般的&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="ragとの関係"&gt;RAGとの関係&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Retrieval-Augmented Generation（RAG）は、この「検索して、上位の文書をLLMのプロンプトに含めて生成する」というパイプライン全体を指す&lt;/li&gt;
&lt;li&gt;検索の精度が低ければ、無関係な文書がプロンプトに混ざり、LLMの生成結果も悪化する&lt;/li&gt;
&lt;li&gt;つまりRAGの品質は、生成モデル自体の性能だけでなく、BM25・Dense Retrieval・リランキングを含む検索パイプライン全体の設計に大きく依存する&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="まとめ"&gt;まとめ&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Bag-of-Wordsは単語の出現頻度だけを見る素朴な表現で、出現回数に比例してスコアが線形に増える&lt;/li&gt;
&lt;li&gt;TF-IDFはIDFで単語の重要度を重み付けするが、TF自体は依然線形&lt;/li&gt;
&lt;li&gt;BM25は$k_1$でTFの増加を飽和させ、$b$で文書長を正規化する、確率的関連性モデルに基づくランキング関数&lt;/li&gt;
&lt;li&gt;BM25はあくまで単語の一致に基づくスパース検索で、同義語・言い換えには弱い&lt;/li&gt;
&lt;li&gt;LLMベースの埋め込みによる密検索は意味的な近さで検索でき、BM25と相補的な関係にある&lt;/li&gt;
&lt;li&gt;両者をRRFなどで統合するハイブリッド検索や、上位候補をLLMで再順位付けするリランキングが、実務でよく使われる構成&lt;/li&gt;
&lt;li&gt;この検索パイプライン全体の精度が、RAGの生成品質を直接左右する&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="参考文献"&gt;参考文献&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Robertson, S., &amp;amp; Zaragoza, H. (2009). &amp;ldquo;The Probabilistic Relevance Framework: BM25 and Beyond&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Robertson, S. E., &amp;amp; Sparck Jones, K. (1976). &amp;ldquo;Relevance weighting of search terms&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Karpukhin, V. et al. (2020). &amp;ldquo;Dense Passage Retrieval for Open-Domain Question Answering&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Cormack, G. V., Clarke, C. L., &amp;amp; Buettcher, S. (2009). &amp;ldquo;Reciprocal Rank Fusion outperforms Condorcet and individual Rank Learning Methods&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Lewis, P. et al. (2020). &amp;ldquo;Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>