Módulo 6: Metadata Filtering — el componente que casi nadie implementa primero pero todos terminan necesitando
Módulo 6: Metadata Filtering — el componente que casi nadie implementa primero pero todos terminan necesitando
Descripción del módulo
Hasta acá optimizaste retrieval por calidad: query optimization (M03), re-ranking (M04), hybrid search (M05). Cada técnica mejora qué tan bien encuentras los documentos correctos dentro del corpus completo. Metadata filtering ataca un problema distinto y complementario: buscar en menos documentos.
La idea es simple: si tu corpus tiene 1M de documentos pero tu usuario está autenticado en el workspace acme_corp, no tiene sentido buscar en los 950K documentos de los otros workspaces. Filtra primero a los 50K relevantes, después corre el retrieval. Resultado: latencia 10x menor, precision mejor (menos ruido), y — crítico — aislamiento de seguridad entre tenants.
Esta cápsula introduce el módulo. Vas a aprender por qué metadata filtering no es opcional en sistemas multi-tenant, cuándo aplicarlo en el pipeline (antes o después del retrieval), cómo diseñar el schema desde el inicio para que los filtros que vas a necesitar sean fáciles de expresar, y cómo combinarlo con todo lo anterior.
Al finalizar este módulo serás capaz de:
- ✅ Diferenciar pre-filtering vs post-filtering y elegir el correcto para tu caso
- ✅ Diseñar metadata schema que cubra los filters que vas a necesitar (sin over-engineering)
- ✅ Implementar filtros en ChromaDB con
whereclauses (igualdad, rangos, IN, AND/OR) - ✅ Aislar datos por
workspace_idotenant_idcomo control de seguridad multi-tenant - ✅ Aplicar filtros temporales (recencia) y semánticos (tags, categorías)
- ✅ Integrar metadata filtering con el hybrid search de M05 para producción real
Tiempo estimado del módulo: 3-4 horas (8 cápsulas).
Por qué metadata filtering importa más de lo que parece
Tres situaciones que pasan en sistemas RAG que lo ignoraron al inicio:
Situación 1: data leakage entre tenants
Tu producto tiene 50 clientes. Cada uno tiene su corpus de documentos. Sin metadata filtering, cuando el cliente A hace una query, el retrieval busca en el corpus completo — incluyendo documentos del cliente B. Si las queries y los embeddings son lo suficientemente similares, A puede ver fragmentos de B.
"Compliance descubrió que el chatbot citó un documento de Cliente C cuando Cliente A preguntó sobre pricing. Reportable a regulador."
Esto pasa. No es teórico. Sin where={"tenant_id": "cliente_a"}, no hay garantía técnica de aislamiento — solo esperas que cosine similarity entre tenants sea baja. Cuando los corpus tienen vocabulario compartido, no es baja.
Situación 2: latencia que crece con el corpus
Hace 6 meses tu corpus era 100K vectores. Hoy es 5M (creció con docs nuevos de cada cliente). Latencia de retrieval pasó de 30ms a 250ms. SLA empezó a romperse.
"Por qué el bot está lento? Antes era instantáneo."
Causa raíz: estás buscando en el corpus completo cada vez. Si filtras por tenant primero, cada cliente busca en su subset (~100K vectores promedio), latencia se mantiene en 30ms aunque el corpus global crezca.
Situación 3: respuestas con info desactualizada
Tu corpus tiene 5 años de documentación. La query es "¿cómo configuro el feature X?". El sistema devuelve un doc de 2021 que describe la API vieja, ya deprecada. Usuario sigue las instrucciones, falla.
"El bot me da info equivocada. La API que dice usar ya no existe."
Sin filter por fecha, los docs viejos rankean igual que los nuevos. Solución: where={"created_at": {"$gte": one_year_ago}} para preferir contenido reciente.
Estos tres problemas no se resuelven con mejor chunking, mejor reranking, ni hybrid search. Se resuelven con metadata filtering.
El insight: filtering antes de search es siempre más rápido y más seguro
Sin metadata filtering:
Query
↓
┌──────────────────┐
│ Vector DB │
│ 5M vectores │ ← busca en TODOS
│ (multi-tenant │
│ mezclado) │
└──────┬───────────┘
↓
Top-K
(puede incluir docs
de otros tenants —
data leak risk)
Con metadata filtering (pre-filter):
Query + tenant_id
↓
┌──────────────────┐
│ Filtrar por │
│ tenant_id │ ← reduce a ~100K
│ │
└──────┬───────────┘
↓
┌──────────────────┐
│ Vector DB busca │
│ en subset 100K │
└──────┬───────────┘
↓
Top-K (solo del tenant)
(latencia 10x menor,
data leak imposible)
Pre-filter vs post-filter: la decisión arquitectónica
Hay dos formas de aplicar metadata filtering:
Pre-filter: primero filtrar el corpus, después buscar.
# Pre-filtering (ChromaDB lo hace por default cuando pasas `where`)
results = collection.query(
query_texts=[query],
where={"tenant_id": "acme", "language": "es"},
n_results=5,
)
Post-filter: primero buscar, después filtrar resultados.
# Post-filtering (manual)
all_results = collection.query(query_texts=[query], n_results=100)
filtered = [
doc for doc in all_results["documents"][0]
if doc.metadata["tenant_id"] == "acme"
]
top_5 = filtered[:5]
¿Cuál es mejor?
| Aspecto | Pre-filter | Post-filter |
|---|---|---|
| Latencia | Mejor (busca en menos vectores) | Peor (busca en todo, descarta después) |
| Recall (con filtros restrictivos) | Excelente | Pobre (los relevantes pueden quedar fuera del top-100) |
| Seguridad multi-tenant | Garantizada | Posible bug si el filtro post falla |
| Implementación | Soporte nativo en ChromaDB/Pinecone | Manual, propenso a errores |
Pre-filter es siempre la elección correcta, salvo casos extremos. Cápsula 02 cubre por qué con benchmarks.
Roadmap del módulo
| Cápsula | Tema | Qué construirás | Tiempo |
|---|---|---|---|
| 01 (esta) | Introducción al módulo | Mapa, motivación, criterios de éxito | 10-15 min |
| 02 | Pre-filtering vs post-filtering | Decision framework con benchmarks | 25-30 min |
| 03 | Diseño de metadata schema | Schema robusto desde el inicio | 30 min |
| 04 | Filtros con ChromaDB where | Sintaxis completa: igualdad, rangos, IN, AND/OR | 30-35 min |
| 05 | Multi-tenant isolation | Aislamiento seguro por workspace + audit logging | 30-35 min |
| 06 | Time-based + tag filtering | Recencia y categorización fina | 25-30 min |
| 07 | Integración con hybrid search | Pipeline completo: filter → hybrid → rerank | 30 min |
| 08 | Proyecto integrador | Metadata-Filtered RAG end-to-end | 45-60 min |
Total: 3-4 horas. Es uno de los módulos con menos complejidad técnica pero más impacto operacional.
Conexión con módulos previos y siguientes
Módulos previos:
├─ M01: Pipeline RAG → metadata se inserta en cada chunk durante indexing
├─ M02: Chunking → cada chunk lleva metadata heredada del documento padre
├─ M03: Query Optimization → filters se pueden derivar del query (ej: detectar idioma → filtrar)
├─ M04: Re-ranking → re-rank corre sobre el subset filtrado
└─ M05: Hybrid Search → filters aplican antes de BM25 + semantic en paralelo
Este módulo prepara para:
├─ M07: Production con Pinecone → Pinecone soporta metadata filtering nativo
└─ M08: RAG Evaluation → cómo medir impacto del filtering en métricas
Patrón "estado del arte" RAG production-ready (mayo 2026):
Query + user_context (tenant_id, idioma, fecha, etc.)
↓
Query optimization (M03) — opcional
↓
Metadata filtering (M06) — reducir search space
↓
Hybrid search (M05) — BM25 + semantic en paralelo sobre subset filtrado
↓
Re-ranking (M04) — refinar top-K
↓
LLM generation
Cada componente reduce un problema distinto. Metadata filtering es el más operacional — sin él, los demás trabajan contra ti a escala.
Mejora esperada con metadata filtering
Sobre datasets multi-tenant típicos:
| Métrica | Sin filter | Con filter (tenant + fecha) | Mejora |
|---|---|---|---|
| Latencia p95 | 250ms | 30-50ms | -80% |
| Precision@5 | 75% | 89% | +14 pts |
| Recall@5 | 78% | 88% | +10 pts |
| Data leak risk | ALTO | CERO | crítico |
| Costo de infra (RAM) | Alto (índice grande en RAM) | Mismo | igual |
Lectura: la mejora más importante NO es métrica de calidad — es eliminar data leak risk. En sistemas multi-tenant, eso es non-negotiable.
Límites del módulo: qué NO cubrimos
- ❌ IAM y políticas cloud — separación a nivel de infra (separate vector DB instances per tenant) es un patrón distinto. Útil cuando metadata filtering no es suficiente, pero más caro.
- ❌ Optimización a nivel de motor (índices ANN custom) — metadata filtering eficiente requiere features del backend. Cubrimos qué buscar, no cómo modificar el motor.
- ❌ Personalización basada en learning-to-rank con perfil de usuario — fuera de scope. Es retrieval personalizado, no filtering por metadata.
- ❌ GDPR/compliance específicos — el filtering ayuda al "right to access" y "data isolation", pero el cumplimiento legal completo es más amplio.
Pre-requisitos antes de empezar el módulo
Asegúrate de tener:
- ✅ Pipeline RAG funcional con M01-M05 implementados (o al menos M01 + un retrieval básico).
- ✅ Decisión sobre la vector DB que vas a usar — este módulo asume ChromaDB pero los conceptos aplican a Pinecone, Weaviate, Qdrant.
- ✅ Eval set propio de al menos 30 queries con metadata esperado (ej: query "X" debería filtrar tenant_id=Y).
- ✅ Si tu producto es multi-tenant: autenticación funcional que te dé
tenant_idpor request. Sin eso, metadata filtering no es seguro.
Auto-verificación antes de avanzar
Antes de empezar la cápsula 02, asegúrate de poder responder:
- ¿Por qué metadata filtering NO es opcional en sistemas multi-tenant?
- Menciona tres problemas que metadata filtering resuelve y que ninguna otra técnica del módulo puede resolver.
- ¿Cuál es la diferencia entre pre-filter y post-filter, intuitivamente?
Respuestas
-
Porque sin filtro por
tenant_id, no hay garantía técnica de aislamiento entre tenants. La similaridad coseno puede traer documentos de otros clientes si comparten vocabulario. Eso es data leakage — riesgo de compliance, riesgo legal, riesgo de pérdida de confianza del cliente. Ningún algoritmo de retrieval, rerank o hybrid lo resuelve. Solo el filter explícito. -
(a) Aislamiento multi-tenant: ningún algoritmo de calidad de retrieval evita que docs de otro tenant aparezcan; solo el filter por
tenant_idlo garantiza. (b) Latencia que crece con el corpus: chunking, rerank, hybrid no escalan mejor — todos buscan en el corpus completo. Solo filtering reduce el espacio de búsqueda. (c) Recencia: ningún algoritmo "prefiere" documentos nuevos por sí solo; necesitas filter explícito porcreated_ato boost por fecha. -
Pre-filter reduce el corpus ANTES de buscar — vector DB solo considera vectores que matchean el filter. Post-filter busca en todo, después descarta los que no matchean el filter. Pre-filter es más rápido (busca en menos), más seguro (los descartados nunca se consideraron) y mejor en recall (los top-K son del subset relevante). Post-filter es más lento, propenso a perder relevantes (top-100 puede no incluir todos los del subset), y vulnerable a bugs.
Próximo paso: Cápsula 02
La siguiente cápsula entra en pre-filtering vs post-filtering con benchmarks concretos. Vas a ver con números cuánto pierde post-filter en latencia y recall, y por qué pre-filter es siempre la elección correcta excepto en casos muy específicos. Es la base arquitectónica que define todo lo que viene después.
Recursos
- ChromaDB — Metadata Filtering — Documentación oficial de filtros
where - Pinecone — Metadata Filtering — Filters en producción
- Multi-tenancy in Vector Databases — Patrones de aislamiento
- LangChain — Retrieval Filters — Integraciones con filtering
- Anthropic — Contextual Retrieval — Contexto adicional para retrieval
- GDPR Article 32 — Security of Processing — Por qué aislamiento técnico importa legalmente
Tiempo estimado: 10-15 minutos Siguiente: 02-pre-filtering-vs-post-filtering.md
Notas finales
Este es el último módulo de "Phase 2 — Técnicas de retrieval" del path. Cuando lo cerres, vas a tener implementado el patrón completo de RAG production-ready:
Query optimization (M03)
↓
Metadata filter (M06)
↓
Hybrid search (M05) — semantic + BM25 con RRF
↓
Re-ranking (M04) — cross-encoder o LLM
↓
LLM generation
Cada módulo agregó un componente. Combinados, llevan precision@5 desde ~70% (RAG MVP del M01) hasta 90-95% en producción.
El próximo módulo (M07) no agrega técnicas — toma todo lo que construiste y lo deploya a Pinecone (vector DB managed) para escalar de 1M docs a 10M+ con SLAs de producción. Es la transición de "demo working" a "service running 24/7".
Y el último (M08) cubre cómo medir que todo lo que construiste realmente funciona: golden datasets, métricas Ragas, regression testing, CI/CD para RAG. Es la pieza que separa "creemos que funciona" de "sabemos que funciona".
Recordatorio importante
A partir de este módulo, todos los proyectos asumen que tu sistema es production-ready desde el día 1. Eso significa:
- Aislamiento multi-tenant por design (no opcional).
- Tests automatizados que corren en CI.
- Audit logging para compliance.
- Documentación que un Tech Lead pueda aprobar.
Si tu RAG actual no cumple esto, retrocede y arregla eso antes de avanzar. Es más fácil hacerlo ahora que después de un incidente.