Módulo 3: Features Esenciales para RAG

Cápsula 02: Metadata Filtering (Where Clauses)

🎯 Objetivo de la cápsula

Entender QUÉ es metadata filtering, por qué es la feature más crítica para RAG en producción, y cómo reduce latency 10x mientras mejora accuracy.

Al finalizar esta cápsula:

  • ✅ Explicarás qué es metadata filtering y por qué es esencial
  • ✅ Compararás pre-filtering vs post-filtering (trade-offs)
  • ✅ Identificarás operadores clave (equality, range, membership, logical)
  • ✅ Calcularás impact en performance (latency, accuracy, costos)

Tiempo estimado: 10-12 minutos


🔍 ¿Qué es Metadata Filtering?

Definición

Metadata filtering es capacidad de buscar vectores similares SOLO en subset de documentos que cumplen condiciones específicas (where clauses).

Sin metadata filtering (búsqueda ingenua)

# ❌ Búsqueda en TODO el database
query = "How do I reset my password?"
results = db.query(
    query_embedding=embed(query),
    k=10
)
# Busca en: 500K documentos (todos)
# Latency: 200ms
# Accuracy: 85% (mucho ruido)

Problema: Busca en documentos irrelevantes (marketing, legal, product specs).

Con metadata filtering (búsqueda inteligente)

# ✅ Búsqueda en subset relevante
query = "How do I reset my password?"
results = db.query(
    query_embedding=embed(query),
    k=10,
    where={"category": "support", "language": "en"}
)
# Busca en: 10K documentos (solo support docs en inglés)
# Latency: 20ms (10x faster)
# Accuracy: 95% (sin ruido)

Ventaja: Search space reducido → Latency menor + Accuracy mayor.


📊 Por qué es crítica para RAG

Problema 1: Relevancia (Accuracy)

Escenario: E-commerce RAG con 1M productos

Query: "Nike Air Max precio"

Sin filtering:

Top 10 results:
1. Nike Air Max (product page) ✅
2. Adidas similar shoe (product page) ❌
3. Nike history article ❌
4. Air conditioning product ❌ (false positive: "air")
5. Max brand electronics ❌ (false positive: "max")
...

Accuracy: 60% (4/10 irrelevantes)

Con filtering (category='shoes'):

Top 10 results:
1. Nike Air Max (product page) ✅
2. Nike Air Max variants ✅
3. Similar Nike shoes ✅
...

Accuracy: 95% (9/10 relevantes)

Ganancia: 35% accuracy improvement.

Problema 2: Latency (Performance)

Benchmark (1M vectores, 1536-dim, HNSW):

EscenarioSearch SpaceLatencyvs Baseline
Sin filtering1M vectores180 ms1x
Filtering (10% data)100K vectores18 ms10x faster
Filtering (1% data)10K vectores2 ms90x faster

Clave: Latency es proporcional a search space. Filtering reduce search space dramáticamente.

Problema 3: Costos (Compute)

Con Layer 1 (HNSW) arquitectura:

  • Sin filtering: HNSW navega 1M vectores → CPU intensive
  • Con filtering: HNSW navega 10K vectores → 100x menos CPU

Impact en cloud:

AWS cost (r6i.xlarge, $180/month):
- Sin filtering: CPU usage 80% → Need larger instance ($360/month)
- Con filtering: CPU usage 10% → Can downsize ($90/month)

Savings: $270/month = $3240/year

🏗️ Arquitectura: Pre-filtering vs Post-filtering

Pre-filtering (Filter-then-search)

Proceso:

  1. Aplicar metadata filter primero (SQL-like where clause)
  2. Buscar vectores similares SOLO en subset filtrado
  3. Devolver top-k

Ventaja:

  • ✅ Más rápido (search space reducido)
  • ✅ Menos CPU (no calcula similitud en docs irrelevantes)

Desventaja:

  • ❌ Si subset es vacío → No devuelve resultados
  • ❌ Requiere índice de metadata (overhead)

Usado por: Pinecone, Weaviate (default)

Visualización:

1M documentos
    ↓
[Filter: category='support'] → 10K documentos
    ↓
[Vector search HNSW] → Top 10 resultados

Post-filtering (Search-then-filter)

Proceso:

  1. Buscar vectores similares en TODO el database
  2. Aplicar metadata filter a resultados
  3. Si <k resultados, buscar más vectores
  4. Devolver top-k

Ventaja:

  • ✅ Siempre devuelve k resultados (no falla si subset vacío)
  • ✅ No requiere índice de metadata

Desventaja:

  • ❌ Más lento (busca en todo primero)
  • ❌ Más CPU (calcula similitud en docs que luego filtra)

Usado por: ChromaDB (default)

Visualización:

1M documentos
    ↓
[Vector search HNSW] → Top 100 candidates
    ↓
