RAG・検索基盤

BM25とは|語の一致だけで数えたら、5問中4問で「総則」が1位になった

BM25とは何をしている計算なのか語の一致だけで数えると何が起きるのかつまみは何を変えるのか

文書を検索して並べるとき、素朴には問いの語がいくつ含まれるかで数えます。ところがこの方式には、はっきりした弱点があります。

あらゆる語を少しずつ含む長い総則を1件混ぜたところ、5問中4問でその総則が1位になりました。BM25に変えると2問まで下がります。

この記事の要点

  • 語の一致だけで数えると、長い総則が5問中4問で1位
  • BM25なら2問まで下がる
  • 長さで割る度合いを上げると3問から2問
  • ただし上位3件の適合率はどちらも46.7%で変わらなかった

語の一致だけで数えたら、5問中4問で「総則」が1位になった

文書13件と問い5件で実際に計算しました。語の一致だけでは総則が4問で1位、BM25では2問に下がります。

BM25が何を直しているのかを、実際に計算して確かめました。用意したのは社内規程を模した文書13件で、うち1件は「あらゆる語を少しずつ含む長い総則」です。

検索は本当に実行しています。文書も問いも正解もコードに書いてあり、そこを変えれば結果も変わります。

javascript
// 語の一致だけで数える素朴な方式
function overlap(qs) {
  const q = new Set(bigrams(qs));
  return tokenized.map((d, i) => ({ i, s: d.filter((w) => q.has(w)).length }))
    .sort((a, b) => b.s - a.s);
}

// BM25。珍しい語を重く、同じ語の繰り返しは頭打ち、長さで割る
const idf = Math.log(1 + (N - n + 0.5) / (n + 0.5));
s += idf * ((f * (k1 + 1)) / (f + k1 * (1 - b + (b * d.length) / avgdl)));
text
問い                  語の一致だけ            BM25
宿泊費の上限は             上位: 12,1,5              上位: 1,5,12
日帰りの日当              上位: 3,9,12              上位: 3,9,12
前払の申請期限             上位: 12,4,6              上位: 12,4,6
備品の購入               上位: 12,7,0              上位: 12,7,0
報告書の提出期限            上位: 12,9,11             上位: 11,9,12

上位3件の適合率  語の一致だけ: 46.7%   BM25: 46.7%

長い総則(12番)が1位になった問い
  語の一致だけ: 4 / 5
  BM25:        2 / 5

b の値  総則が1位  上位3件の適合率  意味
     0      3 / 5           46.7%   長さを無視
   0.3      3 / 5           46.7%   やや補正
  0.75      2 / 5           46.7%   標準的な補正
     1      2 / 5           46.7%   長さで強く割る

12番が総則です。語の一致だけで数えると、5問中4問でこれが1位になりました。どの問いにも答えていないのに、です。

長いほど当たる語が増える

理由は数え方にあります。語がいくつ含まれるかで数えると、語数の多い文書ほど有利になります。

総則は「宿泊費の上限」も「前払の申請」も「備品の購入」も列挙しています。それぞれ1回ずつしか触れていませんが、触れている語の種類だけは多いのです。

BM25で2問に下がる

BM25に変えると4問が2問になりました。「宿泊費の上限は」と「報告書の提出期限」では、本来の正解が1位に上がっています

効いているのは、珍しい語を重く数える部分と、文書の長さで割る部分です。総則は長いぶん割られ、専用の条文は短いぶん残ります

長さで割る度合いを動かす

下の表は、長さで割る度合いを変えたものです。割らない設定では3問、標準的な設定では2問まで下がりました。

Elasticsearchの説明でも、この値は文書の長さが語の出現回数をどの程度打ち消すかを制御するとされています。表の動きは、その説明のとおりです。

変わらなかったもの

公平に書いておくと、上位3件の適合率はどちらも46.7%で変わりませんでした。総則が1位から3位に下がっただけで、上位3件には残っています。

つまりこの規模では、順位は改善しても中身は入れ替わりませんでした。指標の選び方で結論が変わる例にもなっています。指標の違いはnDCGの記事で扱っています。

長い総則が上位を占めるのは、数え方が長さを見ていないから。

単位: 問語の一致だけ4問BM25(長さを無視)3問BM25(標準的な設定)2問問い5件のうち、どの問いにも答えていない総則が1位になった数。上位3件の適合率はいずれも46.7%。
図1 ── 長い総則が1位になった問いの数
出典Elasticsearch Reference「Similarity settings」2026-08-18 確認
b Controls to what degree document length normalizes tf values.
原文Elasticsearch Reference「Similarity settings」 この内容の有効期限2027-02-18

BM25とは何をしている計算なのか

語の出現回数と珍しさ、そして文書の長さの3つから点を付けます。多くの検索製品で既定になっています。

BM25は、問いの語がどれだけ含まれるかを、3つの観点で補正しながら点にする計算です。多くの検索製品で既定の方式になっています。

3つの補正

  1. 珍しい語を重く数える。全文書に出る語は軽く
  2. 同じ語の繰り返しを頭打ちにする。10回出ても2回の5倍にはしない
  3. 文書の長さで割る。長い文書の有利さを消す
  4. 語の並び順を見る。BM25は見ていない

