CodeRigor

LESSON

Evaluate retrieval with labeled queries

Measure precision at a stated cutoff, recall and reciprocal rank against independent relevance labels, including empty and incomplete-result cases.

A plausible result list is not enough evidence that a change improved search. Keep a small set of queries with independently chosen relevant document IDs. Run both versions on the same corpus and queries, then compare named metrics at the same cutoff. The labels should describe a user’s information need; they must not be inferred from whichever documents the current ranker prefers.

We compute three metrics for one query. Precision@k measures relevant results per requested slot. Recall measures the fraction of the judged relevant set that was retrieved. Reciprocal rank measures how soon the first relevant result appeared. A single result list cannot turn reciprocal rank into mean reciprocal rank; the latter requires a defined collection of queries and an averaging policy.

The same result list answers different questions
start / 3
Precision counts useful slots, recall covers a relevant set, and reciprocal rank rewards an early first match.
The same result list answers different questions
Precision counts useful slots, recall covers a relevant set, and reciprocal rank rewards an early first match.

Choose a short-output convention and keep it visible. Here precision@4 for one returned relevant result is 1/4, because three requested slots are unfilled. Other reporting systems may choose a different convention; comparisons are meaningful only when both sides agree. Recall with an empty judgment set is defined as zero in this lab, rather than treating absence of labels as evidence of success.

Python
ranked = ['x', 'b', 'a']
relevant = {'a', 'b', 'c'}
top = ranked[:3]
hits = sum(doc_id in relevant for doc_id in top)
print(round(hits / 3, 3), round(hits / len(relevant), 3))

All three metrics use the same cutoff. If a relevant item appears at position two while k is one, reciprocal rank is zero for this report. Repeated ranked IDs are invalid: returning one relevant document several times must not manufacture several hits. Repeated relevance judgments, however, refer to one relevant identity and collapse into a set.

Judgments have limits. An unjudged document is treated as nonrelevant by this small fixture, but in a large collection that may mean it was never assessed. A few labeled queries establish behavior on those queries, not universal retrieval quality. Keep those cases and labels separate from the implementation so a ranking change cannot quietly rewrite the exam.

A cutoff excludes later evidence
start / 3
A relevant document at rank two does not count in a top-one evaluation.
A cutoff excludes later evidence
A relevant document at rank two does not count in a top-one evaluation.
Python
ranked = ['x', 'a']
relevant = {'a'}
for k in (1, 2):
    first = next((i for i, value in enumerate(ranked[:k], 1) if value in relevant), None)
    print(k, 1 / first if first else 0.0)

Use the build to test fewer-than-k results, no results, no labels, duplicate IDs and a relevant item just beyond the cutoff. In the capstone, preserve the corpus, queries, judgments and scoring convention together. That small reproducible evaluation is a useful starting point for the larger semantic and hybrid retrieval experiments in the optional continuation.

Watch & read

Free lectures, talks and readings that cover this skill from another angle. All resources →

Use the text representation and TF–IDF sections. The lab states its own exact tokenization and weighting conventions.