Technique

Économie d'espace : un bénéfice méconnu des index triés dans Elasticsearch

Elasticsearch 6.0 inclut une nouvelle fonctionnalité : les index triés. Vous pouvez en apprendre davantage sur le blog, mais, pour faire court, au moment de l'indexation, les documents sont triés par une ou plusieurs clés de tri dans l'ordre de votre choix. Cela présente quelques avantages :

  • Si vous demandez à Elasticsearch d'afficher et de trier un ensemble de résultats en utilisant la clé utilisée pour trier l'index, Elasticsearch n'a plus rien à classer pendant la recherche. Les résultats sont triés à l'avance !
  • Si vous n'avez pas besoin de tous les résultats et que vous triez ces derniers selon la clé de tri, Elasticsearch interrompt la recherche dès qu'il dispose de suffisamment de résultats pour vous répondre. Vous pouvez alors bénéficier d'améliorations exceptionnelles en matière de performances.
  • Lorsque vos recherches utilisent des opérateurs AND pour relier différents champs, l'index trié facilite les regroupements et permet à Elasticsearch d'ignorer de grands blocs de documents pour accélérer les recherches.

En bref, dans certains cas, cette fonctionnalité rend les recherches plus rapides, particulièrement lorsque de nombreux utilisateurs recherchent et trient vos documents de la même manière. En revanche, on parle peu des bienfaits des index triés en matière d'économie d'espace. Parlons-en sans plus attendre.

Attention : les index triés ne conviennent pas à tout le monde

Avant de décrire le fonctionnement des index triés, je me dois de rappeler que cette fonctionnalité ne convient pas à toutes les situations. Elle a pour effet d'exécuter les actions de tri au moment de l'indexation. Le tri est une opération gourmande. Si la vitesse d'indexation compte parmi vos principales préoccupations, réfléchissez-y à deux fois avant d'activer cette fonctionnalité. Elle peut réduire les performances d'écriture de 40 à 50 %. C'est pourquoi, si vos applications requièrent un taux élevé d'indexation, ce qui est souvent le cas lorsque des volumes importants de logs, d'indicateurs ou de données d'analyse de sécurité doivent être traités, les index triés ne sont probablement pas faits pour vous. En revanche, il peut se révéler utile si votre taux d'indexation est plus faible, si la vitesse de recherche constitue pour vous un facteur déterminant ou si vous bénéficiez d'un processus régulier de réindexation qui s'exécute hors des pics d'indexation.

Examen d'ordres de tri possibles : exemple

Imaginons que j'exécute une instance Elasticsearch qui sert à rechercher des produits. Supposons que je dispose d'un ensemble de documents qui, au moment de l'indexation, ressemble à ce qui suit (je les résume dans un tableau pour faciliter leur lecture) :

ID produitCatégorie de produitCouleur de produitPrix
206f467b-8cfeChaussuresRouge$97.00
4f89fbec-acc3VestesNoir$120.50
47771396-dfe3VestesGris$170.10
c6c8fbdf-651bChapeauxJaune$15.00
dc18c426-0eb3ChaussuresRouge$107.20
ee304259-df57VestesNoir$88.00
9332c0ac-e55eChaussuresNoir$49.00
30e96765-52a1ChapeauxBleu$11.00
811cc8ca-d6bbVestesBleu$92.99

Supposons maintenant que nous souhaitons utiliser les index triés. Quelle clé de tri allons-nous utiliser ? Plusieurs options s'offrent à nous : la catégorie de produit, la couleur de produit ou le prix. Si les recherches effectuées par les utilisateurs sont presque toujours triées par prix et qu'aucun filtre de catégorie ou de couleur n'est disponible, il semble logique d'utiliser le prix comme clé de tri. Cependant, il est probable que les utilisateurs sélectionnent au moins une catégorie avant de rechercher l'article le moins cher. Il se peut aussi qu'ils expriment une préférence quant à la couleur du produit. Trions par catégorie croissante (product_category), par couleur croissante (product_color), puis par prix croissant (price).

"sort.field" : ["product_category", "product_color", "price"], "sort.order" : ["asc", "asc", "asc"]

L'index trié ressemble à ça :

ID produitCatégorie de produitCouleur de produitPrix
30e96765-52a1ChapeauxBleu$11.00
c6c8fbdf-651bChapeauxJaune$15.00
ee304259-df57VestesNoir$88.00
4f89fbec-acc3VestesNoir$120.50
811cc8ca-d6bbVestesBleu$92.99
47771396-dfe3VestesGris$170.10
9332c0ac-e55eChaussuresNoir$49.00
206f467b-8cfeChaussuresRouge$97.00
dc18c426-0eb3ChaussuresRouge$107.20

