Back to Blog
Published:
Last Updated:
Enterprise GraphRAG & Knowledge SystemsChapter 1

Hybrid Retrieval With Prefetch-Time Metadata Filtering

8 min read
1,500 words
high priority
Mudassir Marwat

Mudassir Marwat

Founder & CEO, Cognilium AI

Hybrid Retrieval With Prefetch-Time Metadata Filtering — Cognilium AI

TL;DR

Why filtering after RRF fusion loses the right chunks, and how a "drop trait → mode → grade" progressive relaxation ladder keeps narrow queries answerable without dropping retrieval quality.

A hybrid retriever combines a dense embedding model with a sparse BM25 index, fuses results with reciprocal rank fusion, and reranks. Adding metadata filtering on top of this — "only chunks tagged grade=4 and mode=active" — looks like a one-line change. It is not. Where the filter applies decides whether your retrieval quality survives narrow queries.

Post-filter loses chunks before the reranker sees them

The naive integration: retrieve top-K from each retriever, fuse, drop chunks whose metadata fails the filter. For broad queries this is fine — most chunks pass. For narrow queries (a specific grade and mode in a small corpus), 80% of the top-K may fail the filter. Now the reranker has 4 chunks to work with instead of 30, and the answer goes from "evidence-grounded" to "best of a poor pool."

Prefilter keeps the candidate pool full

The fix: push the filter down into both retrievers. Qdrant supports filter-during-search natively, so the dense side already retrieves only filter-passing chunks. The sparse side runs BM25 over the same prefiltered set. Fusion sees 200 candidates instead of 200-of-which-160-fail. The reranker gets a full 30-chunk input regardless of how narrow the filter is.

Progressive relaxation handles the empty-set case

Narrow filters sometimes return zero candidates — the corpus has no grade-4 active-mode chunk for "synonym practice for adjectives." A retrieval that returns zero is worse than one that returns slightly off-target chunks; the LLM produces "I do not have material on this" instead of generating from analogous content.

The relaxation ladder: drop the most specific trait (the writing-trait tag) first, retry; if still empty, drop mode (active/passive); if still empty, drop grade. Each step is one Qdrant call. The query that hit the relaxed level is logged so editors can see which trait/mode/grade combinations are sparse and decide whether to add content or merge tags.

What this looks like in practice

  • Strict-filter queries: ~85% — relaxation never triggers
  • ~12% relax once (drop trait), ~3% relax twice (drop mode), <0.5% relax three times
  • Reranker input size: stays at 30 chunks regardless of filter narrowness
  • Corpus: 584 chunks across 188 catalogued lessons
  • P50 retrieval latency: ~80ms strict, +40ms per relaxation level

When this hurts

Push-down filters require indexed metadata fields. If your filter dimensions change weekly, every change is a reindex. Pick filter dimensions that are part of your domain model — grade, content type, language — not transient experiment flags.

Share this article

Enterprise GraphRAG & Knowledge Systems

Topic Cluster

The work behind this series

How we design the graph schema, the retrieval path and the evaluation harness behind these articles.

Mudassir Marwat

Mudassir Marwat

Founder & CEO, Cognilium AI

Mudassir Marwat's argument is that ERP systems record decisions they never optimise.

Founder & CEO of Cognilium AI; 37 AI agents in production across four products; 4 production AI products built and operated; three clouds in production (AWSGCPAzure)
Agentic AIRAG → GraphRAG retrievalVoice AIMulti-Agent Orchestration
Next in this series
Organizational Memory: RAG Across Slack, Confluence, and Loom
Chapter 2 · 9 min

Frequently Asked Questions

Find answers to common questions about the topics covered in this article.

Post-filter: retrieve top-K, then drop chunks whose metadata fails the filter. K shrinks below your reranker cutoff and you lose answer quality. Prefilter: filter the candidate set to filter-passing chunks first, then retrieve top-K from that smaller set. K stays full at the cost of compute.
Most queries pass strict filters fine. Widening upfront pollutes those queries with irrelevant chunks. Relaxation triggers only on the narrow queries that need it — keeping precision high in the common case.
Domain-specific traits first (most specific, most likely to be over-narrow), then mode (active vs. passive lesson), then grade level. Anything before "drop nothing" — at which point the query is genuinely empty.
Fusion happens after both dense and sparse retrievers return. If we post-filter: each retriever returns 100 chunks, fusion picks 30, filter drops 25, you have 5. Prefilter: candidate pool is filter-passing chunks (say 800 of 5,000), each retriever returns 100 from that pool, fusion picks 30 — full reranker input.
Qdrant supports filter-during-search natively, so it is not a separate query — the cost is the index lookup with the filter pushed down. Indexed metadata fields stay fast (sub-50ms for our 584-chunk corpus). Non-indexed filters degrade to scan and you feel it.

Still have questions?

Get in touch with our team for personalized assistance.

Contact Us

Still have a question this did not answer?

The person who wrote this article answers these. Describe your setup and what you are stuck on — you will get a straight answer, including where we think the approach is wrong.

Related Articles

Continue exploring related topics and insights from our content library.

The Production LLMOps Stack: Evals, Judges, Retries, Circuit Breakers
11 min
1
Mudassir Marwat
May 5, 2026

The Production LLMOps Stack: Evals, Judges, Retries, Circuit Breakers

The day-2 ops layer of an LLM product — what to evaluate, what to judge in real time, what to retry, and when to fail closed. The components that turn a prototype into something operable.

words
Read Article
LLM-as-Judge With Temperature-Escalation Retry Inside a 60-Second Budget
7 min
2
Mudassir Marwat
May 5, 2026

LLM-as-Judge With Temperature-Escalation Retry Inside a 60-Second Budget

Judge scores below 85? Retry with temperature 0.3, 0.4, 0.5 — three attempts inside a 60-second wall-clock budget. The simple loop that hits 99.5% on-spec output without crossing the latency ceiling.

words
Read Article
Smart Category-Score Routing That Cuts LLM Cost ~75%
7 min
3
Mudassir Marwat
May 5, 2026

Smart Category-Score Routing That Cuts LLM Cost ~75%

A pipeline of 12 scorers + 11 analysts does not need to fan out everywhere. Route each chunk to matching analysts and save three quarters of the LLM bill.

words
Read Article

Explore More Insights

Discover more expert articles on AI, engineering, and technology trends.