ElasticSearch comme nouveau standard de la recherche applicative

Lorsque que vous devez mettre en place un moteur de recherche dans votre application Web, différentes solutions s’offrent à vous, en fonction de vos données, de la manière dont elles sont stockées, de leur taille, de vos objectifs…

C’est un domaine dans lequel plus le temps passe, plus votre application stocke des données, et plus la recherche se complexifie. Un mauvais choix sur cette brique applicative n’est donc pas forcément visible immédiatement mais le sera sur le long terme.

État de l’art de ce qu’il ne faudrait plus faire

Vous ne pouvez pas confier à un SGBD des millions d’enregistrements si vous souhaitez y faire de la recherche « full text » avec un scoring sérieux rapidement et sans douleur, ces outils sont rarement fait pour exécuter de telles requêtes. Malgré cela, une bonne partie des applicatifs PHP open source usent du pire dans leur configuration par défaut.

Si nous prenons l’exemple de Wordpress, voici ce qui est dit sur la recherche1 :

WordPress has killer search baked in. Every word you write is fully searchable […]

Ce n’est pas exactement ce que j’appellerai une « killer search ». Tous les mots écrits peuvent être recherchés, mais grâce a une simple requête LIKE2 :

$search .= "{$searchand}(($wpdb->posts.post_title LIKE '{$n}{$term}{$n}') OR ($wpdb->posts.post_content LIKE '{$n}{$term}{$n}'))";

Dans la table posts, seul le champ title est indexé, cela veut dire que si vous recherchez « toto » dans un blog avec 1000 articles, les 1000 articles doivent être parcourus par le moteur de stockage. Plus votre blog contient d’articles, et plus la recherche sera lente, car dépendante d’une fonctionnalité de votre SGBD qui n’est pas faite pour scaler. Et que dire de la pertinence de ce type de recherche ! Comment être sûr que l’article avec le plus d’occurrences du mot recherché sera remonté en premier ?

Poursuivons avec FluxBB, un moteur de forum en PHP. On passe au niveau superieur, plutôt que d’effectuer une recherche LIKE dans des champs text, chaque message est séparé en token (chaque mot est un token). Ces tokens sont rattachés aux messages dont ils sont extraits via une table de liaison : la requête est un poil plus complexe mais les résultats plus rapides et pertinents… jusqu’à une certaine limite. Si vos utilisateurs produisent des messages d’environ 20 mots, votre table de liaison pun_search_matches contiendra 2 millions d’enregistrements dès les 100 000 premiers message. Pas étonnant que les gros forums FluxBB tels que UbuntuFR passent par Google pour la recherche, car avec presque 5 millions de messages, celle du logiciel atteint rapidement les limites d’un MySQL.

Ces produits ont tous les deux une contrainte qui les pousse à utiliser le SGBD pour la recherche : il s’agit de solutions clé en main, qui doivent être aisément installables par n’importe quel utilisateur de PHP sur son hébergement mutualisé Lycos.

Votre application et vos clients méritent mieux que ça.

Introducing ElasticSearch

ElasticSearch logoElasticSearch est un logiciel champion du buzzword bingo3 :

  • Open source ;
  • REST (HTTP) ;
  • JSON ;
  • Cluster ;
  • Scalable et distribué ;
  • Temps réel ;
  • NoSQL ;
  • Big data ;
  • Lucene.

C’est en Java, c’est super simple à installer et à distribuer, il n’y a pas de mapping ou de configuration obligatoire à faire. Il est utilisé, entre autres, par GitHub, Soundcloud, StackOverflow ou encore Foursquare.

Pour reprendre l’exemple du forum FluxBB, chaque message serait alors un document JSON :

{
    "post_id": 42,
    "topic_id": 2,
    "content": "ElasticSearch is also usefull for logs storage and logs analysis.",
    "author": {
        "name": "Damien",
        "author_id": 1
    }
}

Le seul travail du développeur est de dénormaliser le message et ses relations en fonction des besoins de recherche. Ce petit document s’indexe via une requête HTTP sur l’API d’ElasticSearch. Il est ensuite analysé et devient une série de token dans Lucene.

Nous pouvons désormais chercher ce document :

  • avec un filtre par auteur ;
  • avec un score de pertinence ;
  • par n’importe quel mot (Damien, logs…) ;
  • avec des facettes ;
  • avec des suggestions…

Je vous parle des facettes, car c’est la feature qui produit le plus l’effet « Whaou! ». Indexons d’autres messages avec d’autres auteurs et d’autres contenus (exemple exécutable dans ce gist).