4番目は含まれません。語がどの順で並んでいるかは考えないので、意味の近さを捉える仕組みとは別物です。

既定になっている理由

Elasticsearchの説明では、BM25が既定の方式で、出現回数の補正が組み込まれており、名前のような短い項目でうまく働くとされています。

つまり調整しなくても、そこそこの結果が出る方式です。前の節で見たとおり、語の一致だけで数える方式より明らかに素直に並びます。

2つのつまみ

調整できる値は2つです。同じ文書では、1つは語の出現回数が頭打ちになる度合い、もう1つは文書の長さで割る度合いだと案内されています。

前の節で動かしたのは後者です。長い総則の扱いが、この値で変わりました。

余談 日本語では区切り方のほうが効く

実装してみて感じたのは、BM25の設定より、日本語をどう語に区切るかのほうが結果を左右するということでした。今回は2文字ずつ区切る素朴な方法を使っています。区切り方が変われば、同じ計算でも順位が変わります。文字を揃える処理は日本語正規化の記事で扱っています。

出典Elasticsearch Reference「Similarity settings」2026-08-18 確認
BM25 similarity ( default ) TF/IDF based similarity that has built-in tf normalization and is supposed to work better for short fields (like names).
原文Elasticsearch Reference「Similarity settings」 この内容の有効期限2027-02-18

BM25のつまみをどう扱うか

まず既定のまま測ります。動かすのは、長い文書が上位を占めるといった具体的な症状が出てからです。

BM25には調整できる値がありますが、最初から動かす必要はありません。既定でそこそこ働く方式として設計されています。

症状から入る

動かす判断は、症状から入ります。長い文書ばかり上位に来るなら、長さで割る度合いを上げる。前の節の表が、その動きを示しています。

同じ語を大量に繰り返した文書が上位に来るなら、もう1つの値のほうです。Elasticsearchでも、語の出現回数を頭打ちにする度合いを制御すると説明されています。

動かす前に測る

つまみを動かす前に、問いと正解の組を用意してください。前の節でも、これがなければ「4問から2問に減った」という比較ができません。

測り方はnDCGの記事で扱っています。指標を複数並べて見るのが実際的です。

BM25で解けないもの

語が一致しなければ、BM25は当てられません。「宿泊費」と「ホテル代」のように、違う語で同じことを指す場合は0点になります。

ここは別の仕組みで補います。意味の近さで探す方式と組み合わせる形は、LlamaIndexの記事で扱った文書の分け方とも関わってきます。

既定で動かし、症状が出てからつまみに手を付ける。

充足 2 / 4問いと正解の組を用意してあるこれがないと「4問から2問に減った」という比較ができない症状を見てからつまみを動かしている長い文書が上位に来るなら長さで割る度合い、繰り返しなら頭打ちの度合い語の一致だけで並べているどの問いにも答えていない長い総則が5問中4問で1位になった語が違う言い換えもBM25で拾える語が一致しなければ0点になる。別の仕組みで補う必要がある文書13件・問い5件での実測にもとづく。上位3件の適合率はどちらの方式も46.7%だった。
図2 ── BM25を扱うときの点検項目
出典Elasticsearch Reference「Similarity settings」2026-08-18 確認
k1 Controls non-linear term frequency normalization (saturation).
原文Elasticsearch Reference「Similarity settings」 この内容の有効期限2027-02-18

よくある質問

なぜ長い文書が上位に来るのですか
語の一致だけで数えると、語数の多い文書ほど当たる語も増えるためです。内容が薄くても、あらゆる語を少しずつ含んでいれば上位に出ます。
BM25は何を変えているのですか
珍しい語を重く数え、同じ語が何度出ても効き目が頭打ちになるようにし、文書の長さで割ります。この3つで長い文書の有利さが打ち消されます。
つまみは何を調整するのですか
1つは同じ語が繰り返されたときの効き方、もう1つは文書の長さでどれだけ割るかです。Elasticsearchでも、この2つが選べると案内されています。
上位3件の適合率が変わらないのはなぜですか
この計測では、総則が1位から3位に下がっただけで上位3件には残ったためです。順位は改善しても、上位3件に何が入るかは変わりませんでした。

まとめ

  • BM25は珍しい語を重く、長い文書を軽く数える方式
  • 語の一致だけだと長い総則が5問中4問で1位
  • BM25では2問に下がる
  • 上位3件の適合率はどちらも46.7%で変わらなかった

今日から始められること

  1. 検索の対象に、あらゆる語を含む長い文書がないか探す
  2. その文書が上位に来ていないかを、実際の問いで確かめる
  3. 来ているなら、並べ方が語の一致だけになっていないか調べる
  4. 長さで割る度合いを変えて、順位がどう動くか測る

実務で組んだBM25のワークフローには、値段が付きます

同じ課題を持つ会社にとって、動いている設定は「作る時間」を買えるということです。ServiceDockは自作のワークフローやテンプレートを出品できるマーケットプレイスです。手数料や出品の流れは出品者向けページにまとまっています。

出品の仕組みを見る