Back to Practice

store_nodes() for BM25 hybrid

Completion

In this exercise, you will implement a hybrid retriever that combines dense embeddings with BM25 sparse retrieval using Reciprocal Rank Fusion (RRF). The key challenge is that when using Qdrant as the vector store, index.docstore.docs is empty—nodes must be scrolled back from the vector store via the store_nodes() utility provided in the codebase. Your task is to complete the build_fusion_retriever function that:

  1. Calls store_nodes(index) to hydrate the full corpus as a list of BaseNode objects.
  2. If the node list is empty, falls back to returning the dense_retriever unchanged.
  3. Builds a BM25Retriever from those nodes using from_defaults() with similarity_top_k set to sparse_top_k (computed as min(top_k, len(node_list)) to avoid corpus-size issues).
  4. Creates a QueryFusionRetriever with mode="reciprocal_rerank" and num_queries=1 (no LLM expansion) that fuses dense_retriever and the sparse retriever.
  5. Wraps the construction in a try/except so that any failure (e.g., missing dependencies) returns the dense retriever unchanged.

The starter code has three # TODO: gaps. Fill them in with the correct code.

Relevant identifiers from the source code:

  • store_nodes(index) -> list
  • BM25Retriever.from_defaults(nodes=..., similarity_top_k=...)
  • QueryFusionRetriever(retrievers, similarity_top_k=..., num_queries=..., mode="reciprocal_rerank", ...)
Your code
Sources
  • roadmap-kg/kg/rerank.py:188-225
  • roadmap-kg/kg/rerank.py:151-186
  • roadmap-kg/kg/memory_common.py:975-990