Retour sur Algolia, solution de recherche en SaaS

Retour sur Algolia, solution de recherche en SaaS

J’utilise Elasticsearch depuis bientôt 2 ans maintenant et j’en suis tous les jours plus satisfait. Alors quand un de nos clients nous a demandé un POC pour son futur moteur de recherche, j’ai sauté sur l’occasion avec plaisir. Trois jours plus tard, j’avais un moteur de recherche complet, déployé avec tous les contenus, un auto-compléteur performant, des agrégations, plein d’options pour ajuster la pertinence, des analyses fines en Français et en Allemand…

Mais l’objectif était ensuite de comparer cette solution, utilisant un logiciel open-source, à Algolia, une solution de recherche en SaaS. Les critères ? Aussi bien financiers que techniques et bien entendu fonctionnels : la recherche doit être la plus intuitive et pertinente possible pour les utilisateurs. Je vous livre ici mes impressions de développeur PHP et d’utilisateur d’Elasticsearch sur ce moteur.

Un moteur de recherche orienté base de données

Tout est parti d’un moteur de recherche offline pour applications mobiles, sorti en 2012 et distribué sous forme de SDK. Il eut un grand succès mais peu de clients étaient prêts à payer pour l’utiliser. Sa grande force était sa rapidité et sa tolérance typographique – ce qui intéressa d’autres secteurs, et c’est début 2013 que la version SaaS fut lancée. Le succès a été rapide, et Algolia est aujourd’hui une société bien ancrée dans le secteur. Ils proposent donc un moteur de recherche hébergé, accessible via une API Rest, à la Elasticsearch.

La documentation est plutôt agréable à lire et un client officiel pour PHP est mis à disposition – c’est donc sur ce client que j’ai basé mes développements.

Dès la page d’accueil de leur site cependant, je suis tombé sur cet article comparant la solution à Elasticsearch. Écrit en Juin 2013, il est cependant parsemé d’erreurs et fait référence à Elasticsearch 0.90.2 (une version ancienne par rapport à la forte activité d’Elasticsearch) !

Contrairement à ce qui est indiqué dans ce comparatif, il est tout à fait possible de mixer pertinence et popularité dans un résultat de recherche, c’est le rôle des function score query. J’irai même jusqu’à dire que c’est Algolia qui pèche dans ce domaine – comme nous verrons plus loin.

De même, je n’aurais pas utilisé une prefix query pour faire la fonctionnalité de « Search as you type » mais plutôt un bon vieux EdgeNGram, plus performant.

La fonctionnalité qui me semble la plus intéressante est donc leur tokenisation : c’est très simple, vous n’avez pas la main dessus ! À part quelques remplacements et stop-words, vous n’allez pas avoir la possibilité de changer l’algorithme d’élision, le stemmer, le tokenizer… Car toutes ces problématiques sont gérées pour vous – quelle que soit la langue. La tolérance aux fautes demande une configuration fine dans Elasticsearch, c’est par défaut avec Algolia.

La rapidité d’exécution des requêtes est aussi beaucoup vantée. Je serai aussi plutôt d’accord, leur backend traite les recherches avec une très bonne vélocité (temps de traitement fournis). Mais s’y ajoute la latence réseau (appel vers l’Internet) qui, comparé à un Elasticsearch dans le réseau local ne doit pas être négligée.

Une belle démonstration de leur moteur est disponible ici.

Les petits plus

Une fonctionnalité souvent demandée par nos clients est la possibilité d’extraire des statistiques sur les recherches effectuées par les utilisateurs :

  • quels sont les termes les plus recherchés ;
  • quels termes ne remontent aucun résultat ;
  • comment les facettes sont-elles utilisées ?

Algolia vous propose un dashboard avec toute sorte de statistiques sur les recherches effectuées par vos utilisateurs, et c’est plutôt une très bonne idée.

Il existe aussi une option attributeForDistinct, qui permet de faire comme son nom l’indique des DISTINCT comme en SQL (elle garde le meilleur hit en cas de collision), une fonctionnalité qui aurait été vraiment intéressante si il avait été possible de faire des recherches dans plusieurs index…

Les petits points d’attention

Quelques concepts m’ont surpris en tant que développeur, voici quelques pro-tips© avant de l’utiliser vous-même.

Par exemple, nous sommes forcés d’utiliser un champ nommé objectID pour l’id de nos documents. Cela implique que notre représentation JSON contient des champs propre à l’outil (impactant templates, représentation JSON, etc).

Cela rejoint toute une liste de champs « spéciaux », réservés implicitement et non documentés :

  • _tags ;
  • _highlightResult ;
  • _rankingInfo.

Autre inconvénient lors des recherches, il n’est pas possible de rechercher dans plusieurs index simultanément, en fusionnant les résultats. Il faut le savoir avant de penser vos documents et leur stockage. Il n’y a aucune notion de types, tout est index – attention donc à ne pas se retrouver bloqué par l’impossibilité de faire une recherche cross-index.

Enfin, notez bien que la pagination commence à zéro et non à un. Cela vous sauvera quelques minutes d’angoisse… L’API ne retourne pas d’exception si vous êtes « OutOfRange » et vous aurez donc des résultats vides sans comprendre pourquoi (vous le sentez le vécu ici ?).

La pertinence calculée à l’indexation

