A web page has a title, headings, a body, a URL, and the anchor text of links pointing to it. A query word in the title is stronger evidence than the same word in the body, as weighted zone scoring showed for Boolean matches. The obvious way to bring fields into BM25 is to compute a BM25 score for each field separately and add them with weights. Robertson, Zaragoza, and Taylor (2004) showed that this obvious approach is subtly wrong, and proposed BM25F, which combines the fields before the term frequency saturation rather than after. BM25F became the standard way to rank structured documents with BM25 and was central to strong web search results at TREC.
This article explains what goes wrong with the obvious approach, derives the BM25F formula, works a small two-field example by hand, and then traces BM25F on a real index: the search box of this site, which ranks the wiki's articles with BM25F over four fields.
The problem with adding field scores
BM25's term frequency component, $\frac{\mathit{tf}\,(k_1 + 1)}{\mathit{tf} + k_1}$ for a document of average length, saturates. It rises quickly for the first few occurrences and then levels off at $k_1 + 1$. The saturation encodes the idea, from the 2-Poisson model, that once a document is clearly about a term's concept, further occurrences add little.
Adding per-field scores applies the saturation separately in each field. Each field's first occurrence then receives the steep early part of its own curve, and the sum can far exceed what any amount of evidence in a single field could produce. With two fields weighted title 3 and body 1, and $k_1 = 1.2$, the most a term can contribute is $(3 + 1) \times 2.2 = 8.8$ times its IDF under per-field summing, four times the maximum of 2.2 that BM25 allows for one field. A document that mentions a query term once in the title and once in the body is treated as though it contained two independent pieces of evidence, each scored on the steep early part of its own curve. Robertson and colleagues argued that occurrences in different fields are evidence about the same underlying question, whether the document is about the term, and should be combined before the diminishing returns are applied.
The argument from eliteness
The objection can be put in the terms of the 2-Poisson model. There, a document is either elite for a term (it is about the term's concept) or not, and the term frequency is evidence about that hidden property. BM25's saturating curve is an approximation to how strongly a given frequency indicates eliteness. Scoring each field with its own curve and adding the results amounts to assuming a separate eliteness property for each term and field, title-eliteness and body-eliteness, and further assuming that these are independent given relevance. Robertson and Zaragoza (2009, sec. 3.6.1) call this "a little unreasonable". A better assumption is that eliteness belongs to the term and the document, and is shared across fields, while the relationship between eliteness and frequency differs by field: an author who has chosen a topic packs its words far more densely into a title than into body sentences. Under that assumption, the evidence from all fields should be accumulated first, the saturation applied once to the total, and only then the terms combined. That is the order BM25F uses.
What a title occurrence is worth
The difference shows clearly if we ask what a single title occurrence is worth in body occurrences. Take the two-field setting above, with IDF 2.0 and every field of average length:
- Per-field summing. One title occurrence scores $3 \times 2.0 \times \frac{1 \times 2.2}{1 + 1.2} = 6.0$. The body alone can never reach that: its score approaches $2.0 \times 2.2 = 4.4$ as the body frequency grows without limit (4.348 at 100 occurrences). One word in the title outweighs any amount of body text, a ratio no one chose.
- BM25F. One title occurrence adds 3 to the pseudo frequency, so it scores exactly what three body occurrences score, $2.0 \times \frac{3 \times 2.2}{3 + 1.2} = 3.143$. The weight 3 means what it says.
A second title occurrence on top of the first adds 2.250 under summing, more than the first body occurrence (2.000), because the title's curve is multiplied by 3. Under BM25F it adds 0.524, since the shared curve is already flattening.
Adding per-field scores also makes the field weights hard to interpret. The weight multiplies a value that has already been saturated, so it scales the field's maximum contribution along with its first occurrence and has no reading in terms of occurrences. In BM25F, described next, an integer weight has a simple reading: a weight of 3 counts the field as if its text appeared three times (Robertson and Zaragoza, 2009, sec. 3.6.4).
The BM25F formula
BM25F first forms a single pseudo term frequency for each term in each document. It weights each field's frequency and normalizes it by that field's length:
$$\widetilde{\mathit{tf}}_{t,d} = \sum_{f} w_f \, \frac{\mathit{tf}_{t,f,d}}{B_{f,d}}, \qquad B_{f,d} = (1 - b_f) + b_f\, \frac{l_{f,d}}{\bar{l}_f},$$
where $\mathit{tf}_{t,f,d}$ is the number of occurrences of $t$ in field $f$ of document $d$, $w_f$ is the field's weight, $l_{f,d}$ is the field's length in $d$, $\bar{l}_f$ is the average length of that field across the collection, and $b_f$ is a per-field length normalization parameter. The score then applies the saturation once:
$$\mathrm{BM25F}(d, q) = \sum_{t \in q} \mathrm{IDF}(t)\, \frac{\widetilde{\mathit{tf}}_{t,d}\,(k_1 + 1)}{\widetilde{\mathit{tf}}_{t,d} + k_1}.$$
Length normalization has moved inside the field sum, so each field is normalized by its own typical length. A long body and a long title are long in different senses, and a single document-level length would conflate them. The original 2004 proposal normalized by a single document length, the weighted sum of the field lengths. The per-field form shown here was used by Zaragoza and colleagues (2004) at TREC and is the version given by Robertson and Zaragoza (2009), who also omit the $(k_1 + 1)$ factor, which only rescales scores and does not change the ranking.
Checking that it reduces to BM25
Two special cases confirm that the formula generalizes BM25 rather than replacing it.
One field. With a single field of weight 1, the pseudo frequency is $\mathit{tf}/B_d$, and the term score is
$$\mathrm{IDF}(t)\,\frac{(\mathit{tf}/B_d)(k_1 + 1)}{\mathit{tf}/B_d + k_1} = \mathrm{IDF}(t)\,\frac{\mathit{tf}\,(k_1 + 1)}{\mathit{tf} + k_1 B_d},$$
after multiplying the numerator and denominator by $B_d$. Since $k_1 B_d = k_1\left(1 - b + b\,L_d/L_{\mathrm{avg}}\right)$, this is exactly BM25. Dividing the frequency by $B_d$ before saturating is the same as scaling $k_1$ by $B_d$ inside the saturation, which is how the BM25 article writes it.
Integer weights, one shared $b$. In the simpler 2004 version, the pseudo frequency is $\sum_f w_f\, \mathit{tf}_{t,f,d}$ and the document length is the weighted sum $\sum_f w_f\, l_{f,d}$ (Robertson and Zaragoza, 2009, eqs. 3.16 to 3.18). If the weights are integers, this is ordinary BM25 applied to a document in which each field's text has been copied $w_f$ times: the copies multiply both the term's count and the document's length. With per-field $b_f$, as in the formula above, the copying picture no longer holds exactly, but the weights still count occurrences, since each field's frequency is first scaled by its own normalizer and then multiplied by $w_f$.
The IDF
BM25F keeps one IDF per term, computed over whole documents: a term's document frequency counts documents that contain it in any field. Robertson and Zaragoza (2009, sec. 3.6.3) note that this works well in practice but can misbehave when one field is very verbose and contains most terms for most documents, and that the right definition of IDF for fielded documents is an open question.
A worked comparison
Take two fields, title with weight 3 and $b = 0.5$, and body with weight 1 and $b = 0.75$, with $k_1 = 1.2$ and a term with IDF 2.0. Three documents contain the term:
| Document | Title occurrences | Body occurrences | Sum of field scores | Pseudo tf | BM25F |
|---|---|---|---|---|---|
| X | 1 | 1 | 8.000 | 4.000 | 3.385 |
| Y | 0 | 4 | 3.385 | 4.000 | 3.385 |
| Z (body twice the average length) | 1 | 4 | 8.885 | 5.286 | 3.586 |
All fields are of average length except Z's body. Under per-field summing, X scores more than twice as high as Y, because its single title occurrence and single body occurrence each receive the steep first step of a separate saturation curve. Under BM25F, a title occurrence is worth three body occurrences, as the weights say, so X's pseudo frequency of 4 equals Y's, and the two documents score the same. Z has one more title occurrence than Y. Its body is long, so its four body occurrences are discounted by the length normalization. BM25F ranks it a little above X and Y. Per-field summing ranks it about 11 percent above X and far above Y, so the two methods disagree most about Y, the document whose evidence is all in one field.
The intermediate values, rounded to three decimals, are:
- X under summing. Title: $3 \times 2.0 \times \frac{1 \times 2.2}{1 + 1.2} = 6.000$. Body: $2.0 \times \frac{2.2}{2.2} = 2.000$. Sum 8.000.
- X under BM25F. Pseudo frequency $3 \times 1/1 + 1 \times 1/1 = 4$. Score $2.0 \times \frac{4 \times 2.2}{4 + 1.2} = 3.385$.
- Y. One field only, so both methods give $2.0 \times \frac{4 \times 2.2}{4 + 1.2} = 3.385$. When all the evidence is in one field, summing and BM25F agree.
- Z. The body normalizer is $B = 0.25 + 0.75 \times 2 = 1.75$, so the body contributes $4/1.75 = 2.286$ to the pseudo frequency, which is $3 + 2.286 = 5.286$, and BM25F gives $2.0 \times \frac{5.286 \times 2.2}{5.286 + 1.2} = 3.586$. Summing gives the title's 6.000 plus the body's $2.0 \times \frac{4 \times 2.2}{4 + 1.2 \times 1.75} = 2.885$, for 8.885.
BM25F on this site
The search box of this wiki ranks articles with BM25F (app/search.py). It is a small but complete instance. The numbers in this section are a snapshot taken in November 2026, when the index held 152 articles. They come from the live index, so they shift whenever an article is added or edited, and the exact values, counts and even the rankings below may no longer hold for the site as it stands today. The script tools/experiments/search/bm25f_site.py rebuilds the index from the current articles and recomputes every one of them; what the section illustrates, the gap between BM25F and per-field summing, does not depend on the exact values.
Fields and parameters
Each article is split into four fields:
| Field | Contents | Weight $w_f$ | $b_f$ | Average length (tokens) |
|---|---|---|---|---|
| title | the article's title | 12 | 0.5 | 3.8 |
| summary | the one-paragraph summary and the tags | 1 | 0.5 | 54.9 |
| headings | all section headings, joined | 4 | 0.5 | 29.1 |
| body | the text, with math and code removed | 1 | 0.5 | 2,117.2 |
Lengths count stop words, since positions are kept for phrase queries. The weights and $k_1 = 1.2$ were tuned on the first half of a list of known-item queries (tools/search/queries.tsv), in which each query has one article that should come first, and checked on the second half. The implementation follows Robertson and Zaragoza (2009, eq. 3.21) closely: it omits the $(k_1 + 1)$ factor and uses one IDF over whole articles, Lucene's $\ln\left(1 + \frac{N - \mathit{df} + 0.5}{\mathit{df} + 0.5}\right)$. Its term score is therefore
$$\mathrm{IDF}(t)\,\frac{\widetilde{\mathit{tf}}_{t,d}}{k_1 + \widetilde{\mathit{tf}}_{t,d}},$$
which is at most the IDF itself.
The weights look large next to the body's 1, but the title is short. A title of average length (3.8 tokens) has $B = 1$, and one occurrence of a word there adds 12 to the pseudo frequency, which on its own gives a saturation factor of $12/13.2 = 0.91$. A single title word nearly saturates the term, which is what a known-item search wants. Robertson and Zaragoza (2009, eq. 5.1) suggest scaling $k_1$ by the ratio of weighted to unweighted average document length when fields are weighted, since the weights inflate the pseudo frequencies. Here the ratio is $\frac{12 \times 3.8 + 54.9 + 4 \times 29.1 + 2{,}117.2}{3.8 + 54.9 + 29.1 + 2{,}117.2} = 1.06$ (rounded), because the body dominates both sums, so the suggested $k_1$ would be about 1.27, close to the 1.2 the tuning chose.
One term, traced
For the query pagerank, the term occurs in 9 of the 152 articles (one of them this one), so its IDF is $\ln(1 + 143.5/9.5) = 2.779$. In the article PageRank it appears in every field:
| Field | tf | Length | $B_f$ | $w_f\,\mathit{tf}/B_f$ |
|---|---|---|---|---|
| title | 1 | 1 | $0.5 + 0.5 \times 1/3.8 = 0.63$ | 19.04 |
| summary | 3 | 72 | 1.16 | 2.60 |
| headings | 2 | 102 | 2.25 | 3.55 |
| body | 48 | 5,445 | 1.79 | 26.88 |
The pseudo frequency is about 52.1, the saturation factor $52.1/(1.2 + 52.1) = 0.977$, and the term score $2.779 \times 0.977 = 2.72$, close to the ceiling of 2.78. Per-field summing would instead give each field its own factor ($w_f$ times $x/(1.2 + x)$ for that field's normalized frequency $x$) and add them, for a score of 28.3, ten times the ceiling that BM25F respects. For a one-word query the inflation hardly matters, since every article is inflated by the same rule, and both methods put PageRank first. It matters when a query has several words and the inflation favors whichever word happens to appear in many fields.
Where the two methods disagree
The known-item query watch a web page for changes is meant to find Monitoring Websites. After stop-word removal and stemming it has four terms: watch, which is rare (it occurs in 8 articles), and web, page, and chang, which are common. The figure shows each term's contribution to the two leading articles under both methods.
The article Web Crawling contains web in all four fields. Under per-field summing each field contributes its own saturated score, weighted by up to 12, and web, a common term with IDF about 1.23, contributes about 12.2. Under BM25F the same four fields are pooled into one pseudo frequency of about 38, and the term contributes 1.20, just under its IDF. The rare and specific word watch, which occurs only in the body and summary of Monitoring Websites, then decides the ranking, as it should.
Over the whole list of known-item queries (60 at the time of the snapshot), the scoring function makes a visible difference. Comparing three functions with the same parameters, and with the search's rule that puts exact title matches first switched off so that only the scoring differs:
| Scoring | Queries with the target first (of 60) | Mean reciprocal rank |
|---|---|---|
| BM25F, as deployed | 57 | 0.975 |
| Per-field BM25, weighted and summed | 52 | 0.915 |
| BM25 on the four fields concatenated | 50 | 0.904 |
Concatenating the fields throws away the knowledge that a title word matters more than a body word. Summing per-field scores keeps that knowledge but inflates terms that are spread across fields. BM25F keeps the first without the second. The list is small and was used to tune the weights, so the comparison favors the deployed function somewhat, but the per-query failures of the alternatives are of the kinds the theory predicts: common words that appear in many fields of the wrong article, and articles whose titles alone should have decided the ranking.
Saturation has a cost of its own, which appeared after the snapshot as the wiki grew. A term that already saturates in one article's title is near its ceiling of $\text{idf}$, and an article that mentions the same term fifty times in its body is near the same ceiling, so a large title weight cannot separate them. In November 2026 the query bm25 began to rank Comparing Ranking Models above Okapi BM25. The search now adds a small bonus outside the saturation, $2 \times |Q| / |T|$, to an article whose title terms $T$ contain every query term in $Q$, so that the bonus is larger the more of the title the query covers. On the known-item list it fixed bm25 without costing any other query, and the result was the same for any weight from 0.5 to 8 (tools/search/evaluate.py).
Why the browser can rank like the server
Although BM25F combines fields before saturating, it still adds up over query terms: a document's score is a sum of one contribution per term, and each contribution depends only on the term and the document. The site exploits this. When it starts, it precomputes the BM25F contribution of every (term, article) pair and sends those numbers to the browser, whose instant results only add them up (app/static/js/search-core.js). This is the same move as storing precomputed impacts in an index, described in implementing BM25, and it works for BM25F for the same reason.
Choosing the weights
BM25F has more parameters than BM25: a weight and a length normalization parameter for every field, plus $k_1$. They are tuned on queries with relevance judgments, usually by optimizing a measure such as nDCG over a grid or with coordinate search, one parameter at a time. Typical findings give high weights to the title and to anchor text, which are short and written to describe the page, and lower weights to the body. Anchor text is aggregated from all links pointing to a page, so its length varies enormously. Fields of such different lengths were the reason for giving each field its own $b$ (Zaragoza et al., 2004).
The values can be far from BM25's defaults. For the TREC 2003 web tasks, Zaragoza and colleagues reported, for the topic distillation task, $k_1 = 27.5$, title weight 38.4, anchor weight 35, and body weight 1, with $b$ of 0.95, 0.6, and 0.7 for title, anchor, and body; for the named-page task, $k_1 = 4.9$ with title and anchor weights of 13.5 and 11.5 (Robertson and Zaragoza, 2009, Table 3.1). The large $k_1$ goes with the large weights: the weights inflate the pseudo frequencies, so the saturation constant must grow with them for the curve to keep its shape.
With many parameters, a full grid is too expensive. Robertson and Zaragoza (2009, sec. 5.2.1) suggest a schedule that tunes strongly dependent parameters together: first $k_1$ and a single $b$ with all weights 1 (plain BM25), then the field weights jointly, rescaling $k_1$ as described above, then $k_1$ and each $b_f$ one at a time, repeating until nothing improves.
The number of parameters makes overfitting a real risk, and the test collection discipline of tuning on development queries and reporting on separate test queries matters more here than for plain BM25.
Where BM25F is used
BM25F was used in strong submissions to TREC web search tracks in the mid-2000s (Zaragoza et al., 2004), and the idea of combining field frequencies before saturating has carried into production search libraries. Elasticsearch, for example, offers a query type that searches several fields as if they were one combined field, in the spirit of BM25F. In systems that use learning to rank, BM25F scores, or per-field BM25 scores, are common features, so that a learned model can decide how much each field should count.
References
- Robertson, S., Zaragoza, H., and Taylor, M. (2004). Simple BM25 extension to multiple weighted fields. In Proceedings of CIKM 2004, 42โ49.
- Robertson, S., and Zaragoza, H. (2009). The probabilistic relevance framework: BM25 and beyond. Foundations and Trends in Information Retrieval, 3(4), 333โ389.
- Zaragoza, H., Craswell, N., Taylor, M., Saria, S., and Robertson, S. (2004). Microsoft Cambridge at TREC-13: Web and HARD tracks. In Proceedings of the Thirteenth Text REtrieval Conference (TREC 2004).