Retrieval-Augmented GenerationRAGProduction RAG — Retrieval Debugging & Search Regressions

A metadata filter unexpectedly reduces the result count from 100 to zero. How would you distinguish filtering errors from genuine data absence?

Production incident (illustrative): A legal-policy RAG service returns 100 unfiltered candidates for "2026 contractor travel reimbursement rules". Enabling tenant_id=acme AND region=APAC AND effective_year=2026 AND document_status=active unexpectedly returns zero. The team wants to remove metadata filters to restore results. That could expose documents from other tenants or outdated policies. A zero-result set may be correct under legitimate constraints, a metadata typing/ingestion problem, a Boolean filter-construction defect, a wrong collection/alias, or ANN post-filter starvation. Establish which one with authorized exact counts and a known-record witness.

Core principle: 100 unfiltered vector hits are not evidence that any of those 100 match the complete predicate. Likewise 0 filtered ANN hits does not prove the filtered corpus is empty. Distinguish (1) eligible-record count, (2) search-visible eligible-record count, and (3) ANN candidate coverage. Keep tenant and ACL enforcement invariant throughout.

1. Safely contain and reproduce

  • Capture a reproducible request: tenant_id, principal, query text/vector hash, target collection/alias, shard keys, replica/read consistency, model/version, top_k, full serialized filter JSON, and response metadata. Protect private values and do not log sensitive raw payloads indiscriminately.
  • Confirm mandatory tenant and ACL constraints independently of optional business filters. Never simply drop tenant_id/authorization for a production query. If a policy cannot be retrieved safely, return an "insufficient authorized evidence" response.
  • Retrieve one known expected active authorized document ID from the authoritative content system. Check its correct tenant, status, geographic applicability, effective date, version and actual stored payload types. A witness makes testing more informative than tweaking top-k blindly.
  • Confirm index identity: current alias, namespace, collection, embedding version, field schema, routing keys and shard/replica state. A stale read replica or old index version can contain vectors yet lack newly populated metadata.
  • Build a protected test dataset or an isolated audit environment for comparing omitted predicates; perform any deliberately wider counts only with an authorized operator role, aggregate outputs and minimal retained information.

2. First determine if the eligible set is actually empty

  • Use the authoritative database/source manifest to count active records satisfying the exact business predicate, with the same tenant and authorization conditions.
  • Independently use the vector engine's filtered count API when supported, rather than relying on vector top-k. Qdrant /points/count accepts filters and exact=true for exact counts; exact=false may be approximate during indexing. Elastic _count can help isolate source/index membership.
  • Compare counts at three stages: source eligible, index payload eligible, query-visible eligible. If source count is 0 and predicate semantics are correct, genuine absence is plausible; confirm policy dates, scope and ACL before telling the user "no records."
  • If the source count is positive but the index filtered count is 0, suspect missing/stale payload, field mapping, wrong alias/tenant route, type mismatch or delayed indexing—not ANN graph quality.
  • If filtered exact count is positive but vector search returns 0, inspect ANN pre-filter/post-filter semantics, candidate budgets, threshold and timeouts. Check whether filtered exact/flat retrieval finds relevant points under the same predicates.

3. Clause-by-clause root-cause debugging

  • Start with mandatory authorization (tenant and ACL) unchanged, then add optional filters one at a time and record exact eligible counts. Do not compare an unsafe globally unfiltered count with a tenant-filtered result as if they had the same population.
  • Test tenant_id and permitted principal against exact stored payload; string case, trailing spaces, ID serialization and hierarchy may differ. Treat a missing ACL field as deny-by-default, not an invitation to remove the filter.
  • Inspect region: APAC vs Asia-Pacific vs IN vs multi-valued arrays. Decide whether "APAC" means direct label membership or a business-defined region hierarchy; enforce the correct mapping and include region-map version.
  • Inspect effective_year: number 2026 versus string "2026". Match filter types to field schema; coercion differs across engines. For an effective-date range, don't substitute a simple calendar year for an interval-containment test. Test document effective_from <= query_date and effective_to > query_date (or explicit open-ended semantics) in a timestamp-aware implementation.
  • Inspect document_status: ACTIVE, active, published or boolean flag; a new pipeline may have renamed the field without backfilling existing points. Determine whether the source genuinely marks the record inactive.
  • Inspect missing and null: missing field, explicit JSON null, empty array and empty string can behave differently. Weaviate's null-state filtering, for example, has indexing requirements and documents a convention that empty strings/arrays are treated as null. Avoid broad assumptions across providers.
  • Inspect the Boolean expression: a must/AND clause requires every condition; should/OR needs only one; must_not reverses inclusion. Check a mistakenly generated must_not, two incompatible statuses, or an AND where business meaning needs OR. In Qdrant an array can require a nested condition if all constraints must hold on the *same array element*.
  • Inspect field type and text analysis: equality queries on analyzed text may not mean exact-key equality; use field mappings such as Elasticsearch keyword and verify field_caps, mappings and diagnostic explain/profile as available.
  • Inspect vector search specifics: post-filtering a small top-k may remove every candidate despite matching points elsewhere; pre-filtering/exact eligible retrieval can test whether the set is nonempty. Also check a strict score threshold, search timeouts, shard partial responses and stale replicas.

