Key takeaways
- BM25 ranks documents for a keyword query by summing, over query terms, IDF times a saturated, length-normalised term frequency.
- Scores are relative to a query and collection; they have no fixed scale and are not probabilities.
- Classic IDF can go negative for very common terms; Lucene's variant adds one inside the log to avoid it.
- Normalise per query with min-max scaling, or avoid normalising by fusing ranks with reciprocal rank fusion.
- BM25 uses an inverted index; cosine similarity compares vectors, so the two complement each other in hybrid search.
A BM25 score measures how well a document matches a keyword query: for each query term, it multiplies the term's rarity across the collection, its inverse document frequency, by how often the term appears in the document, with diminishing returns and an adjustment for document length, then sums across terms. Higher scores mean better matches for that query. BM25 is the keyword half of hybrid retrieval in RAG.NextUpgrad, so this page covers ranking and scores, calculating them, negative scores, normalisation, indexes, Gensim, cosine similarity and legitimacy.
What is BM25 ranking?
BM25 ranking orders documents by their BM25 score for a query, from most to least relevant. It is the default ranking function in Lucene-based search engines such as Elasticsearch and OpenSearch, and a standard first-stage retriever in RAG systems.
It improves on simple term counting in two ways: repeated occurrences of a word add less and less, so keyword stuffing does not dominate, and long documents are penalised relative to the average length, so short focused documents can rank well. Tuning parameters k1 and b control these effects. BM25 ranks only documents containing at least one query term, which makes it fast and precise for exact words.
What is a BM25 score?
A BM25 score is a number expressing a document's relevance to a specific query within a specific collection. It is relative: a score of 12 means nothing on its own, only that the document ranks above one scoring 8 for the same query.
Also asked as: what is bm25 score · how to normalize bm25 score
Scores depend on the collection's statistics, such as how many documents contain each term and the average document length, so scores from different indexes or queries are not comparable. They are not probabilities and can exceed any fixed range. This is why combining BM25 with vector similarity requires either normalisation or rank-based fusion rather than adding raw scores.
How do I calculate a BM25 score?
For each query term, compute IDF, then multiply by f times k1 plus one, divided by f plus k1 times one minus b plus b times document length over average length, where f is the term's frequency in the document. Sum over query terms.
Also asked as: how to calculate bm25 score
Worked example with k1 of 1.2 and b of 0.75: a term appears in 10 of 1,000 documents, giving IDF of about log of 990.5 over 10.5, plus one in Lucene's variant, roughly 4.56. If it appears 3 times in a document of average length, the term-frequency part is 3 times 2.2 over 3 plus 1.2, about 1.57. The contribution is about 7.2. Repeat for each term and add.
Can a BM25 score be negative?
With the classic Robertson IDF formula, yes: terms appearing in more than half of the documents get negative IDF, which can make scores negative. Many implementations, including Lucene, use a variant that adds one inside the logarithm, keeping IDF and scores non-negative.
Also asked as: can bm25 score be negative
Negative contributions mean a very common term counts slightly against a document, which is rarely useful. If your library produces negative scores, check its IDF formula; you can clip IDF at zero, use the Lucene variant, or remove stop words that appear everywhere. When fusing with other retrievers by rank, the sign of raw scores does not matter.
How do I normalise BM25 scores?
Normalise per query, since scores vary by query: min-max scaling maps the top result to 1 and the lowest retrieved to 0, or divide by the maximum score. Alternatively, avoid score normalisation entirely by fusing result lists with reciprocal rank fusion.
Min-max normalisation is sensitive to outliers and the number of results retrieved, and normalised scores still differ in meaning across queries. Reciprocal rank fusion, which sums one over a constant plus each document's rank in each list, is simpler and robust, which is why many hybrid search systems, including RAG.NextUpgrad, use it. If you need weighted combinations, tune weights on an evaluation set.
How does a BM25 index work?
A BM25 index is an inverted index: for each term, it stores the list of documents containing it, with term frequencies, plus document lengths and collection statistics. At query time, the engine reads only the lists for query terms and scores those documents.
Building the index involves tokenising, normalising and possibly stemming text, then recording postings. Search engines compress postings and use skipping and early termination to score millions of documents quickly. Elasticsearch has used BM25 as its default similarity since version 5. Updates add new postings; deletions are marked and cleaned up during segment merges.
Does BM25 use an inverted index?
Yes, in practice. BM25 is a scoring formula, and inverted indexes are the data structure that makes computing it fast at scale, by looking up only documents that contain the query terms rather than scanning every document.
Also asked as: does bm25 use inverted index
Small experiments, such as the rank_bm25 Python library, compute scores by iterating over all documents in memory, which works for thousands of documents but not millions. For production, use search engines or databases with inverted indexes, such as Elasticsearch, OpenSearch, Lucene-based tools, or Postgres extensions offering BM25. Learned sparse retrieval models also use inverted indexes.
How do I use Gensim BM25 ranking in Python?
Older Gensim versions had a BM25 module in its summarisation package, removed in Gensim 4. Recent Gensim releases include BM25 model classes in its models package for building sparse BM25 representations. Many developers simply use the rank_bm25 library instead.
Also asked as: how to use gensim bm25 ranking in python
With rank_bm25: tokenise documents into word lists, build BM25Okapi(tokenised_docs), then call get_scores or get_top_n with a tokenised query. Keep tokenisation identical for documents and queries. For larger datasets, move to a search engine. If you follow an old tutorial importing gensim.summarization.bm25, it will fail on current Gensim; check your version's documentation.
What is the difference between BM25 and cosine similarity?
BM25 scores lexical matches between a query and documents using term statistics, rewarding exact shared words. Cosine similarity measures the angle between two vectors, typically embeddings that capture meaning, so it matches paraphrases without shared words.
Also asked as: bm25 vs cosine similarity
BM25 excels at exact names, codes and rare terms; cosine similarity over embeddings excels at synonyms and concepts. Cosine can also be applied to TF-IDF vectors, a lexical approach, but in modern RAG it usually means semantic embeddings. Combining both in hybrid search, then reranking with a cross-encoder, gives the most robust retrieval, which is why it is standard in production RAG.
Is BM25 legit?
As an algorithm, yes: BM25 is a well-established, peer-reviewed ranking function from information retrieval research, used for decades in major search engines and still a strong baseline that neural methods must beat. It is legitimate and widely trusted.
If you are asking about a shop or product that happens to use the name BM25, that is unrelated to the algorithm; check independent reviews, company details, return policies and payment protections before buying, as with any online store. Community discussions are useful for experiences, but verify claims through multiple sources.
Sources
- Robertson & Zaragoza, The Probabilistic Relevance Framework: BM25 and Beyond (2009)nowpublishers.com
- Wikipedia, Okapi BM25en.wikipedia.org
- Elastic, Similarity module documentationelastic.co
- Gensim, documentationradimrehurek.com
- Cormack, Clarke & Buettcher, Reciprocal Rank Fusion (2009)plg.uwaterloo.ca
- rank_bm25, repositorygithub.com





