Quel client PHP pour Elasticsearch

Mise à jour du 26 novembre : quelques jours après la publication de cet article, nous avons eu quelques très bon retours sur la partie benchmark. La grosse lenteur constatée sur la SearchSuggestion d’Elastica a disparu, et elasticsearch-php a été reconfiguré et modifié par Zachary Tong, améliorant ses performances, Guzzle et le système de ping était responsable des lenteurs.

Nous faisons maintenant tourner les tests dans une box vagrant, les résultats sont plus robuste et équitable alors voici un nouveau graphique ! On y voit que Sherlock est plus lent, nervetattoo n’est plus le plus rapide partout et elasticsearch-php est maintenant plus proche des bonnes performances d’Elastica.

PHP client benchmark edited

À propos d’Elastica n’étant pas capable de lancer des requêtes en JSON, Nicolas Ruflin nous fait savoir que si, via une nouvelle page dans la documentation. Sherlock, lui, n’a pas d’avenir précis, si le développement devait reprendre, Zachary nous fait savoir qu’il s’agirait de porter l’interface chaînée par dessus le client officiel.

Je suis vraiment très content des retours que cet article à généré, on constate que la communauté est très réactive et les performances on été améliorées sur le client officiel, merci à tous !


Il y a deux mois de cela, la team Elasticsearch a sorti quatre nouveaux clients officiels en Perl, Python, Ruby et PHP. Une annonce surprenante lorsque l’on sait que la communauté a déjà beaucoup travaillé sur des clients dans ces langages, (Tire en Ruby et Elastica en PHP étant les plus connus).

Tire avait 1500 étoiles Github, et a depuis été renommé retire, mettant un terme à son développement. Dans le monde PHP, un autre client en développement s’est arrêté : SherlockPHP.

Le point commun entre ces deux projets ? Leurs auteurs Zachary Tong et Karel Minarik sont maintenant des employés d’Elasticsearch et travaillent sur les clients officiels respectifs ! Bravo à eux ;-)

Le but de cet article est de tester et comparer le nouveau client PHP avec les trois existants :

J’ai choisi une liste de requêtes courantes en Elasticsearch, et j’ai donc entrepris de toutes les programmer avec ces quatre clients, voici mon retour.

Elastica, le plus populaire

Elastica est le client le plus connu actuellement : 560 étoiles, 80 contributeurs, utilisé par la grande majorité de la communauté Symfony2 grâce a FOSElasticaBundle, il est solide et a un bel avenir.

Il est entièrement orienté objet, tout ce que vous pouvez manipuler dans votre cluster a une classe.

$this->client->getIndex("my_index")
    ->getType("my_type")
    ->search("Pony"); // Return a ResultSet object

Vous pouvez requêter vos index, documents et types via des requêtes construites en objets, mais vous ne pouvez pas simplement prendre une requête en Json pour vous en servir. C’est la difficulté lorsque l’on débute avec Elastica : traduire les exemples Json que tout l’écosystème Elasticsearch utilise en graphe d’objets utilisables. La documentation officielle ne couvre pas toutes les fonctionnalités et je recommande donc de lire les très complets tests unitaires pour en apprendre plus, ou avoir des exemples concrets…

Nervetattoo, le plus ancien

C’est le client le plus ancien de ce comparatif (juillet 2010) et il a 183 étoiles pour 5 contributeurs. Son style est bien plus simple qu’Elastica car ici toutes les requêtes et documents sont de simple tableaux PHP.

$this->client->search("Pony"); // Return an array

Nervetattoo est moins verbeux à première vue, mais il peut aussi apporter quelques contraintes, si vous voulez requêter plusieurs type à la fois par exemple, ce dernier étant configuré au niveau du client et non de la requête.

Mes tests comprennent une recherche sur un node déconnecté avec un second node valide configuré, afin de tester le fail-over, et ce client n’a pas été capable de faire la bascule, impliquant que toute l’application ait planté avec une Exception. Cette erreur est liée à une ligne de code dans la lecture de la configuration :

$server = is_array($config['servers']) ? $config['servers'][0] : $config['servers'];

Seul le premier des nodes configurés est utilisé. Un autre problème que j’ai rencontré est que certaines API ne sont pas implémentées, heureusement il est quand même possible de les appeler en construisant l’url manuellement :

// Refresh
$this->client->refresh(); // The index in configured on the client

// Stats
$this->client->request('/my_index/_stats', "GET", false, true);

Il n’y pas de documentation en dehors du README, et les tests ne sont pas complets, mais la base de code est compacte (seulement 12 classes) et il est donc aisé d’en faire le tour..

SherlockPHP, précurseur du client officiel

Voici le client que Zachary Tong a conçu avant de rejoindre Elasticsearch. Il détient 97 étoiles et 11 contributeurs pour moins d’une années de présence, et il a un site sexy (en plus du nom ♥).