Des choses intéressantes se produisent. En voici un exemple :

  • Demandons à Elasticsearch de rechercher les deux paires de chaussures les moins chères et de les trier par prix sans demander le nombre total de résultats pour l'ensemble des chaussures. Elasticsearch doit rechercher le bloc correspondant aux chaussures, ce qu'il peut faire efficacement en ignorant toutes les autres catégories. Une fois les deux résultats trouvés, Elasticsearch les affiche après avoir interrompu la recherche. Pour que cela fonctionne, vous devez inclure chaque élément de l'ordre de tri dans l'index, même en cas de correspondance avec vos filtres.
  • Si je demande product_category:Vestes AND product_color:Noir à Elasticsearch, ce dernier peut ignorer l'ensemble des chapeaux et des chaussures, se concentrer sur les produits « Noir », puis ignorer toutes les autres couleurs.
  • Elasticsearch compresse significativement les données en arrière-plan. La compression fonctionne lorsque des valeurs se répètent. Elle est d'autant plus efficace lorsque les valeurs répétées sont proches les unes des autres dans l'index. En regroupant tous les produits par catégories ou par couleur, les données correspondantes peuvent être efficacement compressées sur le disque. L'espace occupé sur le disque est ainsi réduit, et le système d'exploitation dispose de plus d'espace dans le cache du système de fichiers pour toujours plus de vitesse.

En général, il est recommandé d'utiliser des ordres de tri de cardinalité croissante pour bénéficier du maximum de valeurs répétées consécutives possibles.

Combien d'espace disque puis-je économiser ?

Combien d'espace disque allez-vous économiser en activant cette fonctionnalité ? Comme souvent dans la vie, ça dépend. La cardinalité du champ choisi pour le tri est un facteur prédominant. Toutefois, les économies d'espace disque peuvent être substantielles. Le weekend dernier, j'ai décidé de déplacer quelques données d'automatisation de mes objets connectés d'un vieil ordinateur à une nouvelle machine. Il existe des façons plus rapides de migrer des données, en restaurant une sauvegarde par exemple, mais j'ai pris le temps de faire une réindexation, car je voulais savoir combien d'espace je pouvais économiser en triant l'index. J'ai d'abord réindexé les objets sans ordre de tri :

status    index           pri    docs.count    docs.deleted    pri.store.size 
open      devices-2017    1      33310674      0               4.2gb

Il s'agit d'un peu plus de 30 appareils. Chacun d'eux transmet son état toutes les 30 secondes, ce qui fait  environ un document par seconde au final. Il faudrait que j'augmente massivement le taux d'indexation ou le nombre d'appareils pour observer des ralentissements lors de l'indexation. Dans mon cas, les index triés semblent une bonne solution. Les données sont composées d'identifiants et de noms d'appareils, ainsi que de plusieurs relevés de capteurs, tels que des températures, des indicateurs de marche/arrêt ou des informations d'état. J'ai trié l'index par identifiant d'appareil, puis par heure. Je me suis dit qu'il est très probable que, pour un appareil donné, les valeurs soient semblables ou identiques aux alentours d'une même heure, ce qui permettrait d'améliorer la compression. Par exemple, si l'état d'un interrupteur indique « marche » à 7:00:00, la probabilité est élevée que l'état soit identique à 7:00:30, à 7:01:00, puis pendant encore quelques minutes. Le niveau de compression de ces données devrait être intéressant. Voici le résultat après avoir trié l'index :

status    index           pri    docs.count     docs.deleted    pri.store.size
open      devices-2017    1      3310674        0               2.5gb

Environ 40 % d'économie d'espace !

Attention (encore)

À ce stade, je me sens à nouveau obligé d'avertir tout le monde, car qui n'apprécierait pas que ses données occupent 40 % moins d'espace disque ? Résumons ça en deux phrases :

  • Les économies d'espace obtenues varient. J'ai obtenu 20 % d'économie en triant l'index d'un autre ensemble de données. Choisissez avec soin vos champs de tri.
  • Votre vitesse d'indexation diminuera. Si la vitesse d'indexation vous importe énormément (par exemple, parce que vous traitez des volumes importants de logs ou d'indicateurs), le nombre de documents pouvant être indexés en peu de temps est probablement déterminant à vos yeux. Dans ce cas, il se peut que l'utilisation des index triés ne vous convienne pas.

Si les économies d'espace disque vous importent beaucoup plus que la vitesse d'indexation ou si le volume de votre index ne ralentit pas la vitesse d'indexation, les index triés pourraient valoir le coup.