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 where clauses (igualdad, rangos, IN, AND/OR)
  • ✅ Aislar datos por workspace_id o tenant_id como 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?

AspectoPre-filterPost-filter
LatenciaMejor (busca en menos vectores)Peor (busca en todo, descarta después)
Recall (con filtros restrictivos)ExcelentePobre (los relevantes pueden quedar fuera del top-100)
Seguridad multi-tenantGarantizadaPosible bug si el filtro post falla
ImplementaciónSoporte nativo en ChromaDB/PineconeManual, 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ápsulaTemaQué construirásTiempo
01 (esta)Introducción al móduloMapa, motivación, criterios de éxito10-15 min
02Pre-filtering vs post-filteringDecision framework con benchmarks25-30 min
03Diseño de metadata schemaSchema robusto desde el inicio30 min
04Filtros con ChromaDB whereSintaxis completa: igualdad, rangos, IN, AND/OR30-35 min
05Multi-tenant isolationAislamiento seguro por workspace + audit logging30-35 min
06Time-based + tag filteringRecencia y categorización fina25-30 min
07Integración con hybrid searchPipeline completo: filter → hybrid → rerank30 min
08Proyecto integradorMetadata-Filtered RAG end-to-end45-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étricaSin filterCon filter (tenant + fecha)Mejora
Latencia p95250ms30-50ms-80%
Precision@575%89%+14 pts
Recall@578%88%+10 pts
Data leak riskALTOCEROcrítico
Costo de infra (RAM)Alto (índice grande en RAM)Mismoigual

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_id por 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:

  1. ¿Por qué metadata filtering NO es opcional en sistemas multi-tenant?
  2. Menciona tres problemas que metadata filtering resuelve y que ninguna otra técnica del módulo puede resolver.
  3. ¿Cuál es la diferencia entre pre-filter y post-filter, intuitivamente?
Respuestas
  1. 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.

  2. (a) Aislamiento multi-tenant: ningún algoritmo de calidad de retrieval evita que docs de otro tenant aparezcan; solo el filter por tenant_id lo 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 por created_at o boost por fecha.

  3. 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

  1. ChromaDB — Metadata Filtering — Documentación oficial de filtros where
  2. Pinecone — Metadata Filtering — Filters en producción
  3. Multi-tenancy in Vector Databases — Patrones de aislamiento
  4. LangChain — Retrieval Filters — Integraciones con filtering
  5. Anthropic — Contextual Retrieval — Contexto adicional para retrieval
  6. 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.