[Filter: category='support'] → Top 10 resultados filtrados

Comparación: Pre vs Post

DimensiónPre-filteringPost-filtering
Latency20ms ✅50ms ⚠️
CPUBajo ✅Alto ❌
Garantía k resultsNo ❌Sí ✅
Requiere índice metadataSí ⚠️No ✅
Mejor paraHigh cardinality filtersLow cardinality filters

Decisión:

  • Pre-filtering si filter es selectivo (reduce >50% data)
  • Post-filtering si filter es poco selectivo (<10% reduction)

🔧 Operadores de Metadata Filtering

1. Equality (Exact match)

# Single value
where={"category": "support"}

# Busca docs donde category == "support"
# Uso: Categorías, IDs, status

Ejemplo RAG: Solo buscar en documentación técnica (no marketing).

2. Range (Comparaciones)

# Greater than, less than
where={
    "timestamp": {"$gt": 1640000000},  # Después de 2021-12-20
    "price": {"$lt": 100}               # Menor a $100
}

# Operadores: $gt, $gte, $lt, $lte, $ne

Ejemplo RAG: Solo documentos recientes (últimos 30 días).

3. Membership (IN operator)

# Multiple values
where={
    "category": {"$in": ["support", "faq", "docs"]}
}

# Busca docs donde category IN ["support", "faq", "docs"]

Ejemplo RAG: Buscar en múltiples categorías relevantes.

4. Logical operators (AND, OR, NOT)

# AND (implícito con múltiples conditions)
where={
    "category": "support",
    "language": "en",
    "status": "published"
}

# OR
where={
    "$or": [
        {"category": "support"},
        {"category": "faq"}
    ]
}

# NOT
where={
    "category": {"$ne": "archived"}
}

# Combinado (complex)
where={
    "$and": [
        {"category": {"$in": ["support", "faq"]}},
        {"language": "en"},
        {"timestamp": {"$gt": 1640000000}}
    ]
}

Ejemplo RAG: Documentos de soporte EN INGLÉS NO archivados DE últimos 30 días.


📊 Benchmark: Impact real de Metadata Filtering

Escenario: Customer Support RAG

Setup:

  • Database: 500K documentos
    • Support articles: 50K (10%)
    • Marketing content: 200K (40%)
    • Product specs: 150K (30%)
    • Legal/HR docs: 100K (20%)
  • Algoritmo: HNSW (ChromaDB)
  • Hardware: r6i.xlarge (32 GB RAM)

Query: "How to reset password?"

Test A: Sin metadata filtering

results = db.query(
    query_embedding=embed("How to reset password?"),
    k=10
)

Resultados:

  • Search space: 500K docs
  • Latency: 210ms
  • Top 10 accuracy: 70% (7/10 relevantes)
    • 3 false positives (marketing con "password" mention)
  • CPU usage: 60%

Test B: Con metadata filtering (category='support')

results = db.query(
    query_embedding=embed("How to reset password?"),
    k=10,
    where={"category": "support"}
)

Resultados:

  • Search space: 50K docs (10x reducción)
  • Latency: 22ms (9.5x faster)
  • Top 10 accuracy: 95% (9.5/10 relevantes)
  • CPU usage: 8%

Ganancia:

  • 9.5x latency reduction
  • 25% accuracy improvement
  • 7.5x CPU reduction

Test C: Con multiple filters (category + language + recency)

results = db.query(
    query_embedding=embed("How to reset password?"),
    k=10,
    where={
        "category": "support",
        "language": "en",
        "timestamp": {"$gt": time.now() - 90_days}
    }
)

Resultados:

  • Search space: 8K docs (62x reducción)
  • Latency: 4ms (52x faster)
  • Top 10 accuracy: 98% (9.8/10 relevantes)
  • CPU usage: 2%

Ganancia:

  • 52x latency reduction
  • 28% accuracy improvement
  • 30x CPU reduction

Conclusión: Más filters = Mayor speedup + Mayor accuracy (si filters son relevantes).


🎯 Estrategias de Metadata Filtering para RAG

Estrategia 1: Categorical filtering

Uso: Multi-domain RAG (support + sales + product)

# User selecciona categoría en UI
category = user_input  # "support"

results = db.query(
    query_embedding=embed(query),
    where={"category": category}
)

Ventaja: User controla scope explícitamente.

Estrategia 2: Recency filtering

Uso: Documentación técnica (priorizar versiones recientes)

# Solo documentos de últimos 90 días
cutoff = time.now() - 90_days

results = db.query(
    query_embedding=embed(query),
    where={"timestamp": {"$gte": cutoff}}
)

Ventaja: Evita documentación obsoleta.

Estrategia 3: Multi-tenant filtering

Uso: SaaS RAG (aislar datos por cliente)

