SD System Design In Depth
0%
lesson system-designsearch

BM25 production ranking

Module 5.4: Information Retrieval & Search Engines Updated Sep 17, 2026
📄 Cheat Sheet
BM25 : The Most Important Text Metric in Data Science
ritvikmath BM25 : The Most Important Text Metric in Data Science Watch on YouTube ↗

Derives each BM25 term (saturation k1, length normalisation b, IDF) from the shortcomings of TF-IDF with clear plots.

0:00 / --:--
Implementation build

Explore the BM25 scoring algorithm and document length normalization implemented from first principles in Tiny Search Engine (Inverted Index, Compression & BM25).

Under the Hood: Why Okapi BM25 Replaced TF-IDF

While TF-IDF laid the foundation for information retrieval, raw-TF variants grow linearly with repetition, while the logarithmically damped TF taught in the previous lesson grows more slowly. BM25 makes saturation and document-length normalization explicit and tunable. Okapi BM25 (Best Matching 25) introduced non-linear term frequency saturation and tunable document length penalties, becoming the default similarity in Lucene, Elasticsearch and OpenSearch; Vespa offers it as the bm25 rank feature, though its default text ranking is nativeRank.

The BM25 Mathematical Formula

BM25(D, Q) = Σ IDF(qᵢ) × [ (f(qᵢ, D) × (k₁ + 1)) / (f(qᵢ, D) + k₁ × (1 - b + b × (|D| / avgdl))) ]

BM25 Term Frequency Saturation Curve

flowchart LR TFPoints["Term Count: 1 -> 5 -> 10 -> 50 -> 100"] --> BM25Curve["BM25 Score asymptotically approaches (k1 + 1) ceiling!"] TFPoints --> LinearTF["TF-IDF continues climbing indefinitely!"]

Under the Hood: The Parameters k₁ and b

  • Term Saturation Parameter k₁ (Default: ≈ 1.2): Calibrates how quickly the term frequency score saturates. As the count of a keyword in a document increases, its incremental score addition diminishes, preventing keyword-stuffed spam pages from winning ranking.
  • Document Length Normalization b (Default: ≈ 0.75): Penalizes long documents. If a 100,000-word book mentions "Kafka" 5 times, it is far less relevant than a 50-word tweet that mentions "Kafka" 5 times. When b = 1.0, the score is fully scaled by length; when b = 0, length normalization is disabled.

Worked example: saturation and length in numbers

Use the defaults k1 = 1.2 and b = 0.75, with average document length avgdl = 100 terms. The per-term TF component is f x (k1 + 1) divided by f + k1 x (1 - b + b x dl / avgdl). Its ceiling is k1 + 1 = 2.2.

Term count fShort doc, 50 termsAverage doc, 100 termsLong doc, 1,000 terms
11.261.000.21
31.761.570.54
102.051.961.14
1002.192.172.02

Two lessons: going from 10 to 100 mentions barely moves the score, so keyword stuffing stops paying off; and a single mention in a 1,000-term document is worth about one fifth of a mention in an average document.

Multiply by IDF. Lucene uses IDF = ln(1 + (N - n + 0.5) / (n + 0.5)). For N = 1,000,000 and n = 1,000 documents containing the term, IDF is about 6.9; for a term in 400,000 documents it is about 0.4. The rare term still dominates.

Tuning trade-offs

SettingEffectGood for
Lower k1, around 0.5Saturates after one or two mentionsShort fields such as titles and product names
Higher k1, around 2Repetition keeps helping longerLong technical documents
b = 0No length penaltyFields with uniform length, tags
b = 1Full length normalisationCorpora mixing tweets and books

Production notes

  • BM25 has been Lucene's default similarity since Lucene 6 and Elasticsearch 5. Lucene 8 dropped the constant (k1 + 1) factor from the numerator; this rescales scores but does not change ranking.
  • Multi-field search, for example title and body, needs care: BM25F-style combination or per-field boosts, because each field has its own avgdl.
  • Per-shard statistics mean the same document can score slightly differently on different shards until term stats converge.
Check yourself Question 1 of 3
Meaning of b = 0 recall
From: Under the Hood: The Parameters k₁ and b

An engineer sets b = 0 on a BM25 field. What changes compared with the default b = 0.75?

BM25 Search Ranking
Information Retrieval

Key Takeaways

BM25 prevents keyword spam by asymptotically saturating term frequency scores as count increases.
The k1 parameter (~1.2) controls term frequency saturation non-linearity.
The b parameter (~0.75) penalizes verbose, long documents relative to average document length.
Was this lesson helpful? Spot an issue or have a suggestion? Let us know on GitHub.
Report an issue