Recipe

Metadata filtering for RAG

Vector similarity alone returns semantically near matches, not relevant ones. When you index a corpus that spans tenants, time ranges, languages, or document types, pure cosine search leaks context across boundaries. This recipe shows how to attach structured metadata at ingest, push filter predicates into the retrieval call, and cut hallucinations without rebuilding your index.

1.Attach metadata at ingest time

Every chunk you embed should carry the structured fields you will later filter on. Tenant id, source document, published date, language, and access tier are the common five. Meridian stores these on the vector record so the retrieval layer can prune candidates before the ANN scan rather than after.

2.Push predicates into retrieval

The retrieval call accepts a filter object alongside the query embedding. Predicates compose with AND semantics. A typical multi-tenant call locks the tenant, restricts to documents published in the last 90 days, and excludes archived sources in a single request.

const results = await meridian.retrieve({
  query: "refund policy for enterprise plan",
  top_k: 8,
  filter: {
    tenant_id: "acme_corp",
    published_at: { gte: "2025-09-01" },
    status: { ne: "archived" },
    language: { in: ["en", "en-US"] }
  }
});

3.Validate the filter before LLM handoff

Always assert the returned candidates satisfy the predicate before passing context into the LLM. A misconfigured filter is the most common source of cross-tenant data leakage in production RAG. Meridian emits a filter_applied field on every response so you can log and alert on drift.