Elasticsearch tu t’entends quand tu analyses ?

UPDATE [30/10/2017]: La pull request n'a pas été acceptée, le plugin est donc publié sur mon github personnel. N'hésitez pas à le consulter à cette adresse: french-phonetic-analyser. Je n'ai pour l'instant publié le plugin que pour les versions 5X et 6X d'elasticsearch. Si vous désirez des versions plus anciennes faites moi signe, via une issue ou mieux encore une pull request.

Depuis quelques temps maintenant, je suis en poste chez un client très connu dans le monde de la mode :

GL_LOGO2L_N

On m’a donné comme mission simple : la gestion de clients qui inclut leurs recherches, leurs créations et la modification de leurs informations. Rien de plus simple : un client c’est quoi un nom, un prénom, une ou plusieurs coordonnées postales/mails/téléphoniques ? OK mais la mission est devenue un brin plus compliquée quand on m’a dit : “Je ne veux pas de doublons dans mes clients”.

Le PO de l’équipe en relation avec le métier (oui aux Galeries, l’agilité ce n’est pas un buzz-word) s’est dit que le plus simple pour ne pas avoir de doublons en création est d’être capable de retrouver facilement une personne existante aux différents points d’entrées où les clients peuvent être créés, par exemple, en caisse ou au service client. Sauf que la personne qui est en caisse n’a pas vraiment le temps de retrouver tous les homonymes que M.Dupon(d/t/_) peut avoir. C’est donc à l’application de fournir une recherche simple et performante qui pourrait corriger les erreurs d’orthographe, de frappe et autres subtilités de mise en situation.

Pour la recherche, on s’est naturellement tourné vers Elasticsearch : https://www.elastic.co/. Je ne fais plus les présentations tout le monde connaît, si ce n’est pas le cas je vous renvoie vers nos articles de blog sur le sujet : /tag/elasticsearch/

Les solutions envisagées pour une recherche rapide et efficace

La recherche fuzzy

Tout d’abord, on est parti sur la recherche fuzzy. Le principe de cette recherche est basé sur une distance de Levenshtein, qui pour simplifier calcule un score pour les mots sur le nombre de lettres erronées, ajoutées ou manquantes. Cette recherche est très bien pour corriger de légères erreurs de frappe ou pour trouver les personnes avec un nom ayant une ou deux lettres de différence, ex: Dupont et Dupond.

Tips: Sur Elasticsearch, une recherche fuzzy ayant une configuration avec une distance de 2 ou moins ne fera pas un full scan de l’index et sera extrêmement rapide.

Malheureusement, on arrive vite à la limite de ce genre de recherche quand on découvre que la distance calculée ne rentre pas en compte dans le scoring des documents et donc le tri des résultats. Il faut donc la coupler avec une autre sur la recherche exacte pour avoir plus de pertinence mais cela ne devient pas parfait. Par exemple : si on recherche Menard, il se peut que Monaro arrive avant Menart et même faire remonter une personne s’appelant Menardes.

Ce n’était pas totalement concluant. Alors, on est passé à une autre méthode.

La recherche avec les plugins phonétiques existants

Actuellement il existe des plugins phonétiques pour les langues latines. Nous avons essayé et démontré au PO l’utilisation de double metaphone et aussi de soundex. Leurs principes sont assez rudimentaires. En résumé : ils enlèvent toutes les voyelles et suivant l’algorithme choisi, ils remplacent certaines lettres par une même combinaison. Par exemple, les D et T sont équivalents. Ainsi, Meyrat est “traduit” en MRT, du coup Maret est aussi un équivalent à Meyrat. La limite s’impose d’elle-même : le nombre de résultats retournés est beaucoup trop important et notre personne à la caisse va passer son temps à retrouver le bon client.

Création d’un plugin phonétique français

Notre PO comprend rapidement que ce qu’il désire c’est du phonétique parlé. Donc après la phase d’appréhension de devoir coder son propre plugin phonétique et quelques recherches sur la prononciation, je me rends compte qu’on peut arriver à un meilleur résultat en implémentant de simples règles trouvées sur wikipédia à cette adresse: https://fr.wikipedia.org/wiki/Prononciation_du_fran%C3%A7ais#Prononciation_des_graph.C3.A8mes

Quelques heures passées à coder et à tester mon plugin, le résultat est assez probant (ndlr : coder son propre plugin de filtre de token n’est au final pas si difficile). Mon PO recherche Meyrat et retrouve tous les homonymes tels que Meirra, Merra sans personne d’autre. Jackpot !!!

J’ai aussi fait des micro-benchmarks sur la méthode d’encodage de mon plugin avec JMH et j’obtiens les mêmes performances que les plugins phonétiques existants.

Pour poursuivre

Bon tout ça c’est sympa, mais cela vous apporte quoi à vous lecteurs ?

La réponse se trouve dans l’une des valeurs de Galeries Lafayette, l’audace d’innover : les Galeries Lafayette m’ont permis d’open-sourcer ce plugin. Je remercie les Galeries Lafayette et plus particulièrement mes managers G. Minchella et S. Daubies de leur confiance. En effet, toutes les sociétés ne sont pas aussi coopératives avec la communauté.

Une Pull Request est en cours d’étude chez Elastic, mais vous pouvez dès à présent retrouver le code sur mon fork : https://github.com/elastic/elasticsearch/pull/15996

Je vais aussi en faire un comparator pour Duke ce qui sera très utile pour retrouver des doublons dans un échantillon de données existant et non dédoublonné.
N’hésitez à me transmettre les cas d’utilisations que vous trouveriez, ça m’intéresse.