Faire une recherche sur ces articles est très simple :

{
  "query": {
    "term": {
       "_all": {
        "value": "logs"
       }
    }
  }
}

Cette recherche retourne nos cinq contenus tels que nous les avons envoyés à ElasticSearch, appliquons maintenant une facette sur le nom de l’auteur :

{
  "query": {
    "term": {
       "_all": {
          "value": "logs"
       }
    }
  },
  "facets" : {
    "names" : { "terms" : {"field" : "author.name"} }
  }
}

Avec simplement deux lignes de JSON en plus, nous demandons des statistiques d’agrégation sur le champ author.name, et le résultat est instantané :

[
    {
       "term": "Ternel",
       "count": 2
    },
    {
       "term": "Shay Banon",
       "count": 2
    },
    {
       "term": "Damien",
       "count": 1
    }
]

Bien sûr ces facettes sont calculées sur tous les résultats, pas seulement sur ceux retournés par la requête. Donc si vous avons 10 000 résultats, les statistiques sont calculées sur ces 10 000, cela serait impossible côté client.

La pertinence de la recherche

Nous venons de voir que l’indexation et la recherche sont simples et rapides à mettre en oeuvre avec ElasticSearch. Mais penchons nous sur les résultats :

 {
    "_id": "1",
    "_score": 0.41373864,
    "_source": { [...] }
 },

Le premier résultat est notre document 1, et il possède un score supérieur à tous les autres. La raison est simple, le mot « logs » y est plus présent que dans les autres documents !

Il est possible lors de la recherche de donner des « boost » à certains champs, de trier sur d’autres critères que le score, ou encore de scripter l’algorithme de classification : il n’y a pas de limite.

Que se passe t-il maintenant si nous recherchons « log » et non « logs » ? La recherche par défaut ne retourne rien, mais nous pouvons indiquer à ElasticSearch comment analyser nos contenus. Le moteur dispose en effet d’un nombre important de filtres et de générateurs de token :

  • séparation des mots (couramment un espace, mais pas dans toutes les langues) ;
  • forme courte (enlever le s final, simplifier les tokens pour couvrir toutes les grammaires) ;
  • synonyme (un même mot devient plusieurs tokens dans l’index) ;
  • stop words (exclure certains tokens, tel que « en », « a », « the »…) ;
  • phonétique…

Il est possible d’aller très loin, et même de gérer plusieurs langues sans perte de performance.

Et donc ça scale ?

Vous avez maintenant des millions de documents, des recherches très complexes et les temps de réponse commencent à en pâtir. Comment soulager votre serveur ? Ajouter un node ElasticSearch !

ElasticSearch va automatiquement (configuration par défaut) découvrir le nouveau node, et il va distribuer ses shards4 sur le cluster automatiquement. La prochaine requête de recherche sera traitée par les deux nodes, chacun sur une partie des données !

Nous pourrions aussi parler des replicas, des rivers, du routing… Mais je m’égare.

La recherche et bien plus encore5

Il y aurait encore tellement à dire, mais je souhaitais simplement ici démontrer qu’il n’y a aucune raison aujourd’hui pour avoir une recherche lente et limitée : ElasticSearch est la6 solution à vos problèmes, et aussi à ceux que vous n’avez pas encore. Vous pouvez même l’utiliser comme base de donnée NoSQL indexée. Le temps où il fallait deux ingénieurs Lucene à temps plein pour avoir un autocomplete est révolu.

Certaines entreprises utilisent ElasticSearch à d’autres fins que de la recherche : les capacités d’agrégation et de statistique du moteur (ce que nous avons vu avec les facettes) permettent d’en faire, par exemple, un backend parfait pour un logiciel de traitement de logs applicatifs… Oui je parle de Kibana, essayez donc cette démo.

La communauté est très forte, il est très facile de se faire aider via les liste de diffusion, IRC, ou stackoverflow, et il y a même un support officiel – rassurant pour grosses entreprises qui auraient peur de baser toute leur solution de recherche sur un produit open source. En bref, « Go Elastic or do not go ».


  1. Extrait de codex.wordpress.org/WordPress_Features 

  2. Il existe certainement des plugins pour faire mieux… La ligne incriminée à été trouvé ici

  3. « Elasticsearch is a very buzz-word compliant piece of software. » 

  4. Dans chaque index, les données sont shardées, c’est à dire séparées dans différents indexes plus petits (Shard sur Wikipédia

  5. et bien plus encore 

  6. Apache Solr est une très bonne alternative aussi, mais plus complexe a scaler 

blog comments powered by Disqus