Integración de Elasticsearch en PrestaShop para búsqueda avanzada
Imagina un catálogo con miles de productos, variantes, combinaciones y atributos. El motor de búsqueda nativo de PrestaShop, basado en MySQL, empieza a mostrar sus limitaciones: búsquedas lentas, resultados imprecisos, nula capacidad para manejar sinónimos o corrección ortográfica, y una experiencia de usuario que se resiente. La solución madura y escalable para este problema es la integración de Elasticsearch en PrestaShop.
Este motor de búsqueda distribuido, basado en Lucene, no solo acelera las consultas, sino que permite implementar una búsqueda avanzada ecommerce con filtros dinámicos, búsqueda por facetas, autocompletado inteligente y ranking por relevancia. En este artículo, exploraremos cómo integrar Elasticsearch en PrestaShop, las ventajas técnicas, la configuración del stack y cómo optimizar los filtros productos PrestaShop para maximizar las conversiones.
¿Por qué Elasticsearch y no MySQL para la búsqueda?
El principal cuello de botella en tiendas grandes es el uso de LIKE %texto% en MySQL. Esto fuerza un escaneo completo de tablas, consumiendo CPU y bloqueando lecturas. Elasticsearch, en cambio, indexa los datos en un formato invertido (inverted index) que permite búsquedas full-text en milisegundos.
Beneficios clave para tu tienda
- Velocidad: Las consultas de búsqueda se reducen de segundos a milisegundos.
- Relevancia: Algoritmos de scoring (TF-IDF, BM25) que priorizan productos con mayor coincidencia semántica.
- Facetas en tiempo real: Filtros por precio, talla, color, marca sin recargar la página.
- Sugerencias y autocompletado: Búsqueda predictiva mientras el usuario escribe.
- Tolerancia a fallos: Clusterización horizontal, sin punto único de fallo.
[INFO] Elasticsearch no reemplaza a MySQL como base de datos principal. Actúa como una capa de indexación separada para consultas de búsqueda, dejando las transacciones (carrito, pedidos) en la base de datos relacional.
Preparando el entorno: Stack técnico necesario
Antes de integrar, necesitas tener Elasticsearch corriendo. Puedes hacerlo en un servidor dedicado, un contenedor Docker o usar un servicio cloud (Elastic Cloud, AWS OpenSearch).
Instalación básica con Docker (recomendado para desarrollo)
docker run -d --name elasticsearch \
-p 9200:9200 -p 9300:9300 \
-e "discovery.type=single-node" \
-e "xpack.security.enabled=false" \
docker.elastic.co/elasticsearch/elasticsearch:8.12.0
Verifica que funcione:
curl -X GET "localhost:9200/"
Deberías recibir un JSON con el nombre del cluster y la versión.
Requisitos de PrestaShop
- PrestaShop 1.7.x o 8.x (preferiblemente 8+ para mejor compatibilidad con módulos modernos).
- PHP 7.4+ con extensión
curlyjsonhabilitadas. - Módulo de integración: Puedes optar por módulos gratuitos como "Elasticsearch PrestaShop" de la comunidad, o soluciones premium como "Search Elastic" de Store Commander o "Elasticsearch Pro" de Knowband.
[WARNING] No uses el módulo oficial "PrestaShop Search" con Elasticsearch si no está diseñado para ello. Busca módulos que implementen el motor de búsqueda como reemplazo del nativo.
Integración paso a paso con un módulo personalizado
Para un control total, puedes desarrollar un módulo propio que sincronice productos con Elasticsearch. Aquí te muestro la estructura básica.
1. Creación del índice y mapping
Define un mapping en Elasticsearch que refleje los campos relevantes de producto en PrestaShop.
PUT /prestashop_products
{
"settings": {
"analysis": {
"analyzer": {
"spanish_analyzer": {
"type": "standard",
"stopwords": "_spanish_"
}
}
}
},
"mappings": {
"properties": {
"id_product": { "type": "integer" },
"name": {
"type": "text",
"analyzer": "spanish_analyzer",
"fields": {
"keyword": { "type": "keyword" }
}
},
"description": { "type": "text", "analyzer": "spanish_analyzer" },
"price": { "type": "float" },
"category": { "type": "keyword" },
"attributes": { "type": "nested" },
"stock": { "type": "integer" },
"active": { "type": "boolean" }
}
}
}
2. Hook de sincronización en PrestaShop
En tu módulo, implementa hooks como actionObjectProductAddAfter, actionObjectProductUpdateAfter y actionObjectProductDeleteAfter para mantener el índice actualizado.
public function hookActionObjectProductAddAfter($params)
{
$product = $params['object'];
$this->indexProduct($product);
}
private function indexProduct($product)
{
$body = [
'id_product' => $product->id,
'name' => $product->name[Context::getContext()->language->id],
'description' => strip_tags($product->description[Context::getContext()->language->id]),
'price' => (float)$product->price,
'category' => $this->getCategoryPath($product->id),
'attributes' => $this->getAttributes($product->id),
'stock' => (int)StockAvailable::getQuantityAvailableByProduct($product->id),
'active' => (bool)$product->active
];
$client = $this->getElasticClient();
$client->index([
'index' => 'prestashop_products',
'id' => $product->id,
'body' => $body
]);
}
3. Reemplazar el controlador de búsqueda
Crea un override del controlador SearchController para que use Elasticsearch en lugar de la consulta SQL nativa.
class SearchController extends SearchControllerCore
{
public function initContent()
{
parent::initContent();
$query = Tools::getValue('search_query');
$results = $this->searchElastic($query);
$this->context->smarty->assign([
'products' => $results,
'nbProducts' => count($results)
]);
}
private function searchElastic($query)
{
$client = $this->getElasticClient();
$params = [
'index' => 'prestashop_products',
'body' => [
'query' => [
'multi_match' => [
'query' => $query,
'fields' => ['name^3', 'description', 'category'],
'fuzziness' => 'AUTO'
]
],
'size' => 20
]
];
$response = $client->search($params);
return $this->formatResults($response);
}
}
Implementando búsqueda avanzada ecommerce con facetas
La verdadera potencia de Elasticsearch reside en las agregaciones (aggregations). Permiten generar filtros productos PrestaShop dinámicos sin consultas adicionales a la base de datos.
Configuración de facetas en la consulta
{
"query": { "match": { "name": "zapatilla" } },
"aggs": {
"por_precio": {
"range": {
"field": "price",
"ranges": [
{ "to": 50 },
{ "from": 50, "to": 100 },
{ "from": 100 }
]
}
},
"por_marca": {
"terms": { "field": "attributes.brand.keyword", "size": 10 }
},
"por_talla": {
"terms": { "field": "attributes.size.keyword", "size": 20 }
}
}
}
Renderizado en Front Office
En la plantilla search.tpl, añade un bloque de filtros que recorra las agregaciones devueltas por Elasticsearch.
<div class="filters">
<h3>Filtrar por precio</h3>
{foreach from=$aggregations.por_precio.buckets item=bucket}
<label>
<input type="checkbox" name="price_range" value="{$bucket.from}-{$bucket.to}">
{$bucket.from|default:'0'} - {$bucket.to|default:'∞'} ({$bucket.doc_count})
</label>
{/foreach}
<h3>Marca</h3>
{foreach from=$aggregations.por_marca.buckets item=bucket}
<label>
<input type="checkbox" name="brand" value="{$bucket.key}">
{$bucket.key} ({$bucket.doc_count})
</label>
{/foreach}
</div>
[TIP] Para mejorar la UX, usa AJAX para recargar solo los resultados y las facetas cuando el usuario selecciona un filtro. Puedes implementarlo con un pequeño script JavaScript que llame a un endpoint personalizado.
Optimización de rendimiento y mantenimiento
Indexación incremental vs completa
No reindexes todo el catálogo cada vez. Implementa colas de mensajes (RabbitMQ, Redis) para procesar actualizaciones de productos en lotes pequeños.
# Script de reindexación completa (programar en cron nocturno)
php bin/console prestashop:elasticsearch:reindex --index=prestashop_products
Monitoreo del cluster
Usa Kibana o herramientas como Cerebro para monitorizar la salud del cluster.
# Ver estado del cluster
curl -X GET "localhost:9200/_cluster/health?pretty"
Ajustes de relevancia
Personaliza el scoring usando function_score para dar más peso a productos en stock o con mejores valoraciones.
{
"query": {
"function_score": {
"query": { "match": { "name": "zapatilla" } },
"functions": [
{ "filter": { "term": { "stock": { "gte": 1 } } }, "weight": 2 },
{ "field_value_factor": { "field": "rating", "factor": 1.5 } }
],
"boost_mode": "multiply"
}
}
}
Casos de uso avanzados
Búsqueda por sinónimos
Configura un filtro de sinónimos en el analyzer para que "zapatilla" también encuentre "tenis" o "sneaker".
"filter": {
"synonym_filter": {
"type": "synonym",
"synonyms": [
"zapatilla, tenis, sneaker, deportiva",
"camiseta, remera, t-shirt"
]
}
}
Autocompletado con sugerencias
Implementa un endpoint que devuelva sugerencias basadas en el prefijo escrito.
{
"suggest": {
"product_suggest": {
"prefix": "zapa",
"completion": {
"field": "name.suggest"
}
}
}
}
Consideraciones finales y mejores prácticas
- Seguridad: No expongas Elasticsearch directamente a internet. Usa un proxy inverso (Nginx) con autenticación básica o mejor aún, una VPN.
- Backups: Realiza snapshots periódicos del índice.
- Pruebas de carga: Antes de ir a producción, prueba con un volumen de datos similar al real usando herramientas como Apache JMeter.
- Costes: Elasticsearch consume RAM. Para catálogos de hasta 50.000 productos, 4GB RAM son suficientes. Para más de 500.000, considera clusters de 3 nodos.
[INFO] Si tu tienda tiene menos de 5.000 productos y no esperas crecimiento exponencial, quizás no necesites Elasticsearch. La búsqueda nativa con MySQL y un buen caché puede ser suficiente. Pero si ya sufres lentitud, esta integración es tu mejor inversión en UX.
Integrar Elasticsearch en PrestaShop no es un proyecto trivial, pero los beneficios en velocidad, relevancia y capacidad de filtrado transforman la experiencia de compra. Una búsqueda avanzada ecommerce bien implementada reduce la fricción, aumenta el tiempo en sesión y, en última instancia, mejora la tasa de conversión. Los filtros productos PrestaShop dejan de ser un simple checkbox y se convierten en un sistema dinámico que guía al usuario hacia lo que busca, incluso cuando no sabe exactamente cómo llamarlo.
¿Listo para dar el salto? Empieza por un entorno de pruebas, indexa un subconjunto de productos y mide la diferencia. Tu servidor (y tus clientes) te lo agradecerán.