# Cada tenant tiene su propio namespace
results = db.query(
    query_embedding=embed(query),
    where={"tenant_id": current_user.tenant_id}
)

Ventaja: Security + performance (search en subset).

Estrategia 4: Hierarchical filtering

Uso: Documentos con jerarquía (department → team → project)

# Buscar en scope cada vez más amplio si no hay resultados
scopes = [
    {"department": "engineering", "team": "backend", "project": "api"},
    {"department": "engineering", "team": "backend"},
    {"department": "engineering"},
    {}  # Fallback: buscar en todo
]

for scope in scopes:
    results = db.query(
        query_embedding=embed(query),
        where=scope,
        k=10
    )
    if len(results) >= 5:  # Threshold
        break

Ventaja: Balance entre relevancia (narrow scope) y coverage (broad scope).


🚫 Anti-patterns comunes

Anti-pattern 1: No usar metadata filtering

# ❌ MAL: Buscar en todo sin filtros
results = db.query(query_embedding=embed(query), k=10)

# ✅ BIEN: Filtrar por contexto relevante
results = db.query(
    query_embedding=embed(query),
    where={"category": "support"},
    k=10
)

Impact: 10x latency + 25% accuracy loss.

Anti-pattern 2: Over-filtering (subset vacío)

# ❌ MAL: Filters muy específicos → 0 resultados
results = db.query(
    query_embedding=embed(query),
    where={
        "category": "support",
        "subcategory": "password",
        "language": "en",
        "region": "US-West",
        "version": "2.3.1"
    },
    k=10
)
# Resultado: 0 docs match → No devuelve nada

Fix: Usar hierarchical filtering (intentar con filters más amplios).

Anti-pattern 3: Filtering en application layer (no en DB)

# ❌ MAL: Fetch todo, filtrar en Python
all_results = db.query(query_embedding=embed(query), k=1000)
filtered = [r for r in all_results if r.metadata['category'] == 'support']
top_10 = filtered[:10]

# ✅ BIEN: Filtrar en DB
results = db.query(
    query_embedding=embed(query),
    where={"category": "support"},
    k=10
)

Impact: 10-50x latency (transfer 1000 docs vs 10), CPU waste.


✅ Checklist de comprensión

Verifica que entendiste esta cápsula:

  • ¿Qué es metadata filtering?

    • Respuesta: Buscar vectores similares SOLO en subset de docs que cumplen where clauses (e.g., category='support').
  • ¿Cuál es diferencia entre pre-filtering y post-filtering?

    • Respuesta: Pre-filtering filtra primero (faster), post-filtering busca primero (garantiza k results).
  • ¿Cuál es impact típico de metadata filtering en latency?

    • Respuesta: 10x speedup típico (200ms → 20ms) cuando filter reduce search space 90%.
  • ¿Qué operadores de filtering existen?

    • Respuesta: Equality (==), Range ($gt, $lt), Membership ($in), Logical ($and, $or, $not).
  • ¿Cuándo NO usar metadata filtering?

    • Respuesta: Cuando no tienes metadata relevante, o cuando query es muy general (buscar en todo es correcto).

Si respondiste 4-5/5 correctamente → ✅ Listo para Cápsula 03 (Hybrid Search)


🔗 Conexión con RAG

¿Cómo esto mejora tu RAG system?

Caso A: Customer Support Chatbot

Sin filtering:

User: "How do I reset my password?"
RAG busca en: 500K docs (support + marketing + legal + product)
Latency: 200ms
LLM recibe: 3 support docs + 7 marketing docs con "password"
Response quality: 70% (contaminated context)

Con filtering:

User: "How do I reset my password?"
RAG busca en: 50K docs (solo support)
Latency: 20ms (10x faster)
LLM recibe: 10 support docs relevantes
Response quality: 95%

Ganancia: 10x latency + 25% quality improvement.

Caso B: Multi-tenant SaaS RAG

Sin filtering (INSEGURO):

Tenant A query: "Show me sales data"
RAG busca en: Todos los tenants (data leakage risk!)

Con filtering (SEGURO):

Tenant A query: "Show me sales data"
RAG busca en: where={"tenant_id": "tenant_a"}
Isolation garantizado

Crítico: Security compliance (GDPR, SOC2).


🚀 Siguiente paso

Metadata filtering es feature #1 más crítica. Ahora aprenderás feature #2: Hybrid Search.

Próxima cápsula: 03 - Hybrid Search (Keyword + Semantic)

Aprenderás:

  • Por qué pure semantic search falla en queries específicos
  • Cómo combinar BM25 (keyword) + vector search (semantic)
  • Ranking strategies (RRF, weighted fusion)
  • Impact en accuracy (75% → 92%)

Clave: Metadata filtering reduce search space. Hybrid search mejora ranking dentro de ese space.


Tiempo de lectura: 10-12 minutos
Siguiente: 03-hybrid-search.md