Busqueda semantica en documentos con Qdrant

Basándome en la documentación oficial de Qdrant, aquí está el diseño completo para una colección eficiente de búsqueda semántica en documentos largos:
Diseño de Colección Qdrant para Documentos Largos
- Estrategia de Chunking (Fragmentación)
Los documentos largos deben dividirse en fragmentos manejables debido a los límites de contexto de los modelos de embeddings:
RAG_REFERENCES:
(RAG: Fuente Externa) Pinecone — «El chunking superpuesto es esencial para preservar el contexto semántico en los límites de los fragmentos»
(RAG: Documento 1) Artículo sobre Vectores Dispersos — «Cada chunk se convertirá en un punto vectorial en Qdrant»
Recomendaciones:
Tamaño de chunk: 256-512 tokens (dependiendo del modelo de embedding)
Solapamiento: 10-20% entre chunks consecutivos
Payload por chunk: chunk_index, total_chunks, chunk_text, document_id
- Esquema de Colección y Payload
SCHEMA_PLAN:
Estructura de payload recomendada
payload_schema = {
"document_id": str, # ID único del documento original
"chunk_index": int, # Índice secuencial del chunk (0-based)
"total_chunks": int, # Número total de chunks en el documento
"chunk_text": str, # Texto del chunk (opcional, para debugging)
"document_title": str, # Título del documento
"document_type": str, # Tipo: "report", "email", "legal", "article"
"author": Optional[str], # Autor del documento
"creation_date": datetime, # Fecha de creación
"language": str, # Idioma: "es", "en", etc.
"section_header": Optional[str], # Encabezado de sección si existe
"tenant_id": str, # Para multitenencia (opcional)
"metadata": dict # Metadatos adicionales flexibles
}
- Configuración de Colección
CONFIG_SNIPPET:
from qdrant_client import QdrantClient, models
client = QdrantClient("localhost", port=6333)
client.create_collection(
collection_name="document_chunks",
vectors_config=models.VectorParams(
size=768, # Dimensión del embedding (ej: all-MiniLM-L6-v2)
distance=models.Distance.COSINE, # Mejor para similitud semántica
),
# Opcional: soporte para búsqueda híbrida con vectores dispersos
sparse_vectors_config={
"text-sparse": models.SparseVectorParams()
},
# Configuración de réplicas para producción
replication_factor=2, # 2-3 réplicas para alta disponibilidad
# Configuración HNSW optimizada para documentos
hnsw_config=models.HnswConfigDiff(
m=16, # Número máximo de conexiones por nodo
ef_construct=200, # Calidad del grafo durante construcción
full_scan_threshold=10000, # Umbral para búsqueda exhaustiva
),
# Optimización para filtros frecuentes
optimizers_config=models.OptimizersConfigDiff(
default_segment_number=2,
max_segment_size=50000, # Tamaño máximo de segmento
)
)
- Parámetros de Indexación HNSW
INDEX_PLAN:
m = 16-32: Balance entre precisión y memoria
ef_construct = 200-400: Para documentos donde la precisión es crítica
ef_search = 100-200: Ajustable según requerimientos de latencia
RAG_REFERENCES:
(RAG: Documento 1) — «Para una colección de chunks de documentos, donde la precisión es crucial pero el volumen puede ser alto, se recomienda priorizar ef_construct y m moderadamente altos durante la indexación»
- Estrategia de Filtrado y Multitenencia
Patrones de consulta eficientes:
Búsqueda dentro de un documento específico
filters = models.Filter(
must=[
models.FieldCondition(
key="document_id",
match=models.MatchValue(value="doc_123")
)
]
)
Búsqueda multitenencia
filters = models.Filter(
must=[
models.FieldCondition(
key="tenant_id",
match=models.MatchValue(value="tenant_a")
),
models.FieldCondition(
key="document_type",
match=models.MatchValue(value="report")
)
]
)
RAG_REFERENCES:
(RAG: Documento 3) Guía de Multitenencia — «Las consultas siempre deben incluir un filtro por tenant_id para implementar multitenencia básica»
- Búsqueda Híbrida (Opcional)
Para mejorar la precisión:
Búsqueda híbrida densa + dispersa
results = client.search_batch(
collection_name="document_chunks",
requests=[
models.SearchRequest(
vector=models.NamedVector(
name="text-dense",
vector=dense_embedding
),
filter=filters,
limit=10,
with_payload=True
),
models.SearchRequest(
vector=models.NamedSparseVector(
name="text-sparse",
vector=sparse_embedding
),
filter=filters,
limit=10,
with_payload=True
)
]
)
RAG_REFERENCES:
(RAG: Documento 2) Artículo sobre Búsqueda Híbrida — «Combinar resultados de búsqueda densa y dispersa mediante Fusión de Rango Recíproco (RRF) es rápido y está integrado en Qdrant»
- Patrones de Upsert y Mantenimiento
Estrategia de upsert:
def upsert_document_chunks(document_id: str, chunks: List[Dict]):
points = []
for i, chunk in enumerate(chunks):
point = models.PointStruct(
id=f"{document_id}_{i}", # ID único compuesto
vector=generate_embedding(chunk["text"]),
payload={
"document_id": document_id,
"chunk_index": i,
"total_chunks": len(chunks),
"chunk_text": chunk["text"],
"document_title": chunk.get("title", ""),
"document_type": chunk.get("type", "unknown"),
"creation_date": chunk.get("date"),
"language": chunk.get("language", "es"),
"section_header": chunk.get("section", ""),
"tenant_id": chunk.get("tenant_id", "default")
}
)
points.append(point)
client.upsert(
collection_name="document_chunks",
points=points,
wait=True # Esperar confirmación para consistencia
)
- Consideraciones de Rendimiento
RESULTS_PREVIEW:
Tiempo de búsqueda: 10-50ms para colecciones de hasta 1M de chunks
Recall objetivo: 95%+ con ef_search=200
Carga de memoria: ~1GB por 1M de vectores de 768 dimensiones
Throughput: 100-1000 QPS dependiendo de la configuración de réplicas
- Mejores Prácticas
Normalización de embeddings: Asegurar que todos los vectores estén normalizados para distancia coseno
Índices de payload: Crear índices para campos de filtro frecuentes:
client.create_payload_index(
collection_name=»document_chunks»,
field_name=»document_id»,
field_schema=models.PayloadSchemaType.KEYWORD
)
Monitoreo: Seguir métricas de recall, latencia y uso de memoria
Backup regular: Usar snapshots para recuperación ante desastres - Escalabilidad
Sharding automático: Qdrant distribuye datos automáticamente
Réplicas: 2-3 réplicas para alta disponibilidad y escalado de lecturas
Segmentos: Ajustar max_segment_size según el tamaño de la colección
RAG_REFERENCES:
(RAG: Documento 4) Clúster Multi-nodo — «Para pruebas de carga y alta disponibilidad, desplegar un clúster multi-nodo»
Este diseño proporciona una base sólida para búsqueda semántica eficiente en documentos largos, balanceando precisión, rendimiento y escalabilidad.
Generado por el modelo:







