Elasticsearch : le moteur de recherche flexible

Lorsqu’on a besoin d’une recherche plein texte puissante, on se tourne généralement vers Apache Solr. Ce projet est toujours un bon choix. Mais depuis 2010, le marché offre une alternative intéressante : Elasticsearch. Comme Solr, Elasticsearch est basé sur Apache Lucene, mais il a d’autres caractéristiques. Nous vous expliquons les fonctionnalités du serveur de recherche et expliquons dans notre tutoriel Elasticsearch comment implémenter la recherche en texte intégral à votre projet.

Qu’est-ce qu’ Elasticsearch ?

Compte tenu de la quantité d’informations disponibles sur certains sites Web, on ne peut profiter d’une bonne intuitivité que si une recherche fonctionnelle en texte intégral est mise en œuvre. Si vous ne voulez pas vous rabattre sur les offres de Google ou de Bing pour offrir à vos visiteurs une fonction de recherche, il sera nécessaire d’intégrer votre propre fonction de recherche. C’est ce que vous propose Elasticsearch. Le projet open source est basé sur le logiciel libre Apache Lucene.

Elasticsearch offre les avantages de son prédécesseur stable et les élargi avec d’autres caractéristiques. Tout comme avec Lucene, la recherche s’opère à l’aide d’un index : mais au lieu d’examiner tous les documents pour une demande de recherche, le programme vérifie un index de documents précédemment créé dans lequel tout le contenu est remanié et stocké. Ce processus prend beaucoup moins de temps qu’avec une recherche de tous les documents.

Si Lucene laisse toute liberté quant à l’endroit et la façon d’utiliser la recherche plein texte, il vous oblige toutefois à repartir de zéro. Elasticsearch, en revanche, permet de démarrer plus rapidement pour une utilisation sur le World Wide Web. Avec Elasticsearch, il est possible de construire un serveur de recherche stable en peu de temps, qui peut aussi être facilement distribué sur plusieurs machines.

Plusieurs nœuds (différents serveurs) se rejoignent pour former un cluster. Le Sharding intervient alors : Elasticsearch décompose l’indice et distribue les différentes parties (shards) à plusieurs nœuds. Cela divise la charge de calcul ; pour les grands projets, la recherche en texte intégral est alors beaucoup plus stable. Pour plus de sécurité, vous pouvez également copier les shards sur plusieurs nœuds.

Elaticsearch est basé, à l’instar de Lucene, sur le langage de programmation orienté objet Java. Le moteur affiche les résultats de recherche au format JSON et les diffuse via un service Web REST. L’API facilite grandement l’intégration de la fonction de recherche dans un site Web.

En outre, Elasticsearch offre des services supplémentaires pratiques avec les beats et logstash (appelés Elastic-Stack) de Kibana que vous pouvez utiliser pour analyser la recherche plein texte. La société Elastic, qui est à l’origine du développement d’Elasticsearch et qui a été fondée par l’inventeur du programme, propose également des services payants, comme l’hébergement Cloud.

Que propose Elasticsearch que Google & Co. n’ont pas ?

Comme toujours, Google propose ses solutions propres, et vous pouvez donc intégrer sa fonction de recherche dans votre site Web sans aucun problème. Alors pourquoi choisir une méthode plus fastidieuse et construire votre propre moteur de recherche avec Elasticsearch ? Un élément de réponse : avec Google Custom Search (GCS), vous devenez dépendant du géant des moteurs de recherche et devez autoriser (tout du moins dans la version gratuite) la publicité dans les résultats. Avec Elasticsearch en revanche, le code est open source, et si vous mettez en place une fonction de recherche plein texte, il vous appartient. Vous n’êtes donc dépendant de personne.

Par ailleurs, vous pouvez personnaliser totalement Elasticsearch selon vos souhaits. Si, par exemple, vous gérez une plateforme ou une boutique en ligne, vous pouvez configurer la fonction de recherche de sorte à pouvoir également effectuer une recherche dans les profils des utilisateurs enregistrés. GCS atteint rapidement ses limites dans de telles applications.

