LlamaIndex Clinical Document Retrieval: Metadata Filtering for Singapore Hospitals
Most clinical RAG tutorials retrieve documents by semantic similarity alone. In production hospital settings, that approach fails: a query about a patient's cardiac history might surface discharge summaries from unrelated admissions, violate patient context boundaries, or return documents the querying clinician is not authorized to see. We built retrieval pipelines for Singapore health systems where metadata filtering—by patient identifier, encounter date, document type, and clinical service—is not optional; it is the foundation of safe, compliant clinical AI services.
This tutorial walks through LlamaIndex metadata filtering for clinical document retrieval, with evaluation, privacy, and audit logging patterns we use in healthcare AI Singapore deployments.
Key takeaways
- Semantic search alone is unsafe for clinical documents: metadata filters enforce patient context, encounter boundaries, and access control before similarity ranking.
- LlamaIndex metadata filtering is declarative: filter by patient ID, encounter date, document type, or clinical service using structured query syntax, not prompt engineering.
- Evaluation requires clinical ground truth: measure retrieval precision and recall against clinician-annotated question-document pairs, not generic RAG benchmarks.
- Audit logging is mandatory: every retrieval query, filter applied, and document returned must be logged with user identity, timestamp, and patient context for Singapore PDPA compliance.
- Production cautions: test filter logic exhaustively, validate metadata completeness, and implement human review loops for high-stakes clinical queries.
Why semantic search alone fails in clinical document retrieval
A discharge summary embedding might be semantically similar to a query about "recent cardiac events," but if that summary belongs to a different patient, was authored by a service the querying clinician cannot access, or predates the current admission, retrieval is clinically meaningless or unsafe.
In Singapore hospital deployments, we enforce three metadata boundaries:
- Patient context: only retrieve documents for the patient currently in scope (by NRIC hash, medical record number, or encounter ID).
- Temporal scope: filter by encounter date range, admission window, or "last N days" to avoid surfacing stale clinical narratives.
- Document type and service: restrict retrieval to discharge summaries, progress notes, or radiology reports based on the clinical workflow; filter by authoring service (e.g., cardiology, oncology) when specialty context matters.
Semantic similarity ranks documents after these filters apply. This inverts the typical RAG pattern: metadata filtering is the primary gate, embeddings are the tiebreaker.
How LlamaIndex metadata filtering works for clinical documents
LlamaIndex stores metadata as key-value pairs on each document node. At query time, you pass a MetadataFilters object that specifies exact-match, range, or list-membership conditions. The vector store applies these filters before similarity search, so only eligible documents enter the ranking step.
Metadata schema for discharge summaries
We structure clinical document metadata with these fields:
patient_id: hashed or pseudonymized patient identifierencounter_id: unique admission or visit identifierdocument_type: "discharge_summary", "progress_note", "radiology_report"encounter_date: ISO 8601 date of the encounterclinical_service: "cardiology", "oncology", "emergency", etc.author_role: "attending", "resident", "nurse" (optional, for access control)
These fields are extracted during document ingestion from EHR exports, HL7 messages, or FHIR DocumentReference resources. Metadata completeness is validated before indexing; documents with missing patient_id or encounter_date are quarantined for manual review.
How to build a filtered clinical retrieval pipeline
Step 1: Ingest documents with metadata
```python
from llama_index.core import Document, VectorStoreIndex
from llama_index.core.schema import MetadataMode
import hashlib
Example: discharge summary from EHR export raw_text = "Patient admitted with acute MI, underwent PCI..." patient_nric = "S1234567D" # Singapore NRIC patient_id_hash = hashlib.sha256(patient_nric.encode()).hexdigest()[:16]
doc = Document(
text=raw_text,
metadata={
"patient_id": patient_id_hash,
"encounter_id": "ENC-2026-07-001",
"document_type": "discharge_summary",
"encounter_date": "2026-07-15",
"clinical_service": "cardiology"
},
excluded_llm_metadata_keys=["patient_id", "encounter_id"], # do not pass to LLM context
excluded_embed_metadata_keys=["patient_id", "encounter_id"] # do not embed PII
)
index = VectorStoreIndex.from_documents([doc])
```
Privacy note: we hash patient identifiers before indexing and exclude them from embedding and LLM context. The metadata is used only for filtering, not for semantic search or generation.
Step 2: Query with metadata filters
```python
from llama_index.core.vector_stores import MetadataFilters, ExactMatchFilter, MetadataFilter
Clinician queries: "What was the patient's cardiac history during the last admission?" # System enforces: only this patient, only discharge summaries, only last 30 days
filters = MetadataFilters(
filters=[
ExactMatchFilter(key="patient_id", value=patient_id_hash),
ExactMatchFilter(key="document_type", value="discharge_summary"),
MetadataFilter(key="encounter_date", value="2026-06-29", operator=">=") # last 30 days
]
)
query_engine = index.as_query_engine(
similarity_top_k=5,
filters=filters
)
response = query_engine.query("What was the patient's cardiac history?")
```
The vector store applies filters before similarity search. If no documents match the metadata conditions, the retrieval returns empty, and the LLM receives no context—this is the correct behavior for out-of-scope queries.
Step 3: Log every retrieval for audit
For Singapore PDPA compliance and clinical governance, we log:
- User identity (clinician ID, role)
- Query text (sanitized of PII)
- Metadata filters applied
- Document IDs retrieved
- Timestamp and session context
This audit trail supports retrospective review, access audits, and incident investigation. We store logs in a separate, access-controlled database with retention policies aligned to institutional data governance.
How to evaluate clinical retrieval with metadata filters
Generic RAG benchmarks (e.g., HotpotQA, Natural Questions) do not test metadata filtering logic. We build clinical evaluation sets with:
- Question-document pairs annotated by clinicians: "For patient X's July admission, which discharge summary mentions cardiac catheterization?" → ground-truth document ID.
- Negative cases: queries that should return no documents (wrong patient, wrong date range, wrong document type).
- Access control tests: queries from users without authorization to specific clinical services or document types.
We measure:
- Precision: fraction of retrieved documents that are clinically relevant and in-scope.
- Recall: fraction of ground-truth documents retrieved.
- Filter correctness: zero tolerance for out-of-scope documents (wrong patient, wrong encounter).
Evaluation runs nightly against a held-out test set; regressions trigger alerts to the clinical informatics team. For more on evaluation frameworks, see our AI disclosure guide and readmission prediction transparency post.
Production cautions for clinical RAG with LlamaIndex
Metadata completeness and validation
Incomplete metadata breaks filtering. We validate every document at ingestion:
- Required fields (
patient_id,encounter_date,document_type) must be non-null. - Date formats are ISO 8601; invalid dates are rejected.
clinical_servicevalues are constrained to a controlled vocabulary.
Documents that fail validation are quarantined, not indexed. A daily report lists quarantined documents for manual review.
Filter logic testing
We test filter combinations exhaustively:
- Single patient, multiple encounters
- Date range boundaries (inclusive, exclusive)
- Multiple document types (OR logic)
- Empty result sets (no documents match filters)
Unit tests cover edge cases: leap years, timezone boundaries, null metadata values. Integration tests run against a synthetic clinical corpus with known metadata distributions.
Human review for high-stakes queries
For queries that inform treatment decisions (e.g., "What were the patient's prior adverse drug reactions?"), we route retrieved documents to a clinician review step before LLM generation. The clinician confirms relevance, corrects retrieval errors, and approves the context passed to the LLM. This pattern is common in agentic workflows where retrieval is one step in a multi-agent clinical decision support pipeline.
Monitoring and alerting
We monitor:
- Empty retrieval rate: fraction of queries that return zero documents after filtering. High rates suggest metadata issues or overly restrictive filters.
- Out-of-scope retrieval: documents retrieved for the wrong patient or encounter (should be zero; any occurrence triggers an incident).
- Query latency: P50, P95, P99 retrieval times; spikes indicate vector store performance issues.
Alerts route to the platform engineering team and clinical informatics leads. For monitoring patterns, see our continuous monitoring post.
Why this matters in Singapore and Asia
Singapore's PDPA and the Health Sciences Authority's medical device regulations require that clinical AI systems enforce access control, maintain audit trails, and prevent unauthorized data disclosure. Metadata filtering is not a performance optimization; it is a compliance and safety requirement.
In multi-institution deployments (e.g., regional health clusters, cross-border telehealth), metadata filtering extends to institution identifiers, data residency constraints, and cross-border data transfer rules. We have seen Singapore hospital clusters reject RAG prototypes that lacked metadata filtering, even when semantic retrieval quality was high, because the systems could not demonstrate patient context isolation or audit trail completeness.
For health systems evaluating medical LLM Singapore deployments, metadata filtering is table stakes. The question is not whether to implement it, but how to validate it, test it, and monitor it in production.
What to do next
- Define your clinical metadata schema: identify required fields (patient ID, encounter date, document type) and controlled vocabularies (clinical services, document types). Validate schema completeness with clinical informatics and legal teams.
- Build a clinical evaluation set: work with clinicians to annotate 50–100 question-document pairs covering common retrieval scenarios, negative cases, and access control tests. Measure precision, recall, and filter correctness.
- Implement audit logging: log every retrieval query, filter applied, and document returned with user identity, timestamp, and patient context. Store logs in a separate, access-controlled database with retention policies.
- Test filter logic exhaustively: write unit and integration tests for all filter combinations, edge cases, and empty result sets. Run tests nightly against a synthetic clinical corpus.
- Route high-stakes queries to human review: for queries that inform treatment decisions, implement a clinician review step before LLM generation. Document the review process and approval criteria.
If you are building clinical RAG systems for Singapore health systems and need help with metadata schema design, evaluation frameworks, or audit logging architecture, start a project with our team.
FAQ
What vector stores support metadata filtering with LlamaIndex?
LlamaIndex supports metadata filtering with Pinecone, Weaviate, Qdrant, Chroma, and Postgres with pgvector. For clinical deployments in Singapore, we typically use self-hosted Qdrant or Postgres with pgvector to maintain data residency and avoid third-party data processing agreements. Cloud-hosted vector stores (Pinecone, Weaviate Cloud) require BAAs and data residency guarantees; verify these before production use.
How do you handle missing or incomplete metadata in clinical documents?
We validate metadata completeness at ingestion. Documents with missing required fields (patient_id, encounter_date, document_type) are quarantined, not indexed. A daily report lists quarantined documents for manual review by clinical informatics teams. We do not attempt to infer missing metadata from document text; that introduces error risk and complicates audit trails. If metadata extraction from EHR exports is unreliable, we work with IT teams to improve upstream data quality or add validation steps to HL7/FHIR pipelines.
Can metadata filtering replace access control and authorization?
No. Metadata filtering enforces patient context and clinical scope, but it does not replace user authentication, role-based access control (RBAC), or authorization checks. In production systems, we implement a three-layer access model: (1) user authentication and RBAC at the application layer, (2) metadata filtering at the retrieval layer to enforce patient and encounter scope, and (3) audit logging to record all access. Metadata filtering is one control in a defense-in-depth strategy, not a substitute for IAM or authorization frameworks.
How do you test that metadata filters prevent out-of-scope retrieval?
We build negative test cases: queries that should return zero documents because the patient ID, encounter date, or document type does not match any indexed documents. We also test cross-patient queries (query for patient A with patient B's ID in the filter) and expect empty results. Integration tests run against a synthetic corpus with known metadata distributions; any out-of-scope retrieval (wrong patient, wrong encounter) triggers a test failure and incident alert. We run these tests nightly and before every production deployment. For safety monitoring patterns, see our open-source safety benchmarks post.
Sources
No external sources cited in this post. Content is based on InsytAI's clinical AI deployment experience in Singapore health systems.