Concepts / Term-Based Retrieval with BM25

Term-Based Retrieval with BM25

Term extraction is faster than generating an embedding, and looking up which documents contain a term can be cheaper than a nearest-neighbor search.

  • Programming

Why Scanning Every Vector Gets Expensive

Imagine a collection of embeddings large enough that comparing a query against every stored vector is slow. Each comparison is cheap on its own, but multiplied across millions of stored items, the cost of answering one query grows quickly. Vector search algorithms exist to avoid that full comparison. Instead of checking everything, they organize the stored vectors ahead of time so that a query only needs to look at a promising subset.

The trade-off is that the answer becomes approximate. The search may skip some vectors that a full scan would have found. Two of the best-known strategies for this are IVF and Annoy. IVF groups similar vectors into clusters and searches only the clusters that look promising. Annoy builds several random tree structures and gathers candidates from the places a query lands in them. Both accept a small loss of exactness in exchange for a large gain in speed.

Grouping Vectors Into Clusters

An IVF index is built by grouping. Each stored vector is placed into one cluster, so that vectors near one another in the embedding space tend to share a cluster. The grouping is what lets a query skip most of the database. The index is organized by cluster rather than by individual vector, which means the search can reason about whole groups at once.

IVF indexstored vectors groupedCentroid 1closest to queryCluster 1 vectorsv1, v4, v7Query vectorCentroid 2not searchedCluster 2 vectorsv2, v5Centroid 3not searchedCluster 3 vectorsv3, v6, v8K-means centroidsnearest centroidmembers
Which vectors does a query actually compare against once the index is partitioned into clusters, and how does the query pick which cluster to search? The vector labels below are invented to show the shape of the structure.

The diagram above uses invented vector labels. The highlighted cluster is the one whose centroid sits closest to the query. The other clusters stay unsearched, which is where the speed comes from.

Tracing an IVF Query Step by Step

Worked example

Searching a three-cluster IVF index

An index holds eight vectors, split into three clusters with centroids C1, C2, and C3. A new query is closest to C2. Which vectors does the search compare against the query?

  1. 1
    Compare the query with the centroids

    The search measures how close the query is to C1, C2, and C3. These three comparisons are cheap compared with checking all eight stored vectors.

  2. 2
    Select the closest centroid

    The query is closest to C2, so cluster 2 is the one the search will examine.

  3. 3
    Gather the members of that cluster

    Cluster 2 holds v2 and v5 in this invented example. Those two vectors are compared with the query.

  4. 4
    Skip the other clusters

    The members of cluster 1 (v1, v4, v7) and cluster 3 (v3, v6, v8) are not compared. If one of them was a true close match, the approximate search can miss it.

Result

Only v2 and v5 are compared directly. Six of the eight stored vectors are skipped, which is the source of IVF's speed and of its approximate character.

What do you think happens?

Given the query is closest to C2, which vectors are compared against the query?

  • All eight stored vectors

  • Only the vectors in cluster 2

  • Only the centroids themselves

  • One vector from each cluster

Reveal answer
Answer:

Only the vectors in cluster 2

IVF searches the clusters whose centroids are closest to the query. The vectors in the other clusters are not compared with the query.

Collecting Candidates with Annoy Trees

Annoy, which stands for Approximate Nearest Neighbors Oh Yeah, takes a different route from IVF. It is a tree-based approach introduced by Bernhardsson in 2013. Rather than computing centroids, Annoy builds a number of binary trees. Each tree divides the vectors using random criteria. One simple way to picture a split is to draw a random line through the space, send the vectors on one side into one branch, and send the vectors on the other side into the other branch. Repeating this splitting produces a tree whose leaves hold groups of vectors.

Query vectorTree 1 root splitrandom splitTree 1 leafv1, v4Candidate setv1, v2, v4Tree 2 root splitdifferent random splitTree 2 leafv2, v4traversetraverselands inlands inmergedmerged
How does one query traverse several independently built random trees, and how do the leaves reached in each tree merge into one candidate set? The vector labels are invented.

The diagram shows the idea with invented labels. Annoy does not rely on one tree. It builds several trees, each with its own random splits. During a search, the algorithm traverses these trees and gathers candidate neighbors from the leaves the query reaches. Because each tree splits the space differently, a neighbor missed by one tree may be caught by another. In the diagram, v4 appears in both leaves, while v1 and v2 each come from only one tree. Combining several trees improves the chance of collecting the true close matches.

Annoy is also a practical example of industrial use. Spotify has open sourced its implementation of the approach. The same broad goal is shared by other libraries the source names, namely SPTAG, which stands for Space Partition Tree And Graph and comes from Microsoft, and FLANN, which stands for Fast Library for Approximate Nearest Neighbors. You do not need to memorize their internals to see the pattern: each one trades a small amount of exactness for a large gain in speed.

Term-Based and Embedding-Based Retrieval Compared

Long before embeddings, retrieval relied on matching terms, and that history has produced many mature solutions. This is why both term-based and embedding-based retrieval are relatively easy to start with. Each approach has strengths, and the trade-offs the source describes can be laid out side by side.

DimensionTerm-based retrievalEmbedding-based retrieval
SpeedGenerally faster, since term extraction is quicker than generating an embedding and term lookup can be cheaper than a nearest-neighbor searchGenerally slower because each item needs an embedding and a nearest-neighbor search
Out-of-the-box useWorks well out of the boxUsable from the start, but its strengths appear after adaptation
TuningThe source does not describe a tuning path for term-based retrievalCan be improved over time, and the source notes it can be tuned to outperform term-based retrieval
Keyword handlingMatches exact terms directlyCan blur exact strings, so specific values such as EADDRNOTAVAIL (99) may be harder to find