Elasticsearch vs Apache Solr : quelles sont les différences principales ?

Elasticsearch et Apache Solr sont tous deux basés sur Lucene, mais ont été développés dans des offres indépendantes. De nombreux utilisateurs se demandent quel projet choisir. Même si Elasticsearch est un peu plus jeune et n’est pas supporté par la communauté Apache expérimentée contrairement à Solr, il compte maintenant plus d’utilisateurs. Ceci est principalement dû à la simplification de sa mise en œuvre. De plus, Elasticsearch est particulièrement populaire en raison de son traitement des données dynamiques : grâce à une procédure de mise en cache spéciale, Elasticsearch permet de ne pas avoir à saisir de modifications dans la totalité du cache global. Il suffit simplement de changer un petit segment. Ceci rend Elasticsearch plus flexible.

Cependant, le choix ne se fait en fin de compte souvent qu’en fonction des différentes approches de l’open source. Solr s’engage pleinement dans l’Apache Software Foundation : Community over Code. Chaque contribution apportée au code est prise au sérieux et la communauté décide ensemble des ajouts et des améliorations qui seront apportés au code final. Le développement d’Elasticsearch est différent : ce projet est également open source et est proposé sous une licence Apache gratuite, mais seule l’équipe d’Elastic décide des changements pour le code. Face à ce comportement de gatekeeper, certains développeurs n’y adhèrent pas et préfèrent Solr.

Tutoriel Elasticsearch

Si vous souhaitez commencer à travailler avec Elasticsearch, il est conseillé tout d’abord de se familiariser avec les termes de base. Par exemple en ce qui concerne la structure de l’information :

  • Index : une demande de recherche sur Elasticsearch ne s’applique jamais au contenu lui-même, mais toujours à l’index. Tous les contenus de tous les documents sont stockés et déjà préparés dans ce dossier ; la recherche prend donc peu de temps. Il s’agit d’un index inversé : pour chaque terme de recherche, l’emplacement où le terme peut être trouvé est indiqué.
  • Document : l’output de l’index présente les documents dans lesquels les données se trouvent. Il n’est pas nécessaire qu’il s’agisse de textes complets (par exemple, des articles de blog). Il suffit d’avoir des fichiers purs avec des informations.
  • Field : un document se compose de plusieurs champs. En plus du champ de contenu proprement dit, un document va contenir d’autres métadonnées. Par exemple, Elasticsearch peut être utilisé pour rechercher des métadonnées sur l’auteur ou sur la date de création.

Par ailleurs, quand on parle de remaniement des données, il s’agit avant tout de travailler sur les « tokens ». Un algorithme crée en fait des termes individuels à partir d’un texte complet. Pour la machine, les mots n’existent pas vraiment : un texte se compose d’une longue chaîne de caractères et une lettre a la même valeur qu’un espace. Pour qu’un texte soit formaté de manière significative, il doit d’abord être divisé en tokens. Pour ce faire, par exemple, les whitespaces (c’est-à-dire les espaces et les lignes blanches) sont utilisés comme marqueurs de mots. De plus, la préparation s’accompagne également d’une normalisation : les mots sont écrits en minuscules et les signes de ponctuation sont ignorés. Elasticsearch a repris toutes ces méthodes d’Apache Lucene.

Note

Dans le tutoriel suivant, nous travaillons avec la version 6.3.0 de Elasticsearch. Si vous utilisez une version différente, certains exemples de code ou certaines étapes du tutoriel peuvent fonctionner différemment.

Installation

Les fichiers requis pour Elasticsearch sont disponibles gratuitement sur le site officiel d’Elastic. Les fichiers y sont proposés sous forme de paquets ZIP ou tar.gz, et sont donc faciles à installer sur Linux et Mac via une console.

Remarque

