BM25 ranking
Lesson: Information Retrieval and SearchCheat sheetTrack: RAG building blocks
Problem
BM25 is the standard ranking function for keyword search. It gives a high score to a document that contains rare query terms many times, and it corrects for the length of the document. Hybrid retrieval pipelines run BM25 next to a dense vector search.
Task
Write three functions. The documents and the query are lists of tokens that are already tokenized.
idf(corpus, term)returns the inverse document frequency of one term.bm25_scores(corpus, query, k1=1.5, b=0.75)returns the BM25 score of each document for the query.rank(corpus, query, top_k, k1=1.5, b=0.75)returns the indices of thetop_kdocuments with the highest scores.
Let N be the number of documents. Let n(t) be the number of documents that contain the term t at least once. Use this idf:
Let f(t, d) be the number of times t occurs in document d. Let |d| be the number of tokens in d, and \mathrm{avgdl} the mean of |d| over all documents. The score of document d is
The sum runs over the query list. A term that occurs twice in the query adds its weight twice. A term with f(t, d) = 0 adds nothing.
Tie rule: rank sorts the scores from high to low. When two documents have the same score, the document with the lower index comes first.
Input and output
| Name | Type | Shape | Meaning |
|---|---|---|---|
corpus | list of lists of str | N documents | the tokens of each document |
query | list of str | any length | the query tokens, repeats allowed |
term | str | scalar | one token |
k1 | float | scalar | the term frequency saturation, default 1.5 |
b | float | scalar | the length normalization weight from 0 to 1, default 0.75 |
top_k | int | scalar | the number of indices to return |
idfreturns a Pythonfloat.bm25_scoresreturns a float array of shape(N,). Entryiis the score of documenti.rankreturns a list oftop_kint document indices, best first.
Constraints
1 <= N <= 200and each document has at most 200 tokens.- A document can be empty, but at least one document has a token.
0 <= b <= 1,k1 > 0and1 <= top_k <= N.- Do not change the corpus or the query.
- Use Python and numpy only.
Examples
pythoncorpus = [
["the", "cat", "sat"],
["the", "dog", "sat", "on", "the", "mat"],
["cat", "cat", "food"],
["dogs", "and", "cats"],
]
idf(corpus, "cat"), idf(corpus, "zebra")text(0.6931471805599453, 2.302585092994046)pythonbm25_scores(corpus, ["cat", "sat"])text[1.5234004 0.54578518 1.05823997 0. ]pythonrank(corpus, ["cat", "sat"], 3)text[0, 2, 1]Document 3 contains cats, not cat. Tokens must match exactly, so its score is 0.
Hints
4 hintsSolution and notes
LockedPass every check with Submit to open the reference solution and the notes.
Run it on your computer
Clone the repository, install numpy and run the same checks in a terminal:
python3 scripts/practice/run.py bm25 my_answer.py
python3 scripts/practice/run.py bm25 my_answer.py --examplesStart my_answer.py from starter.py.
Your code is saved in this browser as you type. On a phone you can read and edit the code, but the checks are easier to use on a desktop.
Keyboard shortcuts
- Ctrl Enter
- Run the examples
- Ctrl Shift Enter
- Submit
- Tab / Shift Tab
- Indent or outdent the lines
- Esc then Tab
- Move the focus out of the editor
- Alt H
- Show the next hint
On a Mac, use Cmd in place of Ctrl.
Select Run to check the examples, or Submit to run every check.