Cómo implementar un sistema de búsqueda avanzada con Elasticsearch y filtros facetados en tu aplicación web a medida
Cómo implementar un sistema de búsqueda avanzada con Elasticsearch y filtros facetados en tu aplicación web a medida
Llega un momento en el que tu aplicación web maneja miles (o millones) de registros — productos, expedientes, fichas técnicas, documentos — y la búsqueda nativa de la base de datos se rinde. Un LIKE '%foo%' contra PostgreSQL aguanta un tiempo, pero acaba devorando CPU y dando una experiencia mediocre. Aquí es donde Elasticsearch, combinado con filtros facetados, se convierte en la pieza que tus usuarios reconocen sin saberlo de Amazon, Booking o cualquier marketplace serio.
Te cuento cómo lo monto yo: arquitectura, decisiones que ahorran disgustos y los pasos concretos para meter Elasticsearch con filtros facetados en una aplicación web a medida.
Por qué Elasticsearch y no otro motor
Elasticsearch es un motor distribuido encima de Apache Lucene. Comparado con Solr, Meilisearch o Typesense, gana en ecosistema, escalado horizontal y, sobre todo, en agregaciones potentes — que es lo que hace posible los filtros facetados sin malabares.
Razones técnicas por las que lo elijo en proyectos a medida:
- Full-text con relevancia tuneable: ponderas campos (que el título pese más que la descripción), aplicas boosting por fecha o popularidad y configuras analyzers por idioma.
- Agregaciones nativas: las facetas salen en la misma petición. Una sola query devuelve resultados y contadores.
- Escala horizontal: ¿crece el volumen? Añades nodos al clúster sin rediseñar la app.
- Ecosistema alrededor: Kibana para visualizar, Logstash y Beats para ingesta, y una API REST decente.
Ahora, si tienes 5.000 registros y un buscador sencillo, no te metas en este charco. Meilisearch o PostgreSQL con pg_trgm te sobran. Elasticsearch justifica su coste operativo cuando necesitas facetas dinámicas, autocompletado tolerante a errores y búsquedas complejas sobre varios campos.
Arquitectura: Elasticsearch como capa, no como sustituto
El error clásico es pensar que Elasticsearch reemplaza a tu base de datos. No lo hace. La arquitectura que funciona deja la base de datos relacional (PostgreSQL, MySQL) como fuente de verdad y usa Elasticsearch solo como índice de búsqueda.
Flujo de datos básico
- Escritura: la app escribe en la BD relacional (INSERT, UPDATE, DELETE).
- Sincronización: un proceso detecta cambios y actualiza el índice de Elasticsearch.
- Lectura de búsqueda: las queries van contra Elasticsearch, que devuelve IDs.
- Hidratación: la app recupera los datos completos de la BD usando esos IDs.
Estrategias de sincronización
Aquí es donde se la juega la arquitectura. Tres enfoques:
- Síncrona: indexas dentro de la misma transacción. Simple, pero acoplas el rendimiento de escritura al estado del clúster. Si Elasticsearch va lento, tus INSERTs se arrastran. No lo recomiendo en producción.
- Cola asíncrona: cada cambio publica un evento en RabbitMQ, Redis Streams o SQS. Un worker consume e indexa. Desacopla escritura de indexado y tolera caídas temporales del clúster.
- Change Data Capture (CDC): Debezium y similares leen el WAL/binlog de la BD y replican a Elasticsearch. No tocas el código de la app, pero ganas complejidad operativa.
Para la mayoría de aplicaciones a medida, la cola asíncrona da el mejor equilibrio. La latencia entre escritura y disponibilidad en búsqueda baja del segundo, y eso es aceptable salvo en casos muy concretos.
Diseño del índice y mapping de campos
El mapping decide qué puedes buscar y cómo se presentan las facetas. Cada campo necesita un tipo adecuado, y cambiarlo después implica reindexar — así que piénsalo antes.
Tipos de campo útiles para facetas
- keyword: valores exactos para filtrar (categorías, marcas, estados). No se tokenizan.
- text: contenido full-text. Se tokeniza y analiza según el idioma.
- integer / float: rangos numéricos (precio, peso, score).
- date: filtros temporales.
- nested: objetos compuestos donde la relación entre campos internos importa.
Un mapping típico para un catálogo de productos:
{
"mappings": {
"properties": {
"nombre": { "type": "text", "analyzer": "spanish" },
"descripcion": { "type": "text", "analyzer": "spanish" },
"categoria": { "type": "keyword" },
"marca": { "type": "keyword" },
"precio": { "type": "float" },
"fecha_publicacion": { "type": "date" },
"atributos": {
"type": "nested",
"properties": {
"nombre": { "type": "keyword" },
"valor": { "type": "keyword" }
}
}
}
}
}
Analyzer para español
El analyzer spanish que viene de serie aplica stemming (junta "implementación" e "implementar" en la misma raíz) y quita stopwords. Pero para una búsqueda decente conviene montar un analyzer personalizado con:
- Filtro de sinónimos: que "móvil" encuentre también "teléfono" o "smartphone".
- ASCII folding: que "búsqueda" matchee con "busqueda" sin tilde. Tus usuarios no escriben tildes, asúmelo.
- N-gramas para autocompletado: sugerencias mientras el usuario teclea.
Filtros facetados con agregaciones
Los filtros facetados son esos paneles laterales con el recuento por valor. En Elasticsearch se construyen con aggregations.
Agregaciones de términos para facetas categóricas
Para una faceta de "Categoría" con contadores:
{
"query": { "match": { "nombre": "gestión documental" } },
"aggs": {
"categorias": {
"terms": { "field": "categoria", "size": 20 }
},
"marcas": {
"terms": { "field": "marca", "size": 50 }
}
}
}
Una petición, resultados y contadores. No necesitas N queries extra.
Agregaciones de rango para facetas numéricas
Para precio o cualquier numérico:
{
"aggs": {
"rangos_precio": {
"range": {
"field": "precio",
"ranges": [
{ "to": 50 },
{ "from": 50, "to": 200 },
{ "from": 200, "to": 500 },
{ "from": 500 }
]
}
}
}
}
El gotcha del filtrado cruzado (post_filter)
Cuando el usuario marca una categoría, los contadores de otras categorías tienen que seguir mostrándose (para que pueda cambiar), pero los contadores de marca y precio deben reflejar solo lo que coincide con esa categoría. Esto se resuelve combinando post_filter con agregaciones filtradas.
La mecánica: aplicas los filtros seleccionados dentro de cada agregación excepto el filtro propio de esa faceta. Faceta de categoría enseña todas las opciones; faceta de marca enseña solo las que casan con la categoría elegida.
Con muchas facetas esto se vuelve un lío considerable. Abstráelo en un servicio que construya las queries programáticamente. Lo agradecerás al cuarto cambio.
Autocompletado y sugerencias en tiempo real
Un buscador serio sugiere mientras el usuario escribe. Elasticsearch te da varias opciones:
- Completion Suggester: estructura en memoria (FST) para sugerencias ultrarrápidas. Ideal para nombres de productos o términos frecuentes.
- Search-as-you-type: tipo de campo que genera n-gramas automáticamente. Va bien para texto libre.
- Prefix queries sobre keyword: lo más simple, pero no perdona erratas.
Lo que monto normalmente: Completion Suggester para los términos top, más una búsqueda fuzzy por debajo para tolerar fallos de tecleo. El endpoint de autocompletado tiene que responder en menos de 100 milisegundos o la experiencia se nota torpe.
Ejemplo de campo search-as-you-type
{
"nombre_sugerencia": {
"type": "search_as_you_type",
"max_shingle_size": 3
}
}
La query es un multi_match sobre los subcampos generados (nombre_sugerencia, nombre_sugerencia._2gram, nombre_sugerencia._3gram).
Rendimiento y tuning del clúster
Un buscador que tarda más de 300 ms deja de ser útil. La optimización va por capas.
Dimensionamiento de shards
Cada índice se parte en shards. La regla práctica: entre 10 y 50 GB por shard. Si tienes 100.000 productos ocupando 2 GB, un solo shard primario sobra. No, no necesitas un cluster de 15 nodos para 50.000 documentos — sobredimensionar shards solo añade overhead.
Caché de queries
Elasticsearch cachea filtros frecuentes solo. Para sacarle partido, separa la parte de filtrado (cacheable) de la de scoring (no cacheable) usando bool con cláusulas filter en vez de must. Pequeño cambio, impacto medible.
Métricas que hay que vigilar
- Latencia P95: percentil 95 del tiempo de respuesta. Objetivo: por debajo de 200 ms.
- Tasa de indexación: documentos por segundo. Detecta cuellos de botella en la sincronización.
- Heap JVM: si pasa del 75% sostenido, necesitas más memoria o más nodos. Punto.
- Merge throttling: si los merges de segmentos Lucene están limitando la escritura.
Kibana trae dashboards predefinidos para todo esto con Stack Monitoring. Úsalos, no reinventes la rueda.
Seguridad y control de acceso
Si distintos usuarios ven distintos subconjuntos de datos, la búsqueda tiene que respetar permisos. Dos enfoques:
- Filtrado en aplicación: el backend añade un filtro de permisos a cada query (por ejemplo
"filter": {"term": {"tenant_id": "cliente-123"}}). Simple y efectivo para multitenancy. - Document Level Security (DLS): Elasticsearch con licencia Platinum o superior permite roles que limitan qué documentos ve cada usuario. Útil cuando varias apps tocan el mismo clúster.
En desarrollos a medida casi siempre voy con filtrado en aplicación: no dependes de licencias comerciales y la lógica de permisos se queda centralizada en el backend, que es donde tiene que estar.
Cuándo un buscador facetado cambia las reglas
Meter Elasticsearch con filtros facetados transforma la experiencia en aplicaciones con volúmenes importantes de datos estructurados. Catálogos de producto, portales inmobiliarios, bases de conocimiento, gestión documental — todos estos casos ganan con una búsqueda que no solo encuentra, sino que deja explorar y refinar.
El esfuerzo no es trivial: diseñas la sincronización, defines mappings, construyes las agregaciones con filtrado cruzado y tuneas el clúster. Pero el retorno en usabilidad y reducción de tiempo de búsqueda lo paga con creces.
Si tu equipo está dándole vueltas a integrar búsqueda avanzada en una aplicación existente o arrancando un desarrollo nuevo que va a manejar mucho dato, hablemos del diseño técnico que encaja con tu caso.
Artículos relacionados
Te puede interesar
Preguntas frecuentes sobre
Como mejorar mi negocio con la metodología Anticompetencia
En Tangram no queremos que la información pase por una cadena interminable de intermediarios donde se pierden los detalles importantes.
Contarás con un interlocutor que coordinará la comunicación y trasladará las decisiones al equipo responsable de tu proyecto.
Cuando sea necesario profundizar en cuestiones de estrategia, diseño o tecnología, podremos involucrar a los especialistas correspondientes.
Así tendrás una comunicación organizada, sin necesidad de gestionar personalmente a todos los profesionales que intervienen.
Queremos que tengas acceso al conocimiento de un equipo especializado, sin sufrir la complejidad de coordinarlo.
No tendrás que averiguar a quién escribir cada vez que tengas una duda.
En Tangram contemplamos la figura del Account Manager como interlocutor principal, encargado de acompañarte durante el proyecto, coordinar la comunicación y facilitar el seguimiento de las decisiones.
Nuestra metodología incluye reuniones de revisión, canales de comunicación y herramientas para que puedas participar en el trabajo.
La organización concreta, la frecuencia de las reuniones y los canales disponibles se establecerán según el proyecto contratado.
Lo importante es que sepas con quién hablar, en qué punto está tu proyecto y qué decisiones necesitan tu participación.
Sí, podemos valorar una colaboración con los profesionales que ya trabajan en tu empresa.
No siempre tiene sentido sustituir un equipo que conoce bien tu negocio. En muchas situaciones, lo más útil es complementar sus conocimientos con especialistas en determinadas áreas.
Podemos estudiar qué responsabilidades asumiría Tangram, cuáles mantendría tu equipo y cómo coordinar las decisiones para evitar duplicidades.
La forma concreta de colaboración dependerá de la organización, las herramientas y las necesidades del proyecto.
No se trata de reemplazar lo que ya funciona, sino de aportar el conocimiento que necesitas para llegar más lejos.
No tienes por qué cambiar de proveedor para explorar una colaboración con Tangram.
Durante nuestra trayectoria hemos trabajado con agencias y consultoras, participando en proyectos en los que cada empresa asumía una parte diferente del trabajo.
Esa experiencia nos permite comprender la importancia de definir responsabilidades y coordinar a los profesionales implicados.
Podemos valorar una colaboración para cubrir necesidades concretas que tu proveedor actual no ofrece o para reforzar determinadas áreas.
Si tienes una relación profesional que funciona, no queremos que la rompas sin motivo. Queremos encontrar dónde podemos aportar valor.
La confidencialidad es especialmente importante cuando hablamos de nuevas ideas de negocio, información económica, estrategias comerciales o desarrollos tecnológicos.
En Tangram tenemos experiencia trabajando en proyectos sujetos a acuerdos de confidencialidad, motivo por el que no podemos mostrar públicamente muchos de los trabajos en los que hemos participado.
Si tu proyecto requiere un acuerdo de confidencialidad (NDA) antes de compartir información sensible, podemos revisar sus condiciones y acordar cómo proteger esa información antes de entrar en los detalles.
Entendemos que la confianza empieza por respetar lo que todavía no quieres hacer público.