4. Worked numerical production example

  • One tenant has 1,000 authorized active vector points. Unfiltered *within-tenant* semantic search returns top-100, but that is only a ranked sample, not a filtered count.
  • With tenant/ACL constraints always enforced, an exact count gives: 1,000 authorized; add region=APAC → 400; add status=active → 240; add effective_year=2026 as an integer equality → 0.
  • The source manifest says 180 valid APAC/active documents for 2026. Inspecting a permitted witness shows payload {"effective_year":"2026"} stored as a string; the filter compares it to numeric 2026. The missing matches are caused by a schema/type contract violation, not a lack of policies.
  • A controlled corrected string-equality filter produces 180 eligible points, matching the authoritative manifest. Of the original unfiltered top-100 hits, suppose only 6 were among those 180; that is why "100 unfiltered" cannot be interpreted as 100 eligible.
  • Hypothetical separate check: the retrieval pipeline performs dense top-10 first, then applies the APAC/year/status constraint; all 10 happen to be outside the eligible set, yielding 0. Engine-native pre-filtering and an exact filtered search return matching documents, revealing post-filter starvation in addition to the type defect.
  • At the same authorized snapshot, corrected pre-filtered ANN top-10 finds the labelled relevant chunk in 9 of 10 controlled queries versus 0 of 10 previously. These numbers are illustrative and too small to claim population-wide recall improvement; validate using a larger representative golden set.
  • Count difference = 180 source eligible − 0 broken-index-filter matches = 180 missing matches; corrected index count = 180, so count reconciliation passes. Yet a count agreement alone does not prove each ID/version or ACL is correct—compare exact IDs, source hashes and per-tenant samples.
  • Query p95 might rise from 95 ms to 130 ms after stricter native filtering due to extra search effort; this is an illustrative 35 ms trade-off to evaluate against the service SLO.

5. Engineering solution and verification

  • Define a versioned metadata contract: canonical tenant identifiers, ACL policy/version, region taxonomy, status enum, timestamp and numeric representations, null conventions, and nested-array semantics. Generate filters from typed builders rather than unvalidated LLM strings.
  • Add ingestion validators: reject or quarantine points with incompatible effective_year types, missing required authorization metadata, invalid status, or ambiguous region codes. For existing data, backfill only correctly authorized active records from the source of truth and reconcile by stable point IDs.
  • Rebuild or adjust relevant payload indexes or field mappings if required by the backend, after verifying compatibility and rollout resources. Avoid unnecessary full embedding recomputation when only metadata is wrong.
  • Use authoritative count and vendor filter diagnostics before increasing ANN top-k or ef_search; these parameters cannot repair a logically impossible predicate or mismatched field type.
  • Choose backend-native pre-filtering/eligible-set search for selective metadata predicates, with sufficient ANN effort and a benchmark against exact filtered kNN. Avoid late post-filtering when correctness requires all top-k results to be eligible.
  • Revalidate AND/OR grouping, range boundaries, missing-value behavior and nested arrays. Store a normalized, parameterized filter representation with its schema version for reproducible traces.
  • Shadow-test the repaired path, perform a small canary with source-to-index count/ID reconciliation, then promote only when ACL-safe retrieval, candidate coverage, latency and freshness gates pass. Roll back the typed metadata migration if it regresses query correctness—but never roll back to a state that exposes revoked data.

