Content scoring tools still tell you to use a term "8–12 times." The advice survives because term frequency genuinely is a ranking input in lexical retrieval. What the advice gets wrong is the shape of the curve. In BM25 — the default scoring function in Lucene, Elasticsearch, OpenSearch, and most hybrid retrieval stacks — term frequency is deliberately saturated, so the fifth mention is worth a fraction of the first and the twelfth is worth close to nothing.
Worse, the same formula contains a length penalty. Padding a page to hit a word count target can lower its score for the term you were trying to rank. If you understand the two knobs that produce this behavior, you can reason about any lexical scorer you encounter, including the ones inside your site search and your RAG pipeline.
What BM25 actually computes
For a query q and document d, BM25 sums a weight per query term:
score(q,d) = Σ IDF(qi) · [ f(qi,d) · (k1 + 1) ]
/ [ f(qi,d) + k1 · (1 − b + b · |d|/avgdl) ]
Three parts matter:
- IDF(qi) — inverse document frequency. Rare terms carry more weight than common ones. This factor usually dominates the score.
- f(qi,d) — raw count of the term in the document, passed through a saturating function controlled by
k1. Lucene's default isk1 = 1.2. - |d|/avgdl — this document's length divided by the average document length in the index, scaled by
b. Lucene's default isb = 0.75.
Note what is not in there: no keyword density, no ratio of term count to word count. Length enters only as a comparison against the rest of the corpus, and frequency enters only through a curve that flattens.
Why the twelfth mention is worth almost nothing
Ignore length for a moment and look at the saturation factor alone, f / (f + k1), expressed as a share of the maximum weight that term could ever contribute:
| Occurrences | Share of max term weight | Gain over previous row |
|---|---|---|
| 1 | 45% | — |
| 2 | 63% | +18 pts |
| 3 | 71% | +8 pts |
| 5 | 81% | +10 pts (over 2 more) |
| 10 | 89% | +8 pts (over 5 more) |
| 20 | 94% | +5 pts (over 10 more) |
The first occurrence buys you nearly half of everything that term can contribute. Going from ten mentions to twenty buys five percentage points of one term's weight — and that weight is then multiplied by IDF, so for a common term it is five percent of a small number.
The practical consequence: matching an additional distinct query term beats repeating one you already match. A document that contains a rare term once gets a full IDF-weighted 45% of that term's ceiling. A document that repeats a common term fifteen times is grinding against an asymptote. This is why pages that cover the surrounding vocabulary of a topic retrieve better than pages that hammer one phrase, and the reason is arithmetic, not a semantic-understanding story.
How length normalization punishes padding
With b = 0.75, the denominator scales with |d|/avgdl. A document twice the average length needs roughly twice the term frequency to achieve the same saturation level. Three times the average length, roughly three times the frequency.
So if you add 800 words of filler to a 600-word page and do not add any new occurrences, the page's score for its target term goes down. Not metaphorically — the denominator grows and the ratio shrinks.
Two things follow:
- "Average length" is corpus-relative. In an index of short product descriptions, a 1,200-word page is heavily penalized. In an index of research papers, it is short. There is no universal good length; there is only length relative to
avgdlin the index doing the retrieval. - Chunking changes the denominator. When a long page is split into passages before indexing, each chunk is scored as its own document against a much smaller
avgdl. The same text can score very differently depending on whether it is indexed whole or in pieces.
Does Google use BM25?
Google has never confirmed that BM25 is part of its ranking stack, and nobody should claim it is. What is documented is that Google uses many signals and that systems have moved well past single-formula lexical scoring.
The transferable part is the property, not the formula. Any sane lexical scorer saturates term frequency and normalizes for length, because without those two corrections the top result for every query is the longest page that repeats the query most. The reasonable inference is that repetition hits diminishing returns in any production retrieval system — but treat that as inference, and treat the specific numbers above as true of Lucene-family scorers, which you can verify directly.
Where this runs in systems you control
You are probably operating at least one BM25 index already:
- Site search on Elasticsearch, OpenSearch, Solr, or Typesense.
- Hybrid retrieval in a RAG application — nearly every vector database now pairs dense search with a BM25 or sparse lexical arm.
- Internal tooling that ranks documents, tickets, or product records.
In Elasticsearch you can read the exact per-term contribution rather than guessing:
GET /pages/_search
{
"explain": true,
"query": { "match": { "body": "hybrid retrieval" } }
}
The explain output breaks the score into IDF, the saturated frequency term, and the length normalization factor for each query term. Run it on two of your own pages and the density advice dies on contact.
How hybrid retrieval combines lexical and vector scores
BM25 scores are unbounded and corpus-dependent; cosine similarities sit in a narrow band. Adding them directly is meaningless, so most hybrid systems fuse ranks instead of scores using reciprocal rank fusion:
RRF(d) = Σ 1 / (k + rank_i(d))
Elasticsearch's RRF implementation defaults to a rank constant of 60. The behavioral consequence is specific: a document that places mid-pack on both arms often outranks a document that is first on one arm and absent from the other. Being lexically perfect but semantically off-topic — or vice versa — is a weak position in a fused system.
What to do with this
- Stop optimizing frequency past about three occurrences. Everything after that is sub-point noise on one term.
- Spend the effort on distinct vocabulary instead. New matching terms start at 45% of their ceiling; repeats start at 2%.
- Check
avgdlin any index you control before deciding a target length. In Elasticsearch, field length statistics are visible through the explain output and index stats. - Do not pad. Filler raises the length denominator and dilutes the terms you care about, in BM25 and in any chunk-level retrieval that follows.
- Tune chunk size against your query length, since chunking resets what "long" means for scoring.
- If you run hybrid retrieval, measure both arms separately before blaming the fusion step. A document missing from the lexical arm entirely is a tokenization or analyzer bug, not a relevance problem.