Contrairement à Elasticsearch, la pertinence des documents est calculée dès l’indexation. Les critères de tri sont définis dans les paramètres de votre index et ne peuvent pas être changés lors de la recherche.

Impossible donc, pour une requête en particulier, de booster un champ plus qu’un autre par exemple. Vous devez configurer cette importance sur l’index (avec attributesToIndex), et toutes vos requêtes appliqueront ce tri.

La pertinence est ensuite composée d’une série de calculs, chacun fournissant un résultat numérique utilisé pour trier les résultats. Il est possible d’y insérer son propre « calcul » avec l’option customRanking, avec par exemple desc(totalVideoViews) pour donner une plus grande importance aux vidéos les plus vues.

Cette limitation d’un tri par index se contourne en envoyant le même document dans plusieurs index ; heureusement Algolia propose une notion de réplication automatique, et vous pouvez donc créer des répliquas de vos index avec une configuration différente.

Les limites du customRanking

Un de mes critères de pertinence est la date de diffusion d’un programme télévisé : plus la diffusion est proche (dans le passé où dans le futur), et plus mon document est important.

Avec Elasticsearch j’utilise les très puissantes Decay function :

"function_score": {
  "functions": [
    {
      "exp": {
        "broadcasts.broadcastTimestamp": {
          "origin": "now",
          "scale": "1d",
          "decay": 0.5
        }
      }
    }
    ...

Chaque document peut avoir plusieurs dates de diffusion et je n’ai pas besoin de m’en soucier, Elasticsearch base son calcul sur la date la plus proche de mon paramètre « origin ».

Avec Algolia, il est possible d’effectuer un tri sur un champ date, mais forcément ascendant ou descendant : pas par proximité.

J’ai donc été obligé de faire moi-même, dans mes documents, le calcul d’intervalle entre la date de diffusion et la date du jour, ce qui m’oblige a ré-indexer mes documents tous les jours.

foreach ($doc['broadcasts'] as $broadcast) {
    $broadcastDate = new \DateTime($broadcast['broadcastTimestamp']);
    $interval = $today->diff($broadcastDate);
    $daysIntervals[] = $interval->days;
}
// New custom field with the min days to broadcast
$doc['closestDaysFromBroadcastAirDate'] = min($daysIntervals);

J’ai ensuite ajouté ce nouveau champ closestDaysFromBroadcastAirDate dans mon customRanking : asc(closestDaysFromBroadcastAirDate). Le résultat est acceptable, mais la précision est plus faible.

Quid des performances ?

Là-dessus rien à redire, j’ai effectué mes tests avec peu de documents mais les temps de traitement côté Algolia sont très bons. S’y ajoute la latence réseau bien sûr, et… un accès disque sur le client PHP. Le tout contribue à des temps de réponse dix fois plus élevés avec Algolia : 0,10s contre 0,01s pour Elasticseach. À ces échelles la différence est négligeable pour certains, mais à ne pas sous-estimer pour d’autres.

Côté indexation, avec l’utilisation des bulk request pour l’un et des batch pour l’autre, les deux moteurs ingèrent les documents comme des petits pains.

Les autres différences

La gestions des alias, très utile dans Elasticsearch, n’est d’aucune utilité ici car les index peuvent être renommés !

$client->moveIndex("YourIndexName_temp", "YourIndexName");

Les recherches sont de simples chaînes de caractère, pas de Query DSL à apprendre (c’est cool) mais en échange une bien moins grande flexibilité. Mes recherches pour Algolia sont beaucoup moins verbeuses que mon DSL Elasticsearch, à n’en pas douter :

$queries[] = array(
    'hitsPerPage' => 20,
    'queryType' => 'prefixAll',
    'typoTolerance' => true,
    'page' => $params['page'] - 1, // hehehehe
    'getRankingInfo' => true,
    'facets' => '*', // All configured facets,
    'query' => 'Ma recherche',
    'maxValuesPerFacet' => 10, // like ES
);
$this->client->multipleQueries($queries);

Ci-dessus une requête avec un maximum d’options. Je vous épargne les 100 lignes de PHP qui construisent ma requête Elasticsearch.

Mes conclusions

Elasticsearch reste mon outil de prédilection parce que je sais exactement ce qu’il fait, et comment il le fait : c’est ma zone de confort, un outil avec lequel je connais les limites et les possibilités.

Cependant je suis convaincu qu’Algolia est un produit tout à fait intéressant ! En quelques instants il est possible d’obtenir une recherche rapide et pertinente. Si le besoin client est simple (un seul type de document, pas de score complexe, pas de statistiques), il sera plus rapide d’utiliser celui-ci. Vous aurez un moteur de recherche rapide, sans maintenance, sans configuration complexe, et sans Java.

Rien de ce qui est fait avec Algolia ne pourrait pas l’être avec Elasticsearch, mais le premier est tellement plus simple a prendre en main ! La partie hébergement est aussi un avantage indéniable, car tout le monde n’est pas en mesure d’ajouter un cluster de machines à son infrastructure (voir found.no pour du Elasticsearch hébergé). Les prix sont comparables, car Algolia n’est pas beaucoup plus cher qu’une paire de très bon serveurs.

Les deux produits sont bons, et même si Algolia est un peu « magique » il répond a un besoin courant avec brio.

blog comments powered by Disqus