dimanche 17 janvier 2010

Solr : le SQL killer pour la recherche

Ceux qui connaissent le Zend Framework et qui ont été confronté à la problématique de mettre ne place un moteur de recherche sur un site ou une application ont certainement eu ne serait-ce que la curiosité de regarder de près Zend_Search_Lucene. Ce composant est une réécriture de Java Lucene, excellent moteur de recherche full-text (entre autre) développé et maintenu par la fondation Apache.

Le portage en PHP est parfaitement compatible au niveau binaire avec son homologue Java. Au niveau binaire signifie, en l'espèce, qu'il est capable d'interroger des index créés avec la version Java de Lucene, et qu'inversement, Java Lucene peut travailler avec les index créés par Zend_Search_Lucene. Et ces index sont stockés dans un format binaire, pour améliorer les performances.

Et c'est précisément là que le bât blesse dans la version PHP de Lucene... si vous avez non seulement regardé de près, mais aussi testé un minimum, avec un jeu de données réaliste, vous vous serez sans doute rendu compte que dès que l'on atteint quelques dizaines de milliers d'entrées dans l'index, ce n'est clairement plus utilisable.

C'est donc là que Solr intervient. Solr est une application Java à déployer sur un serveur d'application type Tomcat (ou encore Jetty, par ailleurs fourni avec l'archive). Son déploiement n'est d'ailleurs pas exactement trivial, du moins pour un habitué de PHP comme je le suis. Mais passons, j'ai tout de même réussi à m'en sortir sans trop de difficultés.

Pour un usage "basique" (mais déjà très impressionnant), peu d'étapes suffisent avant une réelle possibilité d'exploitation.

La première consiste à définir les caractéristiques de son index. Cela se passe dans un fichier XML, qui a l'avantage d'être fourni avec non-seulement un exemple de schéma, mais aussi et surtout de très abondant commentaires, qui constituent par ailleurs l'essentiel de la documentation sur le sujet (ce que l'on peut au passage déplorer, mais bon, imaginons que ça suivra). Définir son index ressemble approximativement à designer une table de base de données. Cela dit, il y a naturellement certaines différences fondamentales.

Parmi les premières notions à acquérir, il y a pas mal de jargon... les notions de "document", de "field types", "fields", "tokenizer"... qui nous sont le plus souvent familières, mais pas nécessairement selon les mêmes acceptions que celles retenues dans Solr/Lucene. Mais là encore, cela s'acquiert très vite. Déjà, quand on a retenu que Document (Solr) = Row (SQL), on a fait du chemin :)

Bref, une fois le schéma défini, on peut commencer de charger des données dans l'index (après avoir simplement redémarré Solr). L'alimentation de l'index, comme la plupart de opérations que l'on réalise sur Solr, se fait via un pseudo service web. En fait, il suffit d'appeler une URL, qui varie selon l'opération qui nous intéresse, et de lui adjoindre d'éventuels paramètres directement dans la "query string" (type ?param=value&otherParam=otherValue). Un peu finalement comme on le ferait pour appeler les différentes actions d'un contrôleur dans une application MVC.

Les actions principales avec Solr sont select (effectuer une recherche), update (ajouter/mettre à jour des documents), et admin (pour accéder à l'interface d'admin, qui, attention n'est pas protégée par défaut !).

Ce billet n'étant pas un tutoriel à proprement parler, je ne résisterai à la tentation de rentrer trop dans les détails, mais je conclurai en listant quelques unes des fonctionnalités de Solr, afin de vous inciter à aller télécharger le package et à suivre le getting started pour vous convaincre  que Solr est une mine d'or pour qui a besoin d'un service de recherche évolué, et somme toute d'une simplicité déconcertante à mettre en place (comparée à la complexité et à la lourdeur des requêtes SQL qu'il faudrait écrire pour s'en passer, sans même parler du degré de pertinence infiniment moindre avec cette deuxième solution) :

 - recherche ultra rapide sur un serveur standard, y compris sur des index allant jusqu'à +/- 1 million de documents
 - gestion native et simplissime des facettes de recherche (ajout de &facet=on&facet.field=NOM_CHAMP) pour l'activer
 - recherche par similarité
 - indices de pertinence natif (mais également personnalisable)
 - recherches spatiales (à partir de coordonnées - intégré à la v1.5, disponible en plug-in pour les précédentes)
 - différents formats de résultats possibles (json, source php, php sérialisé, XML...)
 - possibilité d'effectuer directement une transformation XSLT sur les résultats XML pour retourner du code HTML directement affichable en guise de résultats de recherche
 - etc.

Convaincu ? J'espère :) En tout cas, la suite, c'est par là !