Il expose une interface chaînée (fluent interface) mais elle est incomplète et manque de cohérance. Par exemple, l’objet QueryString représentant la requête Elasticsearch query_string : l’option « query » n’a pas de setter (il est magique) alors que toutes les autres options (comme auto_generate_phrase_queries) sont implémentées – comment un développeur ou un IDE peut-il deviner cela ?

Sherlock::queryBuilder()->QueryString()->query("Pony");

Ma configuration avec deux nodes a aussi été compromise car ils avaient le même host, et seul un node par host est possible par Cluster :

$this->nodes[$host] = array('host' => $host, 'port' => $port);

L’autre problème est que les nodes sont choisis aléatoirement et que si l’un d’entre eux ne répond pas, il n’est pas retiré de la liste.

La documentation est prometteuse mais certains passages importants sont manquants, et certaines fonctionnalités d’Elasticsearch ne sont pas du tout compatibles (les suggestions par exemple).

Dans les bons côtés, on notera que l’utilisation de Json ou de tableau PHP est possible et que la couche HTTP est basée sur rolling-curl.

Elasticsearch-PHP, le petit nouveau

Nous terminons donc avec le client officiel, 108 étoiles et déjà 6 contributeurs après seulement 2 mois de vie publique, il est le seul a avoir une vraie documentation.

Il utilise Guzzle comme client HTTP et a un très bon ConnectionPool avec node choisi aléatoirement et ping pour enlever du cluster les nodes qui ne répondent pas correctement.

La syntaxe est en tableau PHP et il n’y a pas de raccourci pour faire une QueryString, la requête la plus simple d’Elasticsearch, contrairement aux autres clients :

$params = array(
    'index' =>"my_index",
    'type'  =>"my_type",
    'body'  => array(
        'query' => array('query_string' => array(
            'query' => "Pony",
        ))
    )
);

$docs = $this->client->search($params);

La partie body de la requête peut aussi bien être un Json qu’un tableau PHP ce qui est appréciable. Toutes les API sont supportées et facile à utiliser :

$this->client->indices()->stats(array('index' => "my_index"));

Et les résultats sont toujours présentés sous la forme de tableaux PHP.

Performance et mémoire

Maintenant que toutes les requêtes sont développées pour ces clients, nous pouvons en extraire certaines informations sur la mémoire et la vitesse.

Voici la liste des requêtes que j’ai implémenté :

  • getDocument: récupère un document par son ID ;
  • searchDocument: fait une recherche QueryString ;
  • searchDocumentWithFacet: fait une recherche MatchAll avec une facette Term sur le champ name;
  • searchOnDisconnectNode: fait une recherche QueryString sur un node déconnecté ;
  • searchSuggestion: fait une recherche QueryString avec une suggestion Term ;
  • indexRefresh: fait un refresh sur l’index;
  • indexStats: fait un stats sur l’index.

Vous pouvez obtenir le code et lancer vous même ces requêtes sur github.

PHP client benchmark

Comme vous pouvez le voir sur ce graphique, le client officiel en bleu est plus lent sur toutes les requêtes, excepté la recherche avec suggestion où Elastica (en orange) est très lent, ce qui ressemble fort a un bug. Sherlock et Nervetattoo n’ont pas de données sur les requêtes qu’il était impossible de faire mais autrement on constate que Nervetattoo en vert est toujours le plus rapide.

PHP client benchmark memory

Concernant la mémoire utilisée et le temps total d’exécution, le client officiel a clairement besoin d’optimisations, il consomme plus de trois fois la mémoire utilisée par Nervatattoo. Le temps en ordonnée n’est pas pertinent pour Nervetatto et Sherlock mais montre bien qu’Elastica est plus rapide que le client officiel.

Le bon client pour chaque besoin

L’interface chaînée de Sherlock est incomplète et inconsistante, le rendant difficile à utiliser comparé à Elastica, une fois que la différence entre \Elastica\Query et \Elastica\Query\Query est saisie. Il n’est pas stable et 4 de mes 7 requêtes étaient impossibles à faire, en conclusion, vous devriez l’éviter.

Nervatattoo est super rapide, si vous avez besoin d’un petit client simple avec lequel vous pouvez juste copier une requête et la voir fonctionner, il fait un bon travail. Vous n’aurez pas de fail-over ni de documentation mais une bonne empreinte mémoire.

Si vous en voulez plus, il vous reste deux choix : l’API objet d’Elastica ou les tableaux PHP du client officiel. Ce dernier est encore un peu jeune et a besoin d’optimisations, à la fois en vitesse et en mémoire, mais sa partie réseaux semble plus robuste que celle d’Elastica, malgré le manque de support du protocole Thrift.

Elastica reste mon petit préféré mais il lui manque l’habilité de simplement accepter une requête Json copié/collé depuis l’internet ! La grosse consommation de temps de la requête avec suggestion est sans doute un bug temporaire et je n’ai aucun doute que le client officiel sera très vite amélioré. A vous de faire votre choix en fonction de vos attentes et de vos besoins !

blog comments powered by Disqus