Quel outil choisir pour utiliser Elasticsearch dans un projet Symfony

Comment utiliser Elasticsearch dans un projet Symfony? Quelle librairie ou bundle utiliser? Ce sont des questions que je lis fréquemment sur les slack communautaires. Je ne vais pas vous écrire un guide complet mais vous donner mon avis sur les différentes solutions que j'ai utilisées ou rencontrées.

J'ai découvert Elasticsearch au ForumPHP en 2014 et je l'utilise depuis 2016 sur ce blog, sur un site e-commerce à fort traffic, sur des applications métiers pour construire des dashboards...

API REST

Elasticsearch propose une API REST pour gérer les index et leur contenu et faire des requêtes dessus. Il est donc possible d'utiliser Elasticsearch avec le composant HttpClient de Symfony sans avoir besoin de rajouter une dépendance. Cela implique qu'il va falloir gérer à la main la connection au cluster, connaitre toutes les URL de l'API et suivre les mise à jour d'ES de près. Je ne pense pas que ce soit le meilleur choix, à terme il y a un risque de maintenance importante du code, comme ça a été le cas quand Elasticsearch a supprimé les type dans les index.


La librairie Elasticsearch-php

La librairie elasticsearch-php est un client simple pour utiliser Elasticsearch. Il abstrait les endpoints de l'API d'ES et simplifie la connexion au cluster. De plus cette librairie est maintenue par l'équipe d'Elasticsearch, elle suit donc les mises à jour au plus près.
Son utilisation est facile, il suffit de lui donner les documents à indexer au format JSON ou en tableau associatif. Pour faire une requête sur l'index, c'est pareil un JSON ou un tableau associatif. Les réponses sont sous forme d'un tableau associatif.
Cette librairie est mon choix par défaut. J'ai pour habitude d'utiliser des JSON dans les requêtes ce qui me permet de facilement les construire  et les débuger dans Kibana. Cette approche me permet aussi d'apprendre la structure des requêtes. J'ai écris un article sur ce blog pour utiliser ce client Elasticsearch dans une projet Symfony en utilisant Twig.
Pour rester dans une démarche objet de bout en bout, il suffit d'utiliser le composant Serializer de Symfony pour transformer les réponses de l'API en objet. Là aussi, j'ai pour habitude d'utiliser l'interface Symfony\Component\Serializer\Normalizer\DenormalizableInterface qui me permet de mettre au plus prés la logique de dénormalisation pour reconstruire des données parfois complexe issuent de plusieurs agrégats quand je travaille sur des dashbaord.


La librairie Rufflin Elastica

La librairie elasticsearch-php couplé à Twig est adapté quand les requêtes sur l'index sont fixes. C'est à dire quand on ne change que des valeurs.
S'il y a un besoin de construire une requête dynamiquement, le faire avec Twig rendrait le template vite illisible et difficile à maintenir et je ne pense pas que l'utilisation d'un tableau associatif soit mieux.
Dans ce cas, la librairie Elastica offre une abstraction objet pour construire les requêtes Elasticsearch, un peu comme le QueryBuilder de Doctrine. Je l'utilise sur un site ecommerce pour gérer la recherche avec les filtres sélectionnés par l'utilisateur.
En arrière plan, Elastica utilise la librairie elasticsearch-php, il est donc possible de mixer les 2 approches en utilisant l'abstraction proposée par Elastica en complément d'un approche plus simple. Cela permet aussi d'upgrader facilement d'elasticsearch-php à Elastica si le besoin s'en fait sentir.

Le bundle Friend Of Symfony Elastica bundle

Ce bundle revient très souvent dans les discussions et je pense qu'il est le premier choix des développeurs qui découvrent Elasticsearch.
Il propose une intégration de la librairie Elastica dans Symfony. Mais surtout il offre une gestion "magique" des documents indexés dans Elasticsearch en se couplant aux entités Doctrine par l’intermédiaire des events lifecycle de ce dernier.
Sur le papier ça semble sexy, mais au final on se retrouve très souvent avec des documents qui ressemblent aux entités, ce qui est une erreur. J'ai toujours dénormalisé le contenu que j'index dans ES pour qu'il soit adapté à mes requêtes et j'utilise plusieurs index si besoin.
Un autre problème est le manque de maitrise du moment de l'indexation. L'utilisation de l'asynchrone pour réduire le temps de réponse des pages n'est pas natif. Et si l'on souhaite tout réindexer suite à un changement de mapping, il faut passer par une commande qui va itérer sur toute la bdd. On connais tous les problèmes de performance des ORM sur les grosses volumétrie, je vous laisse imaginer la ré indexation d'un catalogue ecommerce de 5 millions d'articles.
Et le dernier point négatif et la mise à jour de ce bundle vis à vis d'Elasticsearch ou de Symfony, cela prend en général du temps et bloque la mise à jour du projet.


Je ne vais pas parler de toutes les solutions qui existe, il en a d'autre comme Elastically proposé par Jolicode qui ajoute des fonctionnalités à la librairie Elastica. J'espère que cet article répondra aux questions que se pose les dev qui envisage de commencer l'utilisation d'Elasticsearch avec Symfony.

Ajouter un commentaire