Trade-offs between term-based and embedding-based retrieval, as described in the source

Speedgenerally fasterSpeedembedding and search costOut of the boxworks wellOut of the boxusable from the startKeyword handlingexact term matchTuningcan be improvedKeyword handlingmay blur exact strings
How do term-based and embedding-based retrievers differ side by side on speed, setup effort, tuning needs, and handling of exact keywords?

Keyword Handling and the EADDRNOTAVAIL Case

The speed gap has a clear cause. Term extraction is faster than generating an embedding, and looking up which documents contain a term can be cheaper than a nearest-neighbor search. The strength of embedding-based retrieval is that it can be improved over time. Its weakness is that embeddings can blur exact strings. A specific error code such as EADDRNOTAVAIL (99) can therefore become harder to find later on.

Measuring Retrieval Quality

A retriever is judged by the quality of the data it returns. Two metrics are often used by RAG evaluation frameworks: context precision and context recall, often called precision and recall for short. The source notes that context precision is also called context relevance. Precision asks how much of what was retrieved is actually relevant. Recall asks how much of the relevant material was retrieved at all.

Precisionrelevant share of retrievedRecallretrieved share of relevantDenominatoreverything retrievedDenominatoreverything relevant
How do the retrieved set and the set of truly relevant documents overlap, and which part of that overlap does precision measure versus recall?

These two measures are the natural way to judge an approximate method such as IVF or Annoy, because those methods can trade a missed neighbor for speed. A search that skips clusters or trees may return fewer irrelevant items, which helps precision, yet it may also miss relevant items, which hurts recall.

Worked example

Scoring one retrieval result

A retriever returns four documents for a query. Three of those four are relevant. In total, six documents in the collection are relevant to the query. What are the precision and recall of this result?

  1. 1
    Count the relevant items retrieved

    Three of the four returned documents are relevant.

  2. 2
    Compute precision

    Precision looks at what was retrieved. Three out of four retrieved documents are relevant, which is a precision of 75 percent.

  3. 3
    Compute recall

    Recall looks at what should have been found. Three out of the six relevant documents were retrieved, which is a recall of 50 percent.

  4. 4
    Interpret the pair

    The results are fairly clean, but half of the relevant material was missed. An approximate search that skipped a cluster could produce exactly this pattern.

Result

Context precision is 75 percent and context recall is 50 percent for this invented example.

Common Mistakes When Reading Approximate Search

  • Common mistake

    Assuming an IVF search compares the query with every stored vector

    What it looks like

    Treating a three-cluster index as if all eight vectors are checked for every query

    Why it fails

    IVF searches only the clusters whose centroids are closest to the query, so the other clusters are never compared directly.

    Do this instead

    Compare the query with centroids first, then search the members of the chosen clusters.

  • Common mistake

    Believing one Annoy tree is enough to find every close neighbor

    What it looks like

    Using a single random tree and expecting the leaf it reaches to hold all true neighbors

    Why it fails

    Each tree splits the space differently, and a neighbor missed by one tree may be caught by another.

    Do this instead

    Build multiple trees and gather candidates from the leaves the query reaches in each one.

  • Common mistake

    Using embedding-based retrieval alone for exact error codes

    What it looks like

    Searching for EADDRNOTAVAIL (99) and expecting a meaning-level match to return it reliably

    Why it fails

    Embeddings can blur exact strings, so the specific code can become harder to find.

    Do this instead

    Combine embedding-based retrieval with term-based retrieval, as the source suggests.

  • Common mistake

    Judging a retriever by precision alone

    What it looks like

    Returning two very relevant documents and calling the retriever excellent without checking how many relevant documents exist

    Why it fails

    Precision says nothing about relevant documents that were never retrieved, which is what recall measures.

    Do this instead

    Report context precision and context recall together.

Practice Tracing Candidates

EASY

A three-cluster IVF index has clusters with members {v1, v4}, {v2, v5, v6}, and {v3, v7, v8}. A query is closest to the centroid of the second cluster. List which vectors are compared with the query, and say how many comparisons were skipped out of the eight stored vectors.

Hints
  • First identify which centroid the query is closest to, then list only that cluster's members.
  • Compare the number of members you listed with the total of eight stored vectors.
MEDIUM

A retriever returns five documents for a query. Four are relevant. Eight documents in the collection are relevant overall. Compute context precision and context recall, then explain which one is lower and what that suggests about the search.

Hints
  • Precision uses the five retrieved documents as the denominator.
  • Recall uses the eight relevant documents as the denominator.

Key Takeaways

  • IVF groups stored vectors into clusters with K-means, then searches only the clusters whose centroids are closest to the query, so most vectors are never compared directly.
  • Annoy builds several random binary trees, and a query gathers candidate neighbors from the leaves it reaches in each tree, so a neighbor missed by one tree may be caught by another.
  • Term-based retrieval is generally faster and works well out of the box, while embedding-based retrieval can be tuned to improve but may blur exact keywords, so combining both is a common remedy.
  • Context precision measures how much of what was retrieved is relevant, while context recall measures how much of the relevant material was retrieved, and together they judge approximate methods.

Related concepts

More concepts starting with T