Chapitre 3. Indexation, mise à jour et suppression de données
Ce chapitre couvre
- Utilisation du mapping de type pour définir plusieurs types de documents dans le même index
- Types de champs que vous pouvez utiliser dans les mappings
- Utilisation de champs prédéfinis et de leurs options
- Mise en pratique des concepts precedents au niveau de l’indexation, la mise à jour et la suppression de données
Ce chapitre traite de la manière d’obtenir, de conserver des données dans Elasticsearch et de les maintenir: indexation, mise à jour et suppression de documents. Au chapitre 1, vous avez appris qu’Elasticsearch est orienté documents et que les documents sont composés de champs et de leurs valeurs, ce qui les rend autonomes, un peu comme si les noms de colonne d’une table étaient contenus dans les lignes. Au chapitre 2, vous avez vu comment indexer un tel document via l’API REST d’Elasticsearch. Ici, nous allons approfondir le processus d’indexation en examinant les champs de ces documents et leur contenu. Par exemple, lorsque vous indexez un document comme ceci:
Le champ name est une String car sa valeur, « Elasticsearch Denver », est une chaîne de caractères. Les autres champs peuvent être des nombres, des booléens, etc. Dans ce chapitre, nous examinerons trois types de champs:
- Principaux(Types de base. On parle de primitif)— Ces champs incluent des chaînes de caractères et des nombres.
- Tableaux et champs multiples— Ces champs vous aident à stocker plusieurs valeurs du même type primitif dans un seul champ. Par exemple, vous pouvez avoir plusieurs chaînes de balises dans votre champ balises.
- Prédéfini— Des exemples de ces champs : _ttl (qui signifie «time to live») , _timestamp.
Considérez ces types de champs comme des métadonnées pouvant être gérées automatiquement par Elasticsearch pour vous offrir des fonctionnalités supplémentaires. Par exemple, vous pouvez configurer Elasticsearch pour ajouter automatiquement de nouvelles données aux documents, telles qu’un horodatage, ou alors utiliser le champ _ttl pour supprimer automatiquement vos documents au bout d’un délai spécifié.
Une fois que vous connaissez les types de champs pouvant figurer dans vos documents et comment les indexer, nous examinerons comment mettre à jour les documents déjà présents. En raison de la manière dont il stocke les données, lorsque Elasticsearch met à jour un document existant, il le récupère et applique les modifications en fonction de vos spécifications. Il indexe ensuite à nouveau le document obtenu et supprime l’ancien. De telles mises à jour peuvent poser des problèmes de simultanéité et vous verrez comment elles peuvent être résolues automatiquement avec les versions de document. Vous verrez également différentes manières de supprimer des documents, certaines plus rapidement que d’autres. Cela est dû à la manière particulière dont Apache Lucene, la principale bibliothèque utilisée par Elasticsearch pour l’indexation, stocke les données sur disque.
Nous allons commencer par l’indexation en examinant comment vous pouvez gérer les champs de vos documents. Comme vous l’avez vu au chapitre 2, les champs sont définis dans les mappings. Par conséquent, avant d’examiner de plus près la manière dont vous pouvez utiliser chaque type de champ, nous allons voir comment vous pouvez utiliser les mappings en général.
3.1. UTILISATION DU MAPPING POUR DEFINIR LES TYPES DE DOCUMENTS
Chaque document appartient à un type, qui à son tour appartient à un index. Dans le cadre d’une division logique des données, vous pouvez considérer les index comme des bases de données et les types comme des tables. Par exemple, le site Web de rencontre que nous avons présenté au chapitre 2 utilise un type différent pour les groupes et les événements, car ces documents ont des structures différentes. Notez que si vous avez également un blog sur ce site Web, vous pouvez conserver les entrées de blog et les commentaires dans un index séparé car il s’agit d’un ensemble de données complètement différent.
Les types contiennent une définition de chaque champ du mapping. Le mapping inclut tous les champs pouvant apparaître dans les documents de ce type et indique à Elasticsearch comment indexer les champs d’un document. Par exemple, si un champ contient une date, vous pouvez définir le format de date qui sera acceptable.
Les types fournissent uniquement une séparation logique
Avec Elasticsearch, il n’existe aucune séparation physique des documents de types différents. Tous les documents au sein du même index Elasticsearch, quel que soit leur type, se retrouvent dans le même ensemble de fichiers appartenant aux mêmes fragments. Dans un fragment, qui est un index Lucene, le nom du type est un champ et tous les champs de tous les mappings sont regroupés en tant que champs dans l’index Lucene.
Le concept de type est une couche d’abstraction spécifique à Elasticsearch mais pas à Lucene, ce qui facilite la création de différents types de documents dans le même index. Elasticsearch se charge de séparer ces documents; par exemple, en filtrant les documents appartenant à un certain type lorsque vous effectuez une recherche dans ce type uniquement.
Cette approche crée un problème lorsque le même nom de champ apparaît dans plusieurs types. Pour éviter des résultats imprévisibles, deux champs portant le même nom doivent avoir les mêmes paramètres. Sinon, Elasticsearch risque d’avoir du mal à déterminer à quel domaine vous faites référence. Au final, ces deux champs appartiennent au même index Lucene. Par exemple, si vous avez un champ name dans les documents de groupe et d’événement, les deux doivent être des chaînes de charactères (String), pas une chaîne et l’autre un entier. C’est rarement un problème dans la vie réelle, mais il convient de ne pas l’oublier pour éviter les surprises.
Dans la figure 3.1, les groupes et les événements sont stockés dans différents types. L’application peut ensuite effectuer une recherche dans un type spécifique, tel que des événements. Elasticsearch vous permet également de rechercher dans plusieurs types à la fois, voire dans tous les types d’index, en spécifiant uniquement le nom de l’index lors de la recherche.
Maintenant que vous savez comment les mappings sont utilisés dans Elasticsearch, voyons comment vous pouvez lire le mapping d’un type spécifique et en écrire un.
3.1.1. Récupération et définition de mappings
Lorsque vous apprenez Elasticsearch, vous n’avez souvent pas à vous soucier du mapping, car Elasticsearch détecte automatiquement vos champs et ajuste votre mapping en conséquence. Vous verrez comment cela fonctionne dans la figure 3.1. Dans une application de production, vous souhaitez souvent définir votre mapping à l’avance afin de ne pas avoir à vous fier à la détection automatique des champs. Nous expliquerons comment définir un mapping plus tard dans ce chapitre.
Obtenir le mapping actuel
Pour voir le mapping actuel d’un type de champ, executez un HTTP GET sur _mapping sous l’URL:
Dans la figure suivante, vous indexez d’abord un nouveau document à partir de votre site Web de rencontre, en spécifiant un nouveau type appelé new-events. Elasticsearch crée automatiquement le mapping pour vous. Vous récupérez ensuite le mapping créé, qui affiche les champs de votre document et les types de champs détectés par Elasticsearch pour chaque champ.
Figure 3.1. Obtenir un mapping généré automatiquement
Définir un nouveau mapping
Pour définir un mapping, vous utilisez la même URL que précédemment, mais vous émettez un HTTP PUT au lieu de GET. Vous devez spécifier le mapping JSON dans le corps en utilisant le même format que lorsque vous récupérez un mapping. Par exemple, la demande suivante met en place un mapping qui définit le champ host sous forme de chaîne de caractères(String):
Vous pouvez définir un nouveau mapping après avoir créé l’index, et cela est possible avant même d’insérer un document dans ce type. Pourquoi ce PUT fonctionne-t-il si, comme le montre la figure 3.1, vous avez déjà mis en place un mapping ? Je vous l’expliquerai dans la suite.
3.1.2. Extension d’un mapping existant
Lorsque vous placez un mapping sur un autre existant, Elasticsearch fusionne les deux. Si vous demandez maintenant à Elasticsearch le mapping resultant, vous devriez obtenir quelque chose comme ceci:
Comme vous pouvez le constater, le mapping contient maintenant les deux champs du mapping initial plus le nouveau champ que vous avez défini. Le mapping initial a été étendu au champ nouvellement ajouté, ce que vous pouvez faire à tout moment. Elasticsearch appelle cela une fusion entre le mapping existant et celui que vous fournissez.
Malheureusement, toutes les fusions ne fonctionnent pas. Par exemple, vous ne pouvez pas modifier le type de données d’un champ existant et, en général, vous ne pouvez pas modifier la façon dont un champ est indexé. Voyons de plus près la raison. Comme indiqué dans la figure suivante, si vous essayez de modifier le champ host en un long, on a une exception: MergeMappingException.
Le seul moyen d’éviter cette erreur est de réindexer toutes les données dans new-events, ce qui implique les étapes suivantes:
- Supprimez toutes les données du type new-events. vous apprendrez plus loin dans ce chapitre comment supprimer des données. La suppression des données supprime également le mapping actuel.
- Configurer le nouveau mapping.
- Indexez à nouveau toutes les données.
Pour comprendre pourquoi une réindexation peut être nécessaire, supposons que vous ayez déjà indexé un événement avec une chaîne de caractères dans le champ host. Si vous souhaitez que le champ host soit un long maintenant, Elasticsearch devra changer la façon dont le champ host est indexé dans le document existant. Comme vous le découvrirez plus loin dans ce chapitre, éditer un document existant implique de supprimer et d’indexer à nouveau. Pour définir des mappings corrects qui, espérons-le, ne nécessiteront que des ajouts, et pas de modifications plus tard, examinons les types de base que vous pouvez choisir pour vos champs dans Elasticsearch et ce que vous pouvez en faire.
3.2. TYPES DE BASE POUR LA DÉFINITION DE VOS DOMAINES DANS DES DOCUMENTS
Avec Elasticsearch, un champ peut être l’un des types principaux (voir tableau 3.1), tel qu’une chaîne de caractère (String ), un nombre, ou un type plus complexe dérivé de types principaux, tel qu’un tableau.
Certains types supplémentaires ne sont pas abordés dans ce chapitre. Par exemple, il existe le type imbriqué, qui vous permet d’avoir des documents dans les documents, ou le type geo_point, qui stocke un emplacement sur Terre en fonction de sa longitude et de sa latitude. Nous aborderons ces types supplémentaires au chapitre 8, où nous traitons des relations entre documents, et à l’annexe A, où nous traitons des données géospatiales.
Outre les champs que vous définissez dans vos documents, tels que le nom ou la date, Elasticsearch utilise un ensemble de champs prédéfinis pour les enrichir. Par exemple, il existe un champ _all, où tous les champs du document sont indexés ensemble. Ceci est utile lorsque les utilisateurs recherchent quelque chose sans spécifier le champ – ils peuvent rechercher dans tous les champs. Ces champs prédéfinis ont leurs propres options de configuration. Nous en discuterons plus tard dans ce chapitre.
Examinons chacun de ces types de base pour pouvoir faire de bons choix de mapping lorsque vous indexez vos propres données.
3.2.1. String
Les chaînes de caractères sont les plus simples: votre champ doit être une String si vous indexez des caractères. Ils sont également les plus intéressants car vous avez beaucoup d’options dans votre mapping pour savoir comment les analyser.
L’analyse consiste à parser le texte pour le transformer et à le décomposer en éléments permettant de rendre les recherches pertinentes. Si cela semble trop abstrait, ne vous inquiétez pas: le chapitre 5 explore le concept. Mais regardons maintenant les bases, en commençant par le document que vous avez indexé dans la figure 3.1:
Avec ce document indexé, recherchez le mot late dans le champ name, qui est une chaîne de caractères:
La recherche trouve le document «Late Night with Elasticsearch» que vous avez indexé dans la figure 3.1. Elasticsearch relie les chaînes « late » et « Late Night with Elasticsearch » via une analyse. Comme vous pouvez le voir à la figure 3.2, lorsque vous indexez « Late Night with Elasticsearch », l’analyseur par défaut met toutes les lettres en minuscule, puis divise la chaîne en mots individuels.
L’analyse produit quatre termes: late, nigth, with et elasticsearch. Le même processus est ensuite appliqué à la query string, mais cette fois, « late » produit la même string: « late ». Le document (doc1) correspond à la recherche car le terme late résultant de la requête correspond au terme late résultant du document.
Définition
Un term est un mot du texte et constitue l’unité de base de la recherche. Dans différents contextes, ce mot peut signifier différentes choses: il peut s’agir d’un nom, par exemple, ou d’une adresse IP. Si vous voulez uniquement des correspondances exactes sur un champ, le champ entier doit être traité comme un mot.
D’autre part, si vous indexez «latenight», l’analyseur par défaut crée un seul terme: latenight. La recherche de «late» ne renvoiera pas le doc2 car il n’inclut pas le terme late.
Ce processus d’analyse est l’endroit où le mapping entre en jeu. Vous pouvez spécifier de nombreuses options d’analyse dans votre mapping. Par exemple, vous pouvez configurer l’analyse pour produire des termes qui sont des synonymes de vos termes d’origine. Par conséquent, les requêtes sur les synonymes correspondent également. Comme nous l’avons promis, nous allons plonger dans les détails au chapitre 5, mais pour l’instant, examinons l’index option, qui peut être définie sur analysed (option par défaut), not_analysed ou not. Par exemple, pour définir le champ name sur not_analyzed, votre mapping pourrait ressembler à ceci:
Par défaut, l’index est configuré sur analysed et produit le comportement observé précédemment: l’analyseur met toutes les lettres en minuscule et divise votre chaîne de charactères en mots. Utilisez cette option lorsque vous vous attendez à ce qu’un seul mot produise une correspondance. Par exemple, si les utilisateurs recherchent «elasticsearch», ils s’attendent à voir «Late Night with Elasticsearch» dans la liste des résultats.
Configurer l’index sur l’option not_analyzed a l’effet inverse: le processus d’analyse est ignoré et la chaîne entière est indexée sous la forme d’un terme entier. Utilisez cette option lorsque vous souhaitez des correspondances exactes. En conséquence, vous souhaiterez probablement que seules les mots «big data» apparaissent lorsque vous recherchez «big data» et non «data». De plus, vous en aurez besoin pour la plupart des agrégations, qui comptent les termes. Si vous souhaitez obtenir les balises les plus fréquentes, vous souhaitez probablement que «big data» soit compté comme un terme unique, et non comme «big» et «data» séparément. Nous allons explorer les agrégations au chapitre 7.
Si vous définissez index sur no, l’indexation est ignorée et aucun terme n’est généré. Vous ne pourrez donc pas effectuer de recherche sur ce champ en particulier. Lorsque vous n’avez pas besoin de faire des recherche sur un champ, cette option économise de l’espace et réduit le temps nécessaire pour indexer et rechercher. Par exemple, vous pouvez stocker des critiques pour des événements. Bien que stocker et afficher ces critiques soit utile, il peut ne pas en être autrement. Dans ce cas, désactivez l’indexation de ce champ pour accélérer le processus d’indexation et économiser de l’espace.
Vérifiez si votre requête est « analysed » lors d’une recherche dans des champs qui ne le sont pas
Pour certaines requêtes, telles que la chaîne query_string que vous avez utilisée précédemment, le processus d’analyse est appliqué à vos critères de recherche. Il est important de savoir si cela se produit ou non. Sinon les résultats pourraient ne pas être ceux escomptés.
Par exemple, si vous indexez «Elasticsearch» et que celui-ci n’est pas analysed, le terme « Elasticsearch » est créé. Lorsque vous interrogez “Elasticsearch” comme ceci:
la demande d’URI est de type « analysed » et le terme elasticsearch (minuscule) est généré. Mais vous n’avez pas le terme « elasticsearch » dans votre index; vous avez seulement « Elasticsearch » (avec un E majuscule), vous n’obtenez donc aucun résultat. Au chapitre 4, où nous aborderons les recherches, vous apprendrez quels types de requêtes analysent le texte saisi et lesquels ne le font pas.
Ensuite, regardons comment vous pouvez indexer des nombres. Elasticsearch fournit de nombreux types de base qui peuvent vous aider à gérer les nombres. Nous les qualifierons donc collectivement de numériques.
3.2.2. Numérique
Les types numériques peuvent être des nombres avec ou sans virgule flottante. Si vous n’avez pas besoin de décimales, vous pouvez choisir entre Byte, Short, Integer et Long; si vous en avez besoin, vos choix sont Float et Double. Ces types correspondent aux types de données primitifs de Java et leur choix influe sur la taille de votre index et sur la plage de valeurs que vous pouvez indexer. Par exemple, alors qu’un long occupe 64 bits, un short ne prend que 16 bits, mais un long peut stocker jusqu’à plusieurs billions de fois des nombres plus grand que ceux compris entre –32 768 et 32 767. C’est l’interval correspondant aux numéric de type short .
Si vous ne connaissez pas la plage dont vous avez besoin pour vos valeurs entières ni la précision nécessaire pour vos valeurs à virgule flottante, vous pouvez effectuer ce que Elasticsearch fait en détectant automatiquement votre mapping: utilisez long pour les valeurs entières et double pour les valeurs flottantes. Votre index peut devenir plus gros et plus lent parce que ces deux types occupent beaucoup plus de place, mais au moins vous ne risquez probablement pas d’obtenir une erreur d’Elasticsearch lors de l’indexation concernant le nombre choisit.
Maintenant que nous avons couvert les chaînes de charactères et les chiffres, examinons un type plus spécifique: la date.
3.2.3. Date
Le type date est utilisé pour stocker les dates et les heures. Cela fonctionne comme ceci: vous fournissez normalement une chaîne avec une date, comme dans 2013-12-25T09: 00: 00. Ensuite, Elasticsearch analyse la chaîne et la stocke sous forme de numéro de type long dans l’index Lucene. Ce délai est le nombre de millisecondes écoulées depuis le 1er janvier 1970 à 00:00:00 heure UTC et le temps que vous avez indiqué.
Lorsque vous recherchez des documents, vous fournissez toujours des chaînes de charactères pour les dates et Elasticsearch analyse ces chaînes et utilise plutôt des nombres en arrière-plan. C’est parce que les nombres sont plus rapides à stocker et à utiliser que les chaînes de charactères.
En revanche, il vous suffit de vérifier que Elasticsearch comprend le format de date que vous lui fournissez. Il est défini par l’option format, et Elasticsearch analyse par défaut les horodatages ISO 8601.
ISO 8601
Norme internationale pour l’échange de données relatives à la date et à l’heure, l’ISO 8601 est largement utilisée dans les horodatages dus à la RFC 3339 (www.ietf.org/rfc/rfc3339.txt). Une date ISO 8601 ressemble à ceci:
Il contient tous les ingrédients d’un bon horodatage: les informations sont lues de gauche à droite, du plus important au moins important; l’année a quatre chiffres; et l’heure comprend les secondes et le fuseau horaire. Une grande partie des informations de cet horodatage est facultative. Par exemple, vous n’avez pas besoin de spécifier des millisecondes et vous pouvez même ignorer carrément l’heure.
Lorsque vous utilisez l’option format pour spécifier un format de date, vous disposez de deux options:
- Utilisez un format de date prédéfini. Par exemple, le format de date parse les dates comme ceci: 2013-02-25. De nombreux formats prédéfinis sont disponibles et vous pouvez tous les voir ici: www.elastic.co/guide/reference/mapping/date-format/
- Spécifiez votre propre format personnalisé. Vous pouvez spécifier un modèle pour vos horodatages. Par exemple, le format MM AAAA, les dates seront parsés comme ceci: Juillet 2001.
Pour utiliser toutes ces informations sur les dates, ajoutons un nouveau type de mapping appelé weekly-events, comme indiqué dans la figure suivante. Comme indiqué dans la figure, ajoutez ensuite un nom et la date du premier événement, puis spécifiez un horodatage ISO 8601 pour cette date. Ajoutez également un champ avec la date du prochain événement et spécifiez un format de date personnalisé pour cette date.
Nous avons parlé de chaînes de charactères, de nombres et de dates; Passons au dernier type primitif: boolean. Comme la date, boolean est un type plus spécifique.
3.2.4. Booléen
Le type booléen est utilisé pour stocker les valeurs true / false de vos documents. Par exemple, vous voudrez peut-être un champ indiquant si la vidéo de l’événement est disponible au téléchargement. Un exemple de document pourrait être indexé comme ceci:
Le champ downloadable est automatiquement mappé en tant que booléen et est stocké dans l’index de Lucene sous la forme T pour true ou F pour false. Comme pour les champs de date, Elasticsearch analyse la valeur que vous fournissez dans le document source et transforme true et false en T et F, respectivement.
Nous avons examiné les types principaux: string, numérique, date et booléen, que vous pouvez utiliser dans vos propres champs. Passons maintenant aux tableaux et aux champs multiples, qui vous permettent d’utiliser le même type primitif plusieurs fois.
3.3. TABLEAUX ET CHAMPS MULTIPLES
Parfois, avoir de simples paires champ-valeur dans vos documents ne suffit pas. Vous devrez peut-être avoir plusieurs valeurs dans le même champ. Laissons de côté l’exemple du site de rencontre et examinons un autre cas d’utilisation: vous indexez des articles de blog et vous souhaitez créer un champ de balises contenant une ou plusieurs balises. Dans ce cas, vous avez besoin d’un tableau.
3.3.1. Tableaux
Pour indexer un champ avec plusieurs valeurs, mettez-les entre crochets; par exemple:
À ce stade, vous vous demandez peut-être «Comment définissez-vous un champ de type tableau dans votre mapping?» La réponse est que vous ne le faites pas. Dans ce cas, le mapping définit le champ tags en tant que chaîne, comme c’est le cas lorsque vous avez une valeur unique:
Tous les types de base prennent en charge les tableaux et vous pouvez utiliser des valeurs uniques et des tableaux sans modifier votre mapping. Par exemple, si le prochain article de blog n’a qu’un seul tag, vous pouvez l’indexer comme ceci:
En interne, c’est à peu près la même chose pour Lucene, qui doit indexer plus ou moins de termes dans le même champ, en fonction du nombre de valeurs que vous fournissez.
3.3.2. Champs multiples
Si les tableaux vous permettent d’indexer plus de données avec les mêmes paramètres, les champs multiples consistent à indexer les mêmes données plusieurs fois à l’aide de paramètres différents. Par exemple, dans la figure 3.4, vous configurez le champ tags à partir du type de vos publications avec deux paramètres différents: analysed, pour les correspondances sur chaque mot, et not_analysed, pour les correspondances exactes sur la valeur du tag complet.
Vous pouvez mettre à niveau un seul champ vers une configuration à plusieurs champs sans avoir à réindexer vos données. C’est ce qui se produit si vous avez déjà créé un champ tags de type String avant d’exécuter la commande dans la figure suivante. Le contraire n’est cependant pas possible: vous ne pouvez pas supprimer un sous-champ du mapping une fois qu’il est là.
Vous effectuez une recherche dans la version analysed du champ tags comme vous le faites avec n’importe quelle autre chaîne de charactères. Pour effectuer une recherche dans la version not_analysed (et ne récupérer que les correspondances exactes de la balise d’origine), indiquez le chemin complet: tags.verbatim.
Les types champs multiples et tableaux vous permettent d’avoir plusieurs valeurs de type primitifs dans un seul champ. Nous examinerons ensuite des champs prédéfinis (qui sont normalement gérés par Elasticsearch de manière autonome) pour ajouter de nouvelles fonctionnalités à vos documents, telles que leur expiration automatique.
3.4. UTILISER DES CHAMPS PRÉDÉFINIS
Elasticsearch fournit un certain nombre de champs prédéfinis que vous pouvez utiliser et configurer pour ajouter de nouvelles fonctionnalités. Ces champs prédéfinis diffèrent des champs que vous avez vus jusqu’à présent de trois manières:
- En règle générale, vous ne remplissez pas un champ prédéfini; Elasticsearch le fait pour vous. Par exemple, vous pouvez utiliser le champ _timestamp pour enregistrer la date à laquelle un document a été indexé.
- Ils gèrent des fonctionnalités spécifiques. Par exemple, le champ _ttl (durée de vie) permet à Elasticsearch de supprimer des documents après un laps de temps spécifié.
- Les noms de champs prédéfinis commencent toujours par un trait de soulignement (_). Ces champs ajoutent de nouvelles métadonnées à vos documents. Elasticsearch les utilise pour diverses fonctionnalités, du stockage du document d’origine au stockage des informations d’horodatage pour une expiration automatique.
Nous allons diviser les champs prédéfinis importants dans les catégories suivantes:
- Le contrôl de la façon de stocker et rechercher vos documents. _source vous permet de stocker le document JSON d’origine au fur et à mesure que vous l’indexez. _all indexe tous vos champs ensemble.
- Identifiez vos documents. Ce sont des champs spéciaux contenant des données sur l’indexation de votre document: _uid, _id, _type, _index.
- Ajoutez de nouvelles propriétés à vos documents. Vous pouvez indexer la taille du JSON d’origine avec _size [1]. De même, vous pouvez indexer l’heure à laquelle il a été indexé avec _timestamp [2] et obliger Elasticsearch à le supprimer après un laps de temps spécifié avec _ttl. [3] Nous ne les couvrirons pas ici car il existe souvent de meilleures méthodes pour atteindre les mêmes objectifs (par exemple, il est plus économique d’extraire des index entiers, comme nous le verrons à la section 3.6.2) et ils pourraient devenir obsolètes dans les prochaines versions. 4]
3
- Contrôlez le fragment vers lequel vos documents sont acheminés. Ce sont _routing et parent. Nous allons examiner _routing au chapitre 9, section 9.8, en ce qui concerne la mise à l’échelle, et à la partie _parent au chapitre 8, où nous parlons des relations entre les documents.
3.4.1. Contrôler comment stocker et rechercher vos documents
Commençons par examiner _source, qui vous permet de stocker les documents que vous indexez, et _all, qui vous permet d’indexer tout leur contenu dans un seul champ.
_source pour stocker le contenu original
Le champ _source sert à stocker le document original au format original. Cela vous permet de voir les documents qui correspondent à une recherche classique, pas seulement à leurs identifiants.
_source peut avoir la propriété enabled à true ou false pour spécifier si vous souhaitez ou non stocker le document d’origine. Par défaut, elle est à true et, dans la plupart des cas, c’est une bonne chose, car l’existence de _source vous permet d’utiliser d’autres fonctionnalités importantes d’Elasticsearch. Par exemple, comme vous le découvrirez plus loin dans ce chapitre, la modification du contenu d’un document à l’aide de l’API de mise à jour nécessite que la propriété _source soit activée. De plus, l’implémentation de la mise en évidence par défaut nécessite _source (voir l’annexe C pour plus de détails sur la mise en évidence).
Étant donné que de nombreuses fonctionnalités dépendent du champ _source et que son stockage est relativement peu coûteux en termes d’espace et de performances, la possibilité de le désactiver peut être supprimée dans la version 2.0. Voir la discussion sur GitHub: https://github.com/elastic/elasticsearch/issues/8142. Pour les mêmes raisons, nous ne recommandons pas de le désactiver.
Pour voir comment ce champ fonctionne, regardons ce que Elasticsearch renvoie généralement lorsque vous récupérez un document précédemment indexé:
Vous obtenez également le _source JSON lorsque vous effectuez une recherche, car il est renvoyé par défaut.
Renvoyer seulement certains champs du document source
Lorsque vous récupérez ou recherchez un document, vous pouvez demander à Elasticsearch de ne renvoyer que des champs spécifiques et non l’intégralité de _source. Une façon de faire est de donner une liste de champs séparés par des virgules dans le paramètre fields; par exemple:
Lorsque _source est stocké, Elasticsearch obtient les champs requis à partir de là. Vous pouvez également stocker des champs individuels en définissant l’option store sur Yes. Par exemple, pour stocker uniquement le champ name, votre maping pourrait ressembler à ceci:
Cela peut être utile lorsque vous demandez à Elasticsearch un champ en particulier, car récupérer un seul champ stocké sera plus rapide que d’extraire l’intégralité de _source pour ensuite extraire ce champ, en particulier lorsque vous avez des documents volumineux.
Lorsque vous stockez également des champs individuels, vous devez tenir compte du fait que plus vous en stockez, plus votre index augmente. Habituellement, les index plus grands impliquent une indexation plus lente et une recherche plus lente.
Sous le capot, _source n’est qu’un autre champ stocké dans Lucene. Elasticsearch y stocke le JSON d’origine et en extrait les champs si nécessaire.
_all pour tout indexer
Tout comme _source stocke tout, _all indexe tout. Lorsque vous effectuez une recherche dans _all, Elasticsearch renvoie une réponse, quel que soit le champ correspondant. Ceci est utile lorsque les utilisateurs recherchent quelque chose sans savoir où chercher. Par exemple, la recherche sur “elasticsearch” peut correspondre au nom du groupe “Elasticsearch Denver” ainsi qu’à la balise elasticsearch dans d’autres groupes.
Lancer une recherche à partir de l’URI sans nom de champ recherchera sur _all par défaut:
Si vous recherchez toujours des champs spécifiques, vous pouvez désactiver _all en définissant enabled à false:
Cela réduira la taille totale de votre index et accélérera les opérations d’indexation.
Par défaut, chaque champ est inclus dans _all étant donné que include_in_all est implicitement défini à true. Vous pouvez utiliser cette option pour contrôler ce qui est inclus ou non dans _all:
L’utilisation de include_in_all vous offre une flexibilité, non seulement en termes d’économie d’espace, mais également en ce qui concerne le comportement de vos requêtes. Si une recherche est exécutée sans spécifier de champ, Elasticsearch ne fera correspondre que le contenu des champs également indexés dans _all.
L’ensemble suivant de champs prédéfinis comprend ceux utilisés pour identifier les documents: _index, _type, _id et _uid.
3.4.2. Identifier vos documents
Pour identifier un document dans le même index, Elasticsearch utilise une combinaison du type et de l’ID du document dans le champ _uid. Le champ _uid est composé des champs _id et _type que vous obtenez toujours lors de la recherche ou de l’extraction de documents:
À ce stade, vous pourriez vous demander: « Pourquoi Elasticsearch stocke-t-il les mêmes données à deux endroits différents: vous avez _id, puis _type, puis _uid? »
Elasticsearch utilise _uid en interne pour l’identification car tous les documents atterrissent dans les mêmes index Lucene. La séparation des types et des ID est une abstraction qui facilite le travail avec différentes structures en les divisant en types. _id est normalement extrait de _uid pour cette raison, mais _type doit être indexé séparément afin de pouvoir facilement filtrer les documents par type lorsque vous effectuez une recherche dans un type spécifique. Le tableau 3.2 présente les paramètres par défaut pour _uid, _id et _type.
Tableau 3.2. Paramètres par défaut pour les champs _id et _type
Jusqu’à présent, vous avez généralement fourni les identifiants manuellement dans le cadre de l’URI. Par exemple, pour indexer un document avec l’ID 1, vous exécutez quelque chose comme ceci:
Vous pouviez voir l’ID dans la réponse:
Alternativement, vous pouvez compter sur Elasticsearch pour générer des ID uniques pour vous. Ceci est utile si vous ne possédez pas déjà d’identifiant unique ou si vous n’avez pas besoin d’identifier des documents avec une propriété donnée. En règle générale, c’est ce que vous faites lorsque vous indexez les logs d’application: ils n’ont pas de propriété unique pour les identifier et ils ne sont jamais mis à jour.
Pour que Elasticsearch génère l’ID, utilisez HTTP POST et omettez l’ID:
Vous pouvez voir l’ID généré automatiquement dans la réponse:
Stocker le nom de l’index dans le document
Pour que Elasticsearch stocke le nom de l’index dans le document, ainsi que l’ID et le type, utilisez le champ _index. Comme avec _id et _type, vous pouvez voir _index dans les résultats d’une recherche ou d’une requête GET, mais comme avec _id et _type, ce que vous voyez ici ne provient pas du contenu du champ. _index est désactivé par défaut.
Elasticsearch connaît l’index de chaque résultat; il peut donc afficher une valeur d’ _index, mais vous ne pouvez pas rechercher _index par vous même. La commande suivante ne devrait rien trouver:
Pour activer _index, définissez enabled à true. Le mapping pourrait ressembler à ceci:
Si vous ajoutez des documents à ce type et relancez la recherche précédente, vous devez trouver vos nouveaux documents.
La recherche de documents appartenant à un index particulier peut être facilement effectuée à l’aide de l’URL d’index, comme vous l’avez fait jusqu’à présent. Mais le champ _index peut s’avérer utile dans des cas d’utilisation plus complexes. Par exemple, dans un environnement multi-locataire (plusieurs utilisateurs), vous pouvez avoir un index pour chaque utilisateur. Lorsque vous effectuez une recherche dans plusieurs index, vous pouvez utiliser le regroupement(aggrégation) de termes du champ _index pour afficher le nombre de documents appartenant à chaque utilisateur. Nous examinerons les agrégations au chapitre 7.
Nous avons examiné la manière dont vos documents sont mappés dans Elasticsearch afin que vous puissiez les indexer de manière adaptée à votre cas d’utilisation. Nous verrons ensuite comment modifier des documents déjà indexés.
3.5. MISE À JOUR DES DOCUMENTS EXISTANTS
Vous devrez peut-être modifier un document existant pour diverses raisons. Supposons que vous deviez changer l’organisateur pour un groupe de rencontre. Vous pouvez indexer un document différent sur la même adresse (index, type et ID), mais vous pouvez, comme vous vous en doutez, mettre à jour les documents en envoyant les modifications que vous souhaitez appliquer à Elasticsearch. L’API de mise à jour d’Elasticsearch vous permet d’envoyer les modifications que vous souhaitez appliquer à un document et elle renvoie une réponse indiquant si l’opération a réussi ou non. Le processus de mise à jour est illustré à la figure 3.3.
Comme l’illustre la figure 3.3, Elasticsearch effectue les tâches suivantes (de haut en bas):
- Récupère le document existant: pour que cela fonctionne, vous devez activer le champ _source; Sinon, Elasticsearch ne sait pas à quoi ressemble le document original.
- Applique les modifications que vous avez spécifiées. Par exemple, si votre document était:
et vous vouliez changer l’organisateur, le document résultant serait:
- Supprime l’ancien document et indexe le nouveau document (avec la mise à jour appliquée) à sa place
Dans cette section, nous allons examiner quelques façons d’utiliser l’API de mise à jour et comment gérer la simultanéité via la fonctionnalité de gestion de versions d’Elasticsearch.
3.5.1. Utilisation de l’API de mise à jour
Voyons d’abord comment mettre à jour les documents. L’API de mise à jour expose plusieurs manières de le faire:
- Envoyez un document partiel pour ajouter ou remplacer la même partie du document existant. C’est simple: vous envoyez un ou plusieurs champs avec leurs valeurs, et une fois la mise à jour terminée, vous vous attendez à les trouver dans le document.
- Lors de l’envoi de documents ou de scripts partiels, assurez-vous que le document est créé s’il n’existe pas. Vous pouvez spécifier le contenu d’origine d’un document à indexer s’il n’en existe pas déjà un.
- Envoyez un script pour mettre à jour le document pour vous. Par exemple, dans une boutique en ligne, vous pouvez augmenter le nombre de t-shirts en stock d’un certain montant au lieu de le définir à un nombre fixe.
Envoi d’un document partiel
Le moyen le plus simple de mettre à jour un ou plusieurs champs consiste à envoyer un document partiel avec les valeurs que vous devez définir pour ces champs. Pour ce faire, vous devez envoyer ces informations via une demande HTTP POST à l’endpoint _update de l’URL du document. La commande suivante fonctionnera après l’exécution du fichier populate.sh contenu dans les exemples de code:
Cela définit les champs que vous spécifiez sous doc avec les valeurs que vous indiquez, indépendamment des valeurs précédentes ou de l’existence ou non de ces champs. Si le document entier est manquant, l’opération de mise à jour échouera et vous renverra un message d’erreur disant que le document est manquant.
Lors de la mise à jour, vous devez garder à l’esprit qu’il peut y avoir des conflits. Par exemple, si vous modifiez l’organisateur du groupe en « Roy » et qu’un collègue le remplace en « Radu », l’une de ces mises à jour sera remplacée par l’autre. Pour contrôler cela, vous pouvez utiliser le contrôle de version, que nous verrons plus loin dans ce chapitre.
Créer des documents qui n’existent pas avec upsert
Pour gérer la situation lorsque le document de mise à jour n’existe pas, vous pouvez utiliser upsert. Vous connaissez peut-être ce terme dans les bases de données relationnelles; le terme est un portemanteau de mise à jour et d’insertion.
Si le document est manquant, vous pouvez ajouter un document initial à indexer dans la section upsert du fichier JSON. La commande précédente ressemble à ceci:
Modifier un document avec un script
Enfin, voyons comment mettre à jour un document en utilisant les valeurs du document existant. Supposons que vous ayez une boutique en ligne, que vous indexiez des produits et que vous souhaitiez augmenter le prix d’un produit de 10 points. Pour ce faire, vous utilisez la même API, mais au lieu de fournir un document, vous fournissez un script. Un script est généralement un morceau de code dans le JSON que vous envoyez à Elasticsearch, mais il peut également s’agir d’un script externe.
Nous parlerons davantage des scripts au chapitre 6, car vous utiliserez probablement des scripts pour rendre vos recherches plus pertinentes. Nous allons également vous montrer comment utiliser les scripts dans les agrégations du chapitre 7 et comment accélérer leur exécution au chapitre 10. Examinons maintenant trois éléments importants d’un script de mise à jour:
- Le langage de script par défaut est Groovy. Sa syntaxe est semblable à celle de Java, mais elle est plus facile à utiliser pour les scripts.
- Étant donné que la mise à jour récupère l’attribut _source d’un document existant, le modifie, puis réindexe le document obtenu, vos scripts modifient les champs de cet attribut également. Pour faire référence à _source, utilisez ctx._source, et pour faire référence à un champ spécifique, utilisez ctx._source [‘nom du champ’].
- Si vous avez besoin de variables, nous vous recommandons de les définir séparément du script lui-même sous params. C’est parce que les scripts doivent être compilés et qu’une fois compilés, ils sont mis en cache. L’exécution du même script plusieurs fois avec des paramètres différents nécessite que le script ne soit compilé qu’une seule fois. Les exécutions ultérieures prennent le script existant dans le cache. C’est plus rapide que d’avoir des scripts différents car ils auraient tous eu besoin d’une compilation.
Dans la figure 3.5, vous utiliserez un script Groovy pour augmenter le prix d’un t-shirt Elasticsearch de 10.
Selon la version d’Elasticsearch sur laquelle vous vous trouvez, l’exécution de scripts via l’API, comme dans la figure 3.5, peut être interdite par défaut pour des raisons de sécurité. Cela s’appelle un script dynamique et peut être activé en définissant script.disable_dynamic à false dans elasticsearch.yml. Vous pouvez également stocker des scripts sur le système de fichiers de chaque nœud ou dans l’index .scripts. Pour plus de détails, consultez la documentation du module de script d’Elasticsearch: www.elastic.co/guide/fr/elasticsearch/reference/current/modules-scripting.html.
Vous pouvez voir que ctx._source.price est utilisé à la place du ctx._source [‘price’]. C’est une autre manière de faire référence au champ price. Il est plus facile à utiliser avec curl car les guillemets simples et échappés dans les scripts de shell peuvent être source de confusion.
Maintenant que vous savez comment mettre à jour un document, voyons comment gérer l’accès simultané si plusieurs mises à jour se produisent en même temps.
3.5.2. Mise en œuvre du contrôle de la concurrence par le biais de la gestion des versions
Si plusieurs mises à jour sont exécutées en même temps, vous pouvez rencontrer des problèmes de simultanéité. Comme illustré à la figure 3.4, il est possible qu’une mise à jour réindexe le document entre le moment où l’autre mise à jour a récupéré le document original et celui pendant lequel elle applique ses propres modifications. Sans contrôle sur la simultanéité, la deuxième réindexation annulera les modifications de la première mise à jour.
Heureusement, Elasticsearch prend en charge le contrôle de la concurrence en utilisant un numéro de version pour chaque document. Le document initialement indexé est la version 1. Lorsque vous le réindexez via une mise à jour, le numéro de version est défini sur 2. Si le numéro de version a été défini sur 2 par une autre mise à jour entre-temps, il s’agit d’un conflit et la mise à jour actuelle échoue ( sinon, cela remplacerait l’autre mise à jour comme dans la figure 3.4). Vous pouvez réessayer la mise à jour et, s’il n’y a pas de conflit, la version sera définie sur 3.
Pour voir comment cela fonctionne, vous allez répliquer un processus similaire à celui illustré à la figure 3.5 en utilisant le code de la figure3.6:
1. Indexez un document, puis mettez-le à jour (update1).
2. Update1 commence en arrière-plan et inclut un temps d’attente (veille).
3. Pendant cette veille, émettez une autre commande de mise à jour (update2) modifiant le document. Cette modification a lieu entre la récupération du document original par update1 et son opération de réindexation.
4. Au lieu d’annuler les modifications de update2, update1 échoue car le document est déjà à la version 2. À ce stade, vous avez la possibilité de réessayer update1 et d’appliquer les modifications dans la version 3. (Voir la figure 3.6.)
La figure 3.5 est une représentation graphique de ce qui se passe dans cette liste.
Ce type de contrôle de concurrence est de type optimiste car il permet des opérations parallèles et suppose que les conflits apparaissent rarement, générant des erreurs lorsqu’elles apparaissent. Ceci est opposé au verrouillage pessimiste, dans lequel les conflits sont en premier lieu évités en bloquant les opérations susceptibles de provoquer des conflits.
Réessayer automatiquement une mise à jour en cas de conflit
Lorsqu’un conflit de version apparaît, vous pouvez le gérer dans votre propre application. S’il s’agit d’une mise à jour, vous pouvez essayer de l’appliquer à nouveau. Mais vous pouvez aussi faire en sorte que Elasticsearch le réapplique automatiquement en définissant le paramètre retry_on_conflict:
Utilisation de versions lorsque vous indexez des documents
Un autre moyen de mettre à jour un document sans utiliser l’API de mise à jour consiste à indexer un nouveau documents avec les mêmes index, type et ID. Cela écrase le document existant et vous pouvez toujours utiliser le champ version pour le contrôle d’accès simultané. Pour ce faire, définissez le paramètre version dans la requête HTTP. La valeur doit être la version que vous attendez du document. Par exemple, si vous vous attendez à ce que la version 3 soit déjà présente, une réindexation peut ressembler à ceci:
L’opération échouera avec l’exception de conflit de version que vous avez vue dans la liste 3.6 si la version actuelle est différente de 3.
Avec les versions, vous pouvez indexer ou mettre à jour vos documents en toute sécurité. Voyons ensuite comment supprimer des documents.
Utiliser le versioning externe
Jusqu’à présent, vous utilisiez la gestion des versions interne d’Elasticsearch, qui permet à Elasticsearch d’incrémenter automatiquement le numéro de version à chaque opération, qu’il s’agisse d’un index ou d’une mise à jour. Si la source de vos données est une autre base de données, vous disposez peut-être d’un système de gestion des versions dans ce data store. Par exemple, une basée sur l’horodatage. Dans ce cas, vous pouvez conserver les versions synchronisées ainsi que les documents.
Pour pouvoir compter sur le contrôle de version du système externe(le data store en question), vous devez ajouter version_type = external à chaque requête en plus du numéro de version:
Ainsi, Elasticsearch acceptera n’importe quel numéro de version, à condition qu’il soit supérieur à la version actuelle et qu’il n’incrémente pas le numéro de version seul.
3.6. SUPPRESSION DE DONNÉES
Maintenant que vous savez comment envoyer des données à Elasticsearch, voyons quelles sont vos options pour supprimer une partie de ce qui a été indexé. Si vous avez fait toutes les manipulations indiquées tout au long de ce chapitre, vous avez maintenant des données inutiles en attente de suppression. Nous allons examiner quelques méthodes pour supprimer les données ou au moins les réemmenager de façon à ce qu’elles ne puissent pas ralentir vos recherches ou indexations futures:
- Supprimer des documents individuels ou des groupes de documents. Lorsque vous faites cela, Elasticsearch les marque comme supprimées dans son système, ainsi elles ne s’afficheront plus dans les recherches et les retirera ultérieurement de l’index de manière asynchrone.
- Supprimer completement les index. C’est un cas particulier de suppression de groupes de documents. Mais cela diffère dans le sens où il est facile d’ameliorer les performances de l’opération dans ce cas. Ici la tâche principale consiste à supprimer tous les fichiers associés à cet index, ce qui se produit presque instantanément.
- Fermer les index. Bien qu’il ne s’agisse pas de supprimer, il convient de le mentionner ici. Un index fermé n’autorise pas les opérations de lecture ou d’écriture et ses données ne sont pas chargées en mémoire. Cela revient à supprimer des données d’Elasticsearch, mais cela reste sur le disque et elles sont faciles à restaurer: vous ouvrez l’index fermé.
3.6.1. Suppression de documents
Il existe plusieurs méthodes pour supprimer des documents individuels. Nous en discuterons ici:
- Supprimer un seul document par son ID. Cela est utile si vous n’avez qu’un seul document à supprimer, à condition que vous connaissiez son identifiant.
- Supprimer plusieurs documents en une seule demande. Si vous souhaitez supprimer plusieurs documents individuels, vous pouvez les supprimer tous en une fois dans une demande groupée, ce qui est plus rapide que la suppression d’un document à la fois. Nous aborderons les suppressions en masse au chapitre 10, ainsi que l’indexation et la mise à jour en masse.
- Supprimer un type de mapping, avec tous les documents qu’il contient. Cela permet de rechercher et de supprimer efficacement tous les documents que vous avez indexés dans ce type, ainsi que le mapping lui-même.
- Supprimez tous les documents correspondant à une requête. Cette opération est similaire à la suppression d’un type de mapping, en ce sens qu’une recherche est effectuée en interne pour identifier les documents à supprimer. Vous pouvez ici spécifier uniquement la requête que vous souhaitez et les documents correspondants seront supprimés.
Supprimer un seul document
Pour supprimer un seul document, vous devez envoyer une demande HTTP DELETE via son URL par exemple:
Vous pouvez également utiliser le contrôle de version pour gérer les accès simultanés avec suppressions, comme vous le faisiez lors de l’indexation et de la mise à jour. Par exemple, supposons que vous avez vendu toutes les chemises d’un certain type et que vous souhaitez supprimer ce document afin qu’il ne figure pas du tout dans les recherches. Mais vous ne savez peut-être pas à ce moment-là si un nouvel envoi est arrivé et si les données de stock ont été mises à jour. Pour ce faire, ajoutez le paramètre version à votre requête DELETE, comme auparavant avec les requêtes d’indexation et de mise à jour.
Il existe cependant une particularité dans la suppression en matière de gestion de versions. Une fois le document supprimé, il n’est plus là. Il est donc facile pour une mise à jour de le recréer, même si cela ne devrait pas être le cas (par exemple, car la version de cette mise à jour est inférieure à la version avec suppression). Ceci est particulièrement un problème si vous utilisez la gestion de version externe, car toute version externe fonctionnera sur un document qui n’existe pas.
Pour éviter ce problème, Elasticsearch conserve la version de ce document pendant un certain temps afin de pouvoir rejeter les mises à jour avec une version inférieure à celle de la suppression. Ce délai est de 60 secondes par défaut, ce qui devrait être suffisant pour la plupart des cas d’utilisation, mais vous pouvez le modifier en définissant index.gc_deletes dans elasticsearch.yml ou dans les paramètres de chaque index. Nous parlerons davantage de la gestion des paramètres d’index dans le chapitre 11, lorsqu’on s’attaquera à l’administration.
Suppression d’un type de mapping et de documents correspondant à une requête
Vous pouvez également supprimer un type de mapping entier, ce qui supprime le mapping lui-même ainsi que tous les documents indexés dans ce type. Pour ce faire, vous fournissez l’URL du type à la requête DELETE:
La difficulté avec la suppression des types est que le nom du type est simplement un autre champ dans les documents. Tous les documents d’un index se retrouvent dans les mêmes fragments, quel que soit le type de mapping auquel ils appartiennent. Lorsque vous exécutez la commande précédente, Elasticsearch doit rechercher les documents de ce type, puis les supprimer. Il s’agit d’un détail important en termes de performances pour la suppression de types par rapport à la suppression d’index complets, car la suppression de types prend généralement plus de temps et utilise plus de ressources.
Suppression de documents correspondants à une requête précise
De la même manière que vous pouvez interroger tous les documents d’un type et les supprimer, Elasticsearch vous permet de spécifier votre propre requête pour les documents que vous souhaitez supprimer par le biais d’une API appelée suppression par requête (delete by query). L’utilisation de l’API est similaire à l’exécution d’une requête, excepté que la requête HTTP est DELETE et que le endpoint _search est maintenant _query. Par exemple, pour supprimer tous les documents correspondant à «Elasticsearch» dans l’index get-together, vous pouvez exécuter cette commande:
Comme pour les requêtes classiques, décrites plus en détail au chapitre 4, vous pouvez exécuter une suppression par requête sur un type spécifique, sur plusieurs types, partout dans un index, dans plusieurs index ou dans tous les index. Par contre lorsque vous recherchez dans tous les index, faites attention lorsque vous exécutez une suppression par requête.
En plus d’être prudent, vous pouvez utiliser des sauvegardes. Nous parlerons de sauvegardes au chapitre 11, qui est entièrement consacré à l’administration.
3.6.2. Supprimer des index
Comme on pouvait s’y attendre, pour supprimer un index, vous envoyez une requête DELETE via l’URL de cet index:
Vous pouvez également supprimer plusieurs index en fournissant une liste séparée par des virgules ou même supprimer tous les index en fournissant _all comme nom d’index.
La suppression de tous les documents via curl -DELETE localhost: 9200 / _all vous semble-t-elle dangereuse? Vous pouvez empêcher cela en définissant action.destructive _requires_name: true dans elasticsearch.yml. Cela fera que Elasticsearch rejettera _all, ainsi que les caractères génériques dans les noms d’index, lorsqu’il s’agira de suppression.
La suppression d’un index est rapide car il s’agit principalement de supprimer les fichiers associés à tous les fragments de cet index. La suppression de fichiers sur le système de fichiers est rapide par rapport à la suppression de documents individuels. Lorsque vous faites cela, ils sont uniquement marqués comme supprimés. Ils sont supprimés lorsque les segments sont fusionnés. La fusion consiste à combiner plusieurs petits segments de Lucene en un segment plus grand.
Sur les segments et la fusion
Un segment est une partie de l’index Lucene (ou un fragment, dans la terminologie Elasticsearch) créée lors de l’indexation. Les segments ne sont jamais ajoutés; seuls les nouveaux sont créés lorsque vous indexez de nouveaux documents. Les données ne leur sont jamais supprimées car la suppression ne marque que les documents comme supprimés. Enfin, les données ne changent jamais car la mise à jour des documents implique une réindexation.
Lorsque Elasticsearch exécute une requête sur un fragment, Lucene doit interroger tous ses segments, fusionner les résultats et les renvoyer, à l’instar du processus consistant à interroger plusieurs fragments dans un index. Comme pour les fragments, plus vous devez parcourir de segments, plus la recherche est lente.
Comme vous pouvez l’imaginer, les opérations d’indexation normales créent beaucoup de ces petits segments. Pour éviter d’avoir un très grand nombre de segments dans un index, Lucene les fusionne de temps en temps.
La fusion de certains documents implique la lecture de leur contenu, à l’exclusion des documents supprimés, et la création de segments nouveaux et plus grands avec leur contenu combiné. Ce processus nécessite des ressources, notamment des E / S de processeur et de disque. Heureusement, les fusions s’exécutent de manière asynchrone et Elasticsearch vous permet de configurer de nombreuses options autour d’elles. Nous parlerons davantage de ces options au chapitre 12, où vous apprendrez comment améliorer les performances des opérations d’indexation, de mise à jour et de suppression.
3.6.3. Indices de clôture
Au lieu de supprimer des index, vous avez également la possibilité de les fermer. Si vous fermez un index, vous ne pourrez plus en lire ou écrire des données dessus avec Elasticsearch tant que vous ne l’ouvrez pas à nouveau. Ceci est utile lorsque vous avez des données en flux, telles que les logs d’application. Au chapitre 9, vous apprendrez qu’il est judicieux de stocker des données aussi fluides dans des index temporels, par exemple en créant un index par jour.
Dans un monde idéal, vous garderiez les logs d’applications indéfiniment au cas où vous auriez envie de revenir longtemps en arrière. D’autre part, disposer d’une grande quantité de données dans Elasticsearch nécessite des ressources supplémentaires. Pour ce cas d’utilisation, il est logique de fermer les anciens index. Il est peu probable que vous ayez besoin de ces données, mais vous ne souhaitez pas les supprimer non plus.
Pour fermer l’index de la boutique en ligne, envoyez une requête HTTP POST via son URL sur l’endpoint _close:
Pour l’ouvrir à nouveau, vous exécutez une commande similaire, seul le endpoint devient _open:
Une fois que vous fermez un index, la seule trace de celui-ci dans la mémoire d’Elasticsearch est constituée de métadonnées, telles que le nom et l’emplacement des fragments. Si vous disposez de suffisamment d’espace disque et que vous ne savez pas s’il est nécessaire de rechercher à nouveau ces données, il est préférable de fermer les index plutôt que de les supprimer. En les fermant, vous avez la certitude que vous pouvez toujours rouvrir un index fermé et y effectuer une nouvelle recherche.
3.6.4. Réindexation des exemples de documents
Au chapitre 2, vous avez utilisé les exemples de code du livre pour indexer des documents. L’exécution de populate.sh à partir de ces exemples de code supprime l’index get-together que vous avez créé dans ce chapitre et réindexe les exemples de documents. Si vous examinez à la fois le script populate.sh et la définition de mapping de mapping.json, vous reconnaîtrez différents types de champs que nous avons abordés dans ce chapitre.
Certaines options de mapping et d’indexation, telles que les paramètres d’analyse, sont traitées dans les chapitres à venir. Pour le moment, exécutez populate.sh pour préparer l’index get-together pour le chapitre 4, où nous explorerons plus en profondeur les recherches. Les exemples de code vous fournissent des données avec lesquels travailler.
3.7. RÉSUMÉ
Avant de poursuivre, examinons à nouveau les sujets abordés dans ce chapitre:
- Les mappings vous permettent de définir des champs dans vos documents et d’indiquer comment ces champs sont indexés. Nous disons qu’Elasticsearch est sans schéma, car les mappings sont étendus automatiquement, mais en production, vous devez souvent contrôler ce qui est indexé, ce qui est stocké et comment il est stocké.
- La plupart des champs de vos documents sont des types de base, tels que des chaînes et des nombres. La façon dont vous indexez ces champs a un impact important sur les performances d’Elasticsearch et sur la pertinence de vos résultats de recherche, par exemple les paramètres d’analyse, que nous traiterons au chapitre 5.
- Un seul champ peut également être un conteneur pour plusieurs champs ou valeurs. Nous avons examiné les tableaux et les champs multiples, qui vous permettent d’avoir plusieurs occurrences du même type de base dans le même champ.
- Outre les champs spécifiques à vos documents, Elasticsearch fournit des champs prédéfinis, tels que _source et _all. La configuration de ces champs modifie certaines données que vous ne fournissez pas explicitement dans vos documents, mais a un impact important sur les performances et les fonctionnalités. Par exemple, vous pouvez également décider quels champs doivent être indexés dans _all.
- Comme Elasticsearch stocke des données dans des segments Lucene qui ne changent pas une fois créés, la mise à jour d’un document implique de récupérer celui qui existe, de placer les modifications dans un nouveau document indexé et de marquer l’ancien comme étant supprimé.
- La suppression de documents a lieu lorsque les segments de Lucene sont fusionnés de manière asynchrone. C’est également la raison pour laquelle la suppression d’un index complet est plus rapide que celle d’un ou plusieurs documents individuels: cela implique uniquement la suppression de fichiers sur le disque sans fusion.
- Tout au long de l’indexation, de la mise à jour et de la suppression, vous pouvez utiliser des versions de document pour gérer les problèmes de simultanéité. Avec les mises à jour, vous pouvez demander à Elasticsearch de réessayer automatiquement en cas d’échec d’une mise à jour en raison d’un problème de simultanéité.