Elastic propose Elasticsearch dans deux packs différents. La version standard inclut dans sa version d’essai des fonctionnalités également payantes que vous pouvez utiliser pendant un certain temps. Les packs marqués OSS (Open Source Software) en revanche ne contiennent que des composants libres publiés sous la licence Apache 2.0.

Pour ZIP :

wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-oss-6.3.0.zip
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-oss-6.3.0.zip.sha512
shasum -a 512 -c elasticsearch-oss-6.3.0.zip.sha512 
unzip elasticsearch-oss-6.3.0.zip
cd elasticsearch-6.3.0

Pour tar.gz :

wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-oss-6.3.0.tar.gz
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-oss-6.3.0.tar.gz.sha512
shasum -a 512 -c elasticsearch-oss-6.3.0.tar.gz.sha512 
tar -xzf elasticsearch-oss-6.3.0.tar.gz
cd elasticsearch-6.3.0

Téléchargez d’abord le pack, puis ajoutez la somme de contrôle de la fonction de hachage (SHA512), que vous vérifierez également à la troisième étape. Ensuite, décompressez le pack et mettez-le dans le dossier approprié.

L’archive ZIP peut également être téléchargée et utilisée pour l’installation sous Windows, car le paquet contient un fichier batch que vous pouvez exécuter. Autrement, Elastic fournit maintenant aussi un installateur MSI, mais qui se trouve encore en phase bêta. Le fichier d’installation de ce dernier comporte une interface graphique qui vous guide avec précision tout au long du processus d’installation.

Note

Elasticsearch étant basé sur Java, ce langage de programmation doit également être installé sur votre système. Vous pouvez par conséquent télécharger le Java Development Kit (JDK) qui est gratuit sur le site Web officiel.

Lancez maintenant Elasticsearch depuis la console en naviguant vers le dossier bin et en tapant « elasticsearch » : peu importe que vous soyez sous Linux, Mac ou Windows. Ouvrez ensuite le navigateur de votre choix et appelez le port suivant de l’hôte local : 'http://localhost:9200/'. Si vous avez installé Elasticsearch correctement et si Java est également configuré correctement, vous devriez maintenant pouvoir accéder à la recherche plein texte.

Avec Elasticsearch, vous communiquez via l’API REST et avez donc besoin d’un client supplémentaire. Il est recommandé d’utiliser Kibana pour cela (également une offre open source gratuite d’Elastic). Avec ce programme, vous pouvez utiliser Elasticsearch directement dans votre navigateur. Pour ce faire, il vous suffit de vous rendre sur 'http://localhost:5601/' et d’accéder à une interface utilisateur graphique. Vous pourrez en savoir plus sur la manière d’installer et de configurer Kibana dans notre tutoriel pour Kibana. Dans Kibana et tout autre client, vous pouvez utiliser les méthodes HTTP suivantes pour envoyer des commandes à votre recherche plein texte : PUT, GET, POST et DELETE.

Index

Dans un premier temps, vous devez d’abord créer votre indexe et y ajouter des données. Vous pouvez utiliser deux méthodes HTTP différentes pour cela : POST et PUT. Utilisez PUT si vous voulez spécifier un ID spécifique pour l’entrée. Avec POST, Elasticsearch crée lui-même un identifiant. Dans notre exemple, nous aimerions établir une bibliographie. Chaque entrée doit contenir le nom de l’auteur, le titre de l’œuvre et l’année de publication.

POST bibliography/novels
{
"author": "Isabel Allende",
"title": "La casa de los espíritus",
"year": "1982"
}

Si vous souhaitez utiliser l’entrée de cette façon, vous devez utiliser la console Kibana. Toutefois, si vous ne souhaitez pas utiliser ce logiciel, vous pouvez utiliser cURL. Au lieu de la commande précédente, vous devrez entrer ce qui suit dans la ligne de commande :

curl -XPOST http://localhost:9200/bibliography/novels -H "Content-Type: application/json" -d ‘{"author": "Isabel Allende", "title": "La casa de los espíritus", "year": "1982"}’

