Tech Talk : Recherche dans un grand champ de texte avec les champs stockés d'Elasticsearch (Partie 1)

Elasticsearch devient de plus en plus populaire au fil des ans, aidant les clients à explorer et à analyser leurs données différemment grâce à la recherche. Plus récemment, il a été présenté dans le quadrant Gartner. Avec Elasticsearch, il est incroyablement facile de démarrer un cluster et de se mettre au travail. Cependant, si vous ne configurez pas votre cluster en conséquence, vous aurez tôt ou tard des problèmes.

Dans cet article, nous nous concentrerons sur la modification du comportement par défaut d'Elasticsearch en ce qui concerne le stockage des champs originaux. Nous prêterons également attention aux avantages et aux inconvénients potentiels en termes de performances.

Ce que nous avons essayé de faire

Dans un article précédent sur l'application Function, j'ai parlé de l'extraction et du traitement de texte à partir de documents PDF. Je vais maintenant vous expliquer comment nous avons rendu tous les résultats de calcul disponibles pour la recherche en optimisant les performances.

Notre ensemble de données est composé de documents JSON combinant du texte et des attributs extraits de PDF. La taille du texte est, en moyenne, de 200 000 caractères. L'expérience de l'utilisateur doit être la même que celle d'un célèbre moteur de recherche comme Google. De plus, lorsqu'un utilisateur tape une requête, il doit recevoir une réponse rapidement. Un résultat après 1 minute n'a pas de sens dans nos cas d'utilisation.

Notre ensemble de données sera de 32 To de données indexées. En outre, nous savons qu'Elasticsearch scale-out est bien meilleur que scale-up et qu'il peut facilement gérer les données et la charge de travail. Ce sera une question d'architecture et de nombre de nœuds.

Pour commencer, nous disposons d'un cluster composé de 21 nœuds, à titre d'estimation approximative. Certaines optimisations et configurations méritent d'être mentionnées et expérimentées, par exemple les champs stockés et la mise en évidence. Nous nous concentrerons sur la configuration des champs stockés dans cette première partie.

Le champ stocké dans Elasticsearch

Dans Elasticsearch, un champ stocké vous permet de récupérer sa valeur originale dans le résultat d'une requête. Le document original sera stocké dans un champ appelé source_ qui sera retourné. Dans la plupart des cas, c'est ainsi que vous obtiendrez le document original de votre recherche. Par défaut, le champ source_ contient tous les champs, y compris le grand champ, à moins que vous n'excluiez ou n'incluiez explicitement des champs.

Elasticsearch va lire la _source depuis le disque à chaque fois que vous exécutez une requête, l'analyser en JSON et la renvoyer. La lecture d'un tel champ stocké contenant un texte volumineux peut poser un problème de performance à la fois au niveau de l'unité centrale (analyse d'une structure JSON volumineuse) et des E/S du disque (lecture de nombreuses données). En outre, la lecture d'une quantité inutilement élevée de données à partir du disque épuisera le cache du système de fichiers, ce qui le rendra moins efficace. En fonction de la taille du champ de texte volumineux et des cas d'utilisation, il serait judicieux de modifier le comportement par défaut afin d'obtenir de meilleures performances.

Modifier le _source dans Elasticsearch

Elasticsearch offre la possibilité d'exclure des champs de cette _source particulière. Il vous permet également de stocker un champ spécifique séparément de la _source. De cette façon, vous serez en mesure de retourner des informations précieuses telles que le "titre" et d'autres métadonnées attachées au document sans avoir à analyser et à lire un texte volumineux.

Pour stocker votre champ séparément, vous devez configurer votre mappage d'index : - Excluez-le de la _source. - Spécifier store : true pour stocker séparément.

{
"mappings": {
  "_source": {
    "excludes": ["content"]
  },
  "properties": {
    "content": {
      "type": "text",
      "store": true
    },
    "author": {
      "type": "keyword"
    },
    "title": {
      "type": "keyword"
    }
  }
}
}

Stocker les champs séparément

Même si cette solution permet d'améliorer considérablement les performances, elle présente également de graves inconvénients qu'il convient de connaître.

Comme expliqué dans la documentation officielle, l'exclusion d'un champ de _sourcedésactivera également certaines fonctionnalités utiles :

  • API de mise à jour, de mise à jour par requête et de réindexation.

  • La fonction de mise en évidence des champs non stockés. La mise en évidence des résultats d'une recherche nécessite que le champ soit stocké d'une manière ou d'une autre.

  • Mise à jour d'un index vers une version majeure. À un moment donné, vous ne pourrez plus effectuer de mise à jour.

  • Possibilité de déboguer les requêtes en visualisant le document original.

  • Toutes les fonctionnalités futures potentielles nécessitent la _source originale contenant tous les champs.

Ce que nous recommandons dans Elasticsearch

Il est désormais évident que ce type d'amélioration des performances a un coût élevé. Quelques scénarios nous viennent à l'esprit :

  • Si vous utilisez le texte volumineux exclusivement pour construire l'index inversé en vue d'une recherche en texte intégral, il sera judicieux de l'exclure de la _source. Vous réduirez potentiellement la charge de travail des E/S et de l'unité centrale, mais aussi l'utilisation du disque.

  • Si, dans de rares cas, nous devons récupérer un texte volumineux, il sera judicieux de le stocker séparément du champ _source.

D'après nos cas d'utilisation (grand champ de 200 Ko), nous n'avons pas constaté d'amélioration notable du stockage séparé du grand champ de texte qui justifierait de tels inconvénients. Nous pensons que le cache du système de fichiers a fait la différence.

Comme indiqué dans cet article sur l'amélioration des performances d'Elasticsearch, il serait judicieux d'exclure explicitement le champ de la _source lorsque la taille du champ (100 Mo) est suffisamment importante pour que l'amélioration des performances prenne le pas sur les inconvénients. Dans ce cas très particulier, nous recommandons fortement de conserver les données dans un magasin de données distinct :

  • Mettre à jour les documents en les supprimant manuellement et en les réindexant.

  • Mettre à jour les indices vers une version majeure.

Lors de la mise à niveau, vous devrez repartir d'un cluster vide et réindexer tous les documents manuellement. Dans certains cas, cela peut être inacceptable d'un point de vue commercial, et vous devrez alors travailler avec deux clusters distincts pour minimiser les temps d'arrêt. Vous pouvez également travailler avec un seul cluster s'il est suffisamment grand pour indexer vos données deux fois.

Conclusion

Nous pensions initialement que notre ensemble de données comprendrait un grand champ de texte. Nous nous sommes rapidement rendu compte que notre champ n'était pas si grand, et qu'Elasticsearch est capable de gérer un champ de texte beaucoup plus grand que nous le pensions. L'idée de stocker séparément le grand champ de texte peut sembler intrigante à première vue, mais elle n'apporte aucun avantage précieux en termes de performances dans notre ensemble de données. Nous restons convaincus qu'elle pourrait améliorer les performances dans certains cas particuliers.

Dans l'ensemble, l'exclusion de champs du _source doit être une décision réfléchie. Dans la plupart des cas, nous ne recommandons pas de modifier le _source à moins qu'un champ ne soit suffisamment important pour justifier les inconvénients. Pour en savoir plus sur ce sujet, je vous invite à lire cette discussion.

Précédent
Précédent

Discussion technique : Recherche dans un grand champ de texte avec Elasticsearch et Kibana (Partie 2)

Suivant
Suivant

Tech Talk : Construire des solutions de charge de travail intensive avec l'application de fonction d'Azure, les attentes et les limites