6. Trade-offs, failures and common mistakes

  • No matches vs retrieval miss: exact filtered count zero suggests no matching index payloads; ANN zero despite count positive suggests ranking, search execution or filter placement. Neither alone proves source truth.
  • Relaxing filters: may increase hits but violates tenant isolation, policy-effective dates or access controls. Diagnostic widening belongs only in a separate authorized audit environment; production mandatory filters remain enforced.
  • Post-filtering top-k: cheap to implement, but can eliminate all candidates if the eligible subset was never in the original k. Larger k may lessen symptoms but does not guarantee exhaustive candidate coverage.
  • Pre-filtering: generally respects eligibility during candidate generation but can increase search cost for very selective predicates and depends on engine-specific filtered ANN strategies.
  • Type coercion: silent coercion may make some filters seem to work but can produce unexpected boundary and string comparisons. Typed contracts are safer.
  • Dates: local time zones, inclusive/exclusive boundaries and effective-to null semantics can introduce genuine exclusion even with consistent metadata.
  • Missing/null: allowing records with missing ACL metadata is a security regression; deny by default and repair from the authoritative system.
  • Indexes and replicas: a mapping change/backfill may not be visible instantly on every replica or generation; verify completion, consistency and alias identity before cutover.
  • Counts: aggregate count equality hides which records are wrong; verify expected authorized witness IDs, version hashes and sample citations.

7. Prevent recurrence

  • Maintain golden tests for tenant/ACL combinations, regional hierarchies, status values, year/date ranges, null and missing fields, numeric-vs-string types, nested attributes, and contradictory predicates.
  • Dashboard a filter attrition funnel: authorized total → each business clause → exact eligible point count → filtered ANN hits → fused candidates → answer citation. Segment by tenant, index generation and query class.
  • Alert on abrupt increases in nonempty_source && zero_filtered_index, high rates of empty results on known-authorized canaries, and metadata-contract validation errors after deployments.
  • Run source-to-vector ID-level reconciliation, not just counts. Include versioned access and deletion events in every backfill/migration.
  • Require negative security tests proving a filter rewrite never returns an unauthorized tenant or a superseded policy. Test pre- and post-filter behavior separately with high-selectivity fixtures.
  • Trace full filter JSON, schema version, index alias, exact-count diagnostic and principal-eligible snapshot without exposing confidential user data.
  • Document a ten-minute incident runbook: confirm source witness → count authorized corpus → count each clause → inspect typed payload/mapping → compare exact filtered search to ANN → fix first failing boundary → verify ACL and latency.

Interview takeaway: An empty filtered result is a hypothesis, not an explanation. Compare authoritative eligible records with exact index filter counts, add clauses one at a time, inspect payload types/null/date and Boolean semantics, then distinguish actual empty data from filtered-ANN candidate starvation. Never fix “zero results” by bypassing authorization.

Research references

  • Qdrant, Filtering conditions including must/should/nested and missing fields: https://qdrant.tech/documentation/search/filtering/
  • Qdrant, Count points API and exact counts: https://api.qdrant.tech/api-reference/points/count-points
  • Elasticsearch, Troubleshoot searches, count, field capabilities: https://www.elastic.co/docs/troubleshoot/elasticsearch/troubleshooting-searches
  • Weaviate, Conditional filters, null and missing semantics: https://docs.weaviate.io/weaviate/api/graphql/filters
  • Elasticsearch, kNN search and filtered search: https://www.elastic.co/docs/solutions/search/vector/knn
#RAG metadata filter returns zero results debugging#vector database zero matches filtering incident#Qdrant filtered count troubleshoot empty search#metadata filter type mismatch RAG#pre filtering post filtering zero results#rag#production-rag#retrieval-debugging#metadata-filter#filter-attrition

Learning Sequence

Retrieval-Augmented Generation Curriculum

94% Completed
Up NextRAG

Two nearly identical queries produce completely different retrieval results. How would you assess retrieval instability?

Explore Related Questions

Deepen your understanding across related Retrieval-Augmented Generation topics.

Machinoai Logo
Machinoai

Your edge in the AI era. Deep dives into machine learning concepts, paper explainers, verified industry jobs, and developer tools.

© 2026 Machinoai. All rights reserved.