Dans ce qui suit, nous vous montrons seulement le code pour Kibana, mais il peut être facilement transféré dans la syntaxe de cURL.

Si vous avez tout saisi correctement, Elasticsearch doit renvoyer les informations suivantes au début du message :

{
	"_index": "bibliography",
	"_type": "novels",
	"_id": "AKKKIWQBZat9Vd0ET6N1",
	"_version": 1,
	"result": "created",
}

À ce stade, Elasticsearch peut maintenant trouver un index avec le nom bibliography et le type novels. Comme nous avons utilisé la méthode POST, Elasticsearch génère automatiquement un identifiant unique pour notre entrée. L’entrée est actuellement en première version et a été créée récemment.

Note

Dans Elasticsearch, un type (_type) se référait auparavant à une sorte de sous-catégorie. Il était alors possible de regrouper plusieurs types sous un même index. Cependant, cela a conduit à des problèmes divers et Elastic prévoyait donc de ne plus les utiliser. Avec la version 6.x _type est toujours inclus, mais il n’est plus possible de rassembler plusieurs types sous un même index. A partir de la version 7.0 il est prévu de supprimer tous les types, comme l’expliquent les développeurs dans leur blog.

Vous pouvez également utiliser PUT pour donner un ID spécifique à votre entrée. Ce dernier est défini dans la première ligne du code. Vous avez également besoin de PUT si vous voulez modifier une entrée existante.

PUT bibliography/novels/1
{
"author": "William Gibson",
"title": "Neuromancer",
"year": "1984"
}

La sortie suivante est très similaire à ce que nous obtenons avec la méthode POST, mais Elasticsearch nous donne l’ID que nous avons fourni à la première ligne de l’entrée. La spécification est toujours du même ordre : _index/_type/_id.

{
	"_index": "bibliography",
	"_type": "novels",
	"_id": "1",
	"_version": 1,
	"result": "created",
}

Avec la commande PUT et l’ID unique, nous pouvons aussi changer les entrées :

PUT bibliography/novels/1
{
"author": "William Gibson",
"title": "Count Zero",
"year": "1986"
}

Puisque l’entrée avec l’identifiant 1 existe déjà, Elasticsearch la modifie seulement au lieu d’en créer une nouvelle. Cela se reflète également dans l’output :

{
	"_index": "bibliography",
	"_type": "novels",
	"_id": "1",
	"_version": 2,
	"result": "updated",
}

Le numéro de version est monté à 2 et, donc pour result on obtient updated au lieu de created. Bien sûr, on peut faire la même chose avec un identifiant aléatoire créé par Elasticsearch - mais compte tenu de la longueur des caractères, un travail supplémentaire complique encore un peu plus les choses. Avec la procédure, Elasticsearch écrase tout simplement une entrée si, par exemple, il y a une confusion avec les numéros ID. Pour éviter un écrasement involontaire, vous pouvez utiliser le terminal _create :

PUT bibliography/novels/1/_create
{
"author": "Mary Shelley",
"title": "Frankenstein; or, The Modern Prometheus",
"year": "1818"
}

Comme l’entrée avec l’identifiant 1 existe déjà dans l’index, un message d’erreur s’affiche.

Si vous apportez des modifications à une entrée comme décrit, vous créez à proprement parler une entrée entièrement nouvelle et devez donc saisir toutes les données intégralement. Autrement, vous pouvez également n’intégrer que les modifications de l’entrée existante. Pour ce faire, utilisez la commande _update :

POST bibliography/novels/1/_update
{
"doc": {
	"author": "Franz Kafka",
"genre": "Horror"
	}
}

Nous avons maintenant ajouté un champ supplémentaire à l’entrée et modifié un champ existant sans supprimer les autres, mais cela qu’au premier plan. En arrière-plan, Elasticsearch a néanmoins créé la nouvelle entrée complète, mais a du coup aussi ajouté les contenus déjà existants indépendamment.

En principe, nous avons jusqu’à présent simplement écrit une entrée dans une base de données et nous pouvons maintenant également la récupérer directement ; pour cela, la méthode GET est nécessaire.

GET bibliography/novels/1

Vous pouvez également afficher l’entrée dans votre navigateur :

http://localhost:9200/bibliography/novels/1

Dans la sortie, Elasticsearch affiche tous les détails de notre entrée :

{
	"_index": "bibliography",
	"_type": "novels",
	"_id": "1",
	"_version": 2,
	"found": true,
	"_source": {
		"author": "William Gibson",
		"title": “Count Zero",
		"year": "1984"
	}
}

En plus des informations déjà connues, vous trouverez les champs du document sous _source. Elasticsearch nous informe aussi qu’une entrée a bien été trouvée. Si vous tentez d’appeler une entrée inexistante, aucun message d’erreur n’apparaît. En revanche, Elasticsearch affiche "found": false et aucune entrée n’est à trouver sous _source.

Vous avez également la possibilité de ne retirer que certaines informations de la base de données. Supposons que vous ayez non seulement inclus des données bibliographiques dans votre index, mais aussi le texte complet de chaque roman enregistré. Cela s’afficherait également avec une simple requête GET. Supposons toutefois que vous ne vous intéressiez actuellement qu’au nom de l’auteur et au titre de l’œuvre ; alors il faut faire une requêter ciblée :

GET bibliography/novels/1?_source=author,title

Si les métadonnées d’une entrée ne vous intéressent pas, vous pouvez également n’afficher que le contenu :

GET bibliography/novels/1/_source

Supposons que vous ne vouliez pas appeler une seule entrée dans votre index, mais plusieurs. Elasticsearch a implémenté _mget (pour multi-get) à cette fin. Si vous l’utilisez, spécifiez une série d’identifiants multiples :

GET bibliography/novels/_mget
{
	"ids": ["1", "2", "3"]
}

Même si une entrée n’existe pas encore, la demande complète n’échoue pas. Toutes les données existantes vous seront affichées. Quant aux données manquantes, Elasticsearch explique ne pas pouvoir les retrouver.

La suppression d’une entrée fonctionne de la même manière que pour l’appeler. Toutefois, au lieu d’utiliser GET, vous utiliserez DELETE :

DELETE /bibliography/novels/1

Dans la sortie suivante, Elasticsearch vous informe qu’il a trouvé l’entrée sous l’identifiant spécifié :

{
	"_index": "bibliography",
	"_type": "novels",
	"_id": "1",
	"_version": 5,
	"result": "deleted",
}

De plus, le programme augmente le numéro de version d’une unité. Deux raisons à cela :

  1. Elasticsearch marque l’entrée seulement comme supprimée et ne la supprime pas directement du disque dur. L’entrée ne disparaîtra qu’au fur et à mesure de l’indexation.
  2. Lorsque vous travaillez avec des index distribués sur plusieurs nœuds, une gestion détaillée des versions est extrêmement importante. Par conséquent, Elasticsearch marque chaque modification comme une nouvelle version, ce qui inclut donc aussi la demande de suppression.

Vous pouvez également apporter des modifications uniquement à un numéro de version spécifique que vous connaissez. S’il existe déjà une version plus récente dans le cluster que celle que vous avez spécifiée, la tentative de modification entraîne un message d’erreur.

PUT bibliography/novels/1?version=3
{
"author": "Marcel Proust",
"title": " À la recherche du temps perdu",
"year": "1927"
}

En outre, vous pouvez non seulement appeler plusieurs entrées à la fois, mais également en créer ou en supprimer plusieurs avec _bulk. Pour cela, Elasticsearch utilise une syntaxe légèrement modifiée.

POST bibliography/novels/_bulk
{"delete": {"_id": "1"}}
{"create": {"_id": "1"}}
{"author": "Johann Wolfgang von Goethe", "title": "Die Leiden des jungen Werther", "year": "1774"}
{"create": {"_id": "2"}}
{"author": "Umberto Eco", "title": "Il nome della rosa", "year": "1980"}
{"create": {"_id": "3"}}
{"author": "Margaret Atwood", "title": "The Handmaid’s Tale", "year": "1985"}

Chaque commande a sa propre ligne. Vous spécifiez d’abord l’action à exécuter (create, index, update, delete). En outre, vous spécifiez également quelle entrée vous voulez créer et où. Avec une commande Bulk, il est aussi possible de travailler dans plusieurs index. Pour ce faire, vous devez laisser le chemin vers POST vide et attribuer un chemin différent à chaque action. Lorsque vous créez des entrées, vous devez également spécifier un request body dans une nouvelle ligne. Il contient alors le contenu de l’entrée. L’instruction DELETE n’exige aucunement un request body, puisque l’entrée entière est supprimée.

Jusqu’à maintenant, nous avons toujours donné un même contenu dans les exemples, et ce peu importe le champ : Elasticsearch a interprété toutes les informations comme une chaîne de caractères cohérente. Toutefois, ce n’est pas toujours le cas dans tous les champs. C’est pourquoi Elasticsearch possède un mapping. Ce dernier détermine comment les algorithmes doivent interpréter une entrée. Vous pouvez utiliser le code suivant pour afficher le mapping actuellement utilisé dans votre index :

GET bibliography/novels/_mapping

Tous les champs sont affectés aux types text et keyword. Elasticsearch reconnaît toutefois 6 types de données de base et encore plus de domaines spécifiques. Les 6 principaux types sont divisés en partie en d’autres sous-catégories :

  • String : il concerne à la fois text et keyword. Bien que Keywords est pris en compte comme correspondance exacte, Elasticsearch part du principe qu’un texte doit être analysé avant de pouvoir être utilisé.
  • Numeric : Elasticsearch reconnaît des valeurs numériques qui diffèrent surtout par leur étendue. Par exemple, alors que le type byte peut avoir des valeurs comprises entre -128 et 127, on considérera avec long une fourchette allant de -263 à 263-1.
  • Date : une date peut être spécifiée au jour ou à l’heure. Vous pouvez également spécifier une date sous forme de temps Unix, c’est-à-dire en secondes ou millisecondes depuis le 1er janvier 1970.
  • Boolean : les champs formatés boolean peuvent avoir une valeur vraie (true) ou fausse (false).
  • Binary : vous pouvez insérer des données binaires dans ces champs. Pour cela, utilisez l’encodage Base64.
  • Range : il permet de spécifier une plage. Elle peut se situer entre deux valeurs numériques, deux données ou même entre deux adresses IP.

Ce ne sont là que les principales catégories que vous utiliserez probablement le plus souvent. Pour d’autres types, vous pouvez consulter la documentation Elasticsearch. Les différents types se distinguent surtout par le fait qu’ils sont soit en valeur exacte (exact-value), soit en texte intégral (full-text). Elasticsearch prend donc le contenu du champ comme une entrée précise ou comme un contenu qui doit d’abord être traité. Au cours du mapping, l’analyse est également importante. L’analyse du contenu est divisée en :

Elasticsearch utilise donc des analysers. Si vous incluez bien un document dans l’index et si vous avez bien effectué votre mapping, tous les contenus seront inclus correctement dans l’index inversé. Pour pouvoir utiliser le mapping vous-même, vous devez créer un tout nouvel index. Le mapping des champs existants n’est pas possible.

PUT bibliography
{
	"mappings": {
		"novels": {
			"properties": {
				"author": {
					"type": "text",
					"analyzer": "simple"
				},
				"title": {
					"type": "text",
					"analyzer": "standard"
				},
				"year": {
					"type": "date",
					"format": "year"
				}
			}
		}
}
}

Nous avons défini les deux champs author et title comme text et donc comme full-text. Ils ont donc besoin d’un analyseur approprié. Alors que nous fournissons l’analyseur standard pour le champ titre du roman, nous choisissons l’analyseur moins complexe Simple Analyzer pour le nom de l’auteur. L’année de publication, en revanche, est définie comme date, et donc comme exact-value. Comme Elasticsearch prend par défaut un format année, mois et jour, nous effectuons une modification afin de le limiter à l’année.

La recherche

Dans le chapitre précédent, nous avons utilisé Elasticsearch et son index surtout comme base de données. Cependant, l’intérêt d’Elasticsearch est de pouvoir procéder à des recherches en texte intégral. Cela signifie qu’au lieu de saisir l’identifiant d’un document et d’appeler l’entrée, nous avons redéfini Elasticsearch afin de pouvoir rechercher spécifiquement un contenu. Pour le moteur de recherche, le programme a fourni le paramètre _search. Ainsi, en combinaison avec la méthode GET, vous pouvez, par exemple, afficher toutes les entrées :

GET bibliography/novels/_search
Remarque

Pour les requêtes plus complexes, _search utilise un body entre accolades. Cependant, certains serveurs HTTP ne le prévoit pas pour la méthode GET. Par conséquent, les développeurs considèrent que ces demandes doivent fonctionner également comme POST.

Vous pouvez également laisser le chemin vide pour rechercher tous les index existants. Dans l’output, vous trouverez les informations intéressantes sous hits :

"hits": {
	"total": 3,
	"max_score": 1,
	"hits": [
		{
			"_index": "bibliography",
			"_type": "novels",
			"_id": "2",
			"_score": 1,
			"_source": {
				"author": "Umberto Eco",
				"title": "Il nome della rosa",
				"year": "1980"
			}
		},
	],
	}
}

Toutes les autres entrées de notre index sont également listées dans l’output (et ne sont omises ici que par souci de clarté). Le retour d’Elasticsearch nous fournit deux informations supplémentaires en plus du contenu réel, qui peuvent nous aider à comprendre la recherche en texte intégral :

  • Hits : chaque entrée qui répond aux critères de recherche sera considérée comme une correspondance par Elasticsearch. Le programme affiche également le nombre de hits. Puisque dans notre exemple il y a 3 entrées dans l’index, on trouve "total": 3.
  • Score : Elasticsearch indique la pertinence de l’entrée par rapport à notre requête. Comme dans notre exemple nous avons fait la recherche de toutes les contributions, elles ont toutes le même score de 1. Les entrées sont triées dans les résultats de recherche par ordre décroissant en fonction de leur pertinence.

De plus, Elasticsearch fournit des informations sur le nombre de shards impliqués dans les résultats de la recherche, le nombre de millisecondes que la recherche a pris et si un délai d’attente a été nécessaire.

Par défaut, Elasticsearch n’affiche que les dix premiers résultats de recherche. Toutefois, vous pouvez modifier la configuration en définissant des paramètres :

  • Size : combien de résultats doivent être affichés ?
  • From : combien d’entrées le programme doit-il ignorer avant de les afficher ?

Si vous avez vu seulement les 10 premiers résultats de recherche et que vous voulez visualiser encore les 15 suivants, il sera nécessaire d’utiliser la combinaison de deux paramètres :

GET bibliography/novels/_search?size=15&from=10

Elasticsearch distingue deux types de recherche différents. D’une part, il utilise une version Lite, d’autre part une variante plus complexe qui fonctionne avec le Query DSL - une langue de requête spécifique. Avec la version Lite, vous saisissez votre recherche à l’aide d’une simple chaîne de caractères directement :

GET bibliography/novels/_search?q=atwood

Il est néanmoins également possible d’effectuer une recherche qu’au sein d’un champ précis :

GET bibliography/novels/_search?q=author:atwood

Si vous voulez combiner plusieurs critères de recherche, utilisez le caractère « + ». Utilisez à l’inverse le caractère « - » pour exclure certains critères. Si vous utilisez ces opérateurs, vous devez toutefois utiliser un codage en pourcentage dans la demande de recherche :

GET bibliography/novels/_search?q=%2Bauthor%3Aatwood+%2Btitle%3Ahandmaid

La syntaxe des query string d’Elasticsearch offre encore plus de subtilités pour personnaliser sa recherche. Dans la documentation du logiciel, les développeurs d’Elastic ont résumé tous les éléments essentiels : phrases exactes, champs vides ou espaces réservés.

Cette variante de recherche est bien adaptée pour les requêtes simples, mais pour des tâches plus complexes, la procédure Lite peut rapidement échouer : le risque de faire une erreur dans la longue chaîne de caractères est trop élevé. C’est pourquoi Elasticsearch offre avec Query DSL une procédure plus confortable. Le point de départ d’une recherche est alors le paramètre query auquel on associe un match query :

GET bibliography/novels/_search
{
	"query": {
		"match": {
"author": "allende"
}
	}
}

Le résultat nous montre toutes les entrées qui contiennent le terme « allende » dans le champ author. Il nous dit aussi que l’analyse du mapping a fonctionné, car Elasticsearch ignore les majuscules et les minuscules. Pour afficher toutes les entrées, vous pouvez utiliser match_all en plus de la variante simple déjà introduite :

GET bibliography/novels/_search
{
	"query": {
		"match_all": {}
	}
}

Le contraire de cette recherche est match_none. Par ailleurs, Elasticsearch donne aussi la possibilité de rechercher dans plusieurs champs avec un seul terme de recherche :

GET bibliography/novels/_search
{
	"query": {
		"multi_match": {
			"query": "la",
			"fields": ["author", "title"]
		}
	}
}

Pour permettre les demandes complexes, vous pouvez également combiner plusieurs termes de recherche entre eux et les noter différemment. Cela ouvre les possibilités de trois manières différentes :

  • must : le terme doit apparaître.
  • must_not : le terme ne doit pas apparaître.
  • should : si ce terme apparaît, la pertinence est incrémentée dans les résultats de recherche.

Dans la pratique, on le combine avec une requête bool :

GET bibliography/novels/search_
{
	"query": {
"bool": {
		"must": {
			"match": {
				"title": "la"
			}
},
		"must_not": {
			"match": {
				"title": "rabbit"
			}
		},
		"should": {
			"match": {
				"author": "allende"
			}
		}
	}
}
}

Vous pouvez également étendre votre recherche en ajoutant un filtre. Ceci vous permet de définir des critères qui limitent les résultats de la recherche :

{
	"query": {
"bool": {
		"must": {
			"match": {
				"title": "la"
			}
},
		"filter": {
			"range": {
				"year": {
					"gte": "1950",
					"lt": "2000"
				}
			}
		}
	}
}
}

Dans l’exemple précédent, nous avons filtré selon une période de temps : seules les entrées publiées entre 1950 et 2000 doivent être affichées.

En résumé

Avec cet outil, vous disposez de tout ce dont vous avez besoin pour mettre en œuvre une recherche en texte intégral sur votre site. Elasticsearch propose cependant encore d’autres méthodes pour affiner votre recherche et la rendre plus performante. Pour en savoir plus, consultez le site officiel d’Elastic. Si vous souhaitez étendre la recherche plein texte, vous pouvez également créer vos propres scripts avec d’autres langues telles que Groovy et Clojure.

Avantages et inconvénients d’Elasticsearch

Elasticsearch peut constituer une recherche en texte intégral puissante. Elle offre en effet de nombreux avantages, également par rapport à son concurrent direct Apache Solr.

Avantages Inconvénients
Open Source Elastic fait figure de Gatekeeper
Rapide et stable  
ÉvolutifFlexible et dynamique  
Nombreux modules de programmes prêts à l’emploi (Analyzer, recherche plein texte...)  
Mise en œuvre facile grâce à Java, JSON et REST-API