<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title><![CDATA[Andre Luiz - Elasticsearch Labs]]></title>
    <description><![CDATA[Articles and tutorials from the Search team at Elastic]]></description>
    <copyright><![CDATA[© 2026. Elasticsearch B.V. All Rights Reserved]]></copyright>
    <image>
      <title><![CDATA[Andre Luiz - Elasticsearch Labs]]></title>
      <url>https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1121c0bf0e8a6e65/6a88da6340a1841030ef456f/search-labs-thumbnail.png</url>
      <link>https://www.elastic.co/fr/search-labs/author/andre-luiz</link>
    </image>
    <link>https://www.elastic.co/fr/search-labs/author/andre-luiz</link>
    <atom:link href="https://www.elastic.co/fr/search-labs/rss/author/andre-luiz.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[fr]]></language>
    <lastBuildDate>Mon, 28 Sep 2026 04:02:30 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Mapping embeddings to Elasticsearch field types : semantic_text, dense_vector, sparse_vector]]></title>
    <description><![CDATA[Discuter comment et quand utiliser semantic_text, dense_vector, ou sparse_vector, et comment ils sont liés à la génération d'embedding.]]></description>
    <content:encoded><![CDATA[<p>L'utilisation d'enchâssements pour améliorer la pertinence et la précision de la recherche d'informations s'est considérablement développée au fil des ans. Des outils comme Elasticsearch ont évolué pour prendre en charge ce type de données grâce à des types de champs spécialisés tels que les vecteurs denses, les vecteurs épars et le texte sémantique. Cependant, pour obtenir de bons résultats, il est essentiel de comprendre comment faire correspondre correctement les embeddings aux types de champs Elasticsearch disponibles : <code>semantic_text</code>, <code>dense_vector</code>, et <code>sparse_vector</code>.</p><p>Dans cet article, nous examinerons ces types de champs, quand utiliser chacun d'entre eux et comment ils sont liés à la génération d'encarts et aux stratégies d'utilisation, à la fois lors de l'indexation et de l'interrogation.</p><h2>Type de vecteur dense</h2><p>Le type de champ <code>dense_vector</code> dans Elasticsearch est utilisé pour stocker des vecteurs denses, qui sont des représentations numériques de données telles que du texte, des images et de l'audio, où presque toutes les dimensions sont pertinentes... Ces vecteurs sont générés à l'aide de modèles d'intégration fournis par des plateformes telles que OpenAI, Cohere ou Hugging Face, et sont conçus pour capturer la signification sémantique globale des données, même si elles ne partagent pas de termes exacts avec d'autres documents.</p><p>Dans Elasticsearch, les vecteurs denses peuvent avoir jusqu'à 4096 dimensions en fonction du modèle utilisé. Par exemple, le modèle all-MiniLM-L6-v2 génère des vecteurs de 384 dimensions, tandis que le modèle text-embedding-ada-002 d'OpenAI produit des vecteurs de 1536 dimensions.</p><p>Le champ <code>dense_vector</code> est généralement adopté comme type par défaut pour stocker ce type d'intégration lorsqu'un plus grand contrôle est nécessaire, comme l'utilisation de vecteurs pré-générés, l'application de fonctions de similarité personnalisées ou l'intégration avec des modèles externes.</p><h3>Quand et pourquoi utiliser le type dense_vector ?</h3><p>Les vecteurs denses sont excellents pour capturer la similarité sémantique entre des phrases, des paragraphes ou des documents entiers. Ils fonctionnent très bien lorsque l'objectif est de comparer le sens global des textes, même s'ils ne partagent pas les mêmes termes.</p><p>Le champ de vecteurs denses est idéal lorsque vous disposez déjà d'un pipeline externe de génération d'incrustations utilisant des modèles fournis par des plateformes telles que OpenAI, Cohere ou Hugging Face et que vous souhaitez uniquement stocker et interroger ces vecteurs manuellement. Ce type de champ offre une grande compatibilité avec les modèles d'intégration et une souplesse totale en matière de génération et d'interrogation, ce qui permet de contrôler la manière dont les vecteurs sont produits, indexés et utilisés lors de la recherche.</p><p>En outre, il prend en charge différentes formes de recherche sémantique, avec des requêtes telles que k-NN ou script_score pour les cas où il est nécessaire d'ajuster la logique de classement. Ces possibilités font du vecteur dense un outil idéal pour des applications telles que RAG (Retrieval-Augmented Generation), les systèmes de recommandation et les recherches personnalisées basées sur la similarité.</p><p>Enfin, le champ vous permet de personnaliser la logique de pertinence, en utilisant des fonctions telles que <code>cosineSimilarity</code>, <code>dotProduct</code> ou <code>l2norm</code> pour adapter le classement aux besoins de votre cas d'utilisation. </p><p>Les vecteurs denses restent la meilleure option pour ceux qui ont besoin de flexibilité, de personnalisation et de compatibilité avec des cas d'utilisation avancés comme ceux mentionnés ci-dessus.</p><h3>Comment utiliser la requête pour un type de vecteur dense ?</h3><p>Les recherches sur les champs définis comme <strong><code>dense_vector</code></strong> utilisent la requête des k-voisins les plus proches. Cette requête est chargée de trouver les documents dont le vecteur dense est le plus proche du vecteur de la requête. Vous trouverez ci-dessous un exemple d'application d'une requête k-NN à un champ vectoriel dense :</p>{
  "knn": {
    "field": "my_dense_vector",
    "k": 10,
    "num_candidates": 50,
    "query_vector": [/* vector generated by model */]
  }
}<p>Outre la requête k-NN, s'il est nécessaire de personnaliser la notation des documents, il est également possible d'utiliser la requête script_score, en la combinant avec des fonctions de comparaison vectorielle telles que <strong>cosineSimilarity, dotProduct ou l2norm</strong> pour calculer la pertinence d'une manière plus contrôlée. Voir l'exemple :</p>{
"script_score": {
    "query": { "match_all": {} },
    "script": {
      "source": "cosineSimilarity(params.query_vector,
'my_dense_vector') + 1.0",
      "params": {
        "query_vector": [/* vector */]
      }
    }
  }
}<p>Si vous souhaitez aller plus loin, je vous recommande d'explorer l'article <a href="https://www.elastic.co/search-labs/blog/vector-search-set-up-elasticsearch">Comment configurer la recherche vectorielle dans Elasticsearch.</a></p><p></p><h2>Type de vecteur épars</h2><p>Le type de champ <strong><code>sparse_vector</code></strong> est utilisé pour stocker des vecteurs épars, qui sont des représentations numériques où la plupart des valeurs sont nulles et où seuls quelques termes ont des poids significatifs. Ce type de vecteur est courant dans les modèles basés sur les termes tels que SPLADE ou ELSER (Elastic Learned Sparse EncodeR).</p><h3>Quand et pourquoi utiliser un type de vecteur peu dense ?</h3><p>Les vecteurs épars sont idéaux lorsque vous avez besoin d'une recherche plus précise en termes lexicaux, sans sacrifier l'intelligence sémantique. Ils représentent le texte sous forme de paires jeton/valeur, en ne mettant en évidence que les termes les plus pertinents avec les poids associés, ce qui permet de gagner en clarté, en contrôle et en efficacité.</p><p>Ce type de champ est particulièrement utile lorsque vous générez des vecteurs basés sur des termes, comme dans les modèles ELSER ou SPLADE, qui attribuent des poids différents à chaque mot en fonction de son importance relative dans le texte.</p><p>Pour les cas où vous souhaitez contrôler l'influence de mots spécifiques dans la requête, les types de vecteurs épars vous permettent d'ajuster manuellement le poids des termes afin d'optimiser le classement des résultats.</p><p>Parmi les principaux avantages, citons la transparence de la recherche, puisqu'il est possible de comprendre clairement pourquoi un document a été jugé pertinent, et l'efficacité du stockage, puisque seuls les jetons dont la valeur n'est pas nulle sont enregistrés, contrairement aux vecteurs denses qui stockent toutes les dimensions.</p><p>En outre, les vecteurs épars sont le complément idéal des stratégies de recherche hybrides et peuvent même être combinés avec des vecteurs denses pour associer la précision lexicale à la compréhension sémantique.</p><h3>Comment utiliser l'interrogation pour le type de vecteur épars ?</h3><p>La requête <strong><code>sparse_vector</code></strong> vous permet de rechercher des documents sur la base d'un vecteur de requête au format jeton/valeur. Vous trouverez ci-dessous un exemple de requête :</p>{
  "query": {
    "sparse_vector": {
      "field": "field_sparse",
      "query_vector": {
        "token1": 0.6,
        "token2": 0.2,
        "token3": 0.9
      }
    }
  }
}<p>Si vous préférez utiliser un modèle formé, il est possible d'utiliser un point final d'inférence qui transforme automatiquement le texte de la requête en un vecteur peu dense :</p>{
  "query": {
    "sparse_vector": {
      "field": "field_sparse",
      "inference_id": "the inference ID to produce the token/weights",
      "query": "search text"
    }
  }
}<p>Pour approfondir ce sujet, je vous suggère de lire <a href="https://www.elastic.co/search-labs/blog/sparse-vector-embedding">Understanding sparse vector embeddings with trained ML models (Comprendre les encastrements de vecteurs épars avec des modèles ML formés).</a></p><h2>Type de texte sémantique</h2><p>Le type de champ <strong><code>semantic_text</code></strong> est le moyen le plus simple et le plus direct d'utiliser la recherche sémantique dans Elasticsearch. Il gère automatiquement la génération de l'intégration, à la fois au moment de l'indexation et de l'interrogation, par le biais d'un point final d'inférence. Cela signifie que vous n'avez pas à vous soucier de générer ou de stocker des vecteurs manuellement.</p><h3>Quand et pourquoi utiliser le texte sémantique ?</h3><p>Le champ <code>semantic_text</code> est idéal pour ceux qui veulent commencer avec un minimum d'effort technique et sans avoir à manipuler les vecteurs manuellement. Ce champ automatise des étapes telles que la génération de l'encastrement et le mappage de la recherche vectorielle, ce qui rend l'installation plus rapide et plus pratique.</p><p>Vous devriez envisager d'utiliser <code>semantic_text</code> si vous appréciez la <strong>simplicité et l'abstraction</strong>, car il <strong>élimine la complexité de la configuration manuelle des mappings, de la génération d'embedding et des pipelines d'ingestion</strong>. Il suffit de sélectionner le modèle d'inférence et Elasticsearch s'occupe du reste.</p><p>Parmi les principaux avantages, citons la <strong>génération automatique de l'intégration,</strong> effectuée à la fois pendant l'indexation et l'interrogation, et le <strong>mappage prêt à l'emploi</strong>, qui est préconfiguré pour prendre en charge le modèle d'inférence sélectionné.</p><p>En outre, le champ offre une <strong>prise en charge native du découpage automatique des textes longs (text chunking</strong>), ce qui permet de diviser les textes volumineux en passages plus petits, chacun ayant sa propre intégration, ce qui améliore la précision de la recherche. La productivité s'en trouve grandement améliorée, en particulier pour les équipes qui souhaitent fournir rapidement de la valeur ajoutée sans avoir à s'occuper de l'ingénierie sous-jacente de la recherche sémantique.</p><p>Cependant, bien que <code>semantic_text</code> offre rapidité et simplicité, cette approche présente certaines limites. Il permet d'utiliser des modèles standard du marché, pour autant qu'ils soient disponibles en tant que points de terminaison d'inférence dans Elasticsearch. Cependant, <strong>il ne prend pas en charge les encastrements générés de l'extérieur</strong>, comme c'est le cas avec le champ <code>dense_vector</code>.</p><p>Si vous avez besoin de plus de contrôle sur la manière dont les vecteurs sont générés, si vous souhaitez utiliser vos propres incorporations ou si vous devez combiner plusieurs champs pour des stratégies avancées, les champs <code>dense_vector</code> et <code>sparse_vector</code> offrent la flexibilité nécessaire pour des scénarios plus personnalisés ou spécifiques à un domaine.</p><h3>Comment utiliser la requête pour le type de texte sémantique ?</h3><p>Avant <strong><code>semantic_text</code></strong>, il était nécessaire d'utiliser une requête différente selon le type d'intégration (dense ou éparse). Une requête <code>sparse_vector</code> a été utilisée pour les champs peu denses, tandis que les champs <code>dense_vector</code> ont nécessité des requêtes KNN.</p><p>Avec le type de texte sémantique, la recherche est effectuée à l'aide de la <a href="https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-semantic-query">requête sémantique</a>, qui génère automatiquement le vecteur de la requête et le compare avec les enchâssements des documents indexés. Le type <strong><code>semantic_text</code></strong> vous permet de définir un point final d'inférence pour intégrer la requête, mais si aucun n'est spécifié, le même point final que celui utilisé lors de l'indexation sera appliqué à la requête.</p>{
  "query": {
    "semantic": {
      "field": "semantic_text_field",
      "query": "search text"
    }
  }
}<p>Pour en savoir plus, je vous propose de lire l'article <a href="https://www.elastic.co/search-labs/blog/semantic-search-simplified-semantic-text">Elasticsearch new semantic_text mapping : Simplifier la recherche sémantique</a>.</p><h2>Conclusion</h2><p>Lors du choix de la méthode de mappage des embeddings dans Elasticsearch, il est essentiel de comprendre comment vous souhaitez générer les vecteurs et quel est le niveau de contrôle dont vous avez besoin sur ceux-ci. Si vous recherchez la simplicité, le champ de texte sémantique permet une recherche sémantique automatique et évolutive, ce qui le rend idéal pour de nombreux cas d'utilisation initiaux. Lorsqu'un contrôle plus poussé, des performances plus fines ou une intégration avec des modèles personnalisés sont nécessaires, les champs de vecteurs denses et de vecteurs clairsemés offrent la flexibilité nécessaire.</p><p>Le type de champ idéal dépend de votre cas d'utilisation, de l'infrastructure disponible et de la maturité de votre pile d'apprentissage automatique. Plus important encore, Elastic offre les outils nécessaires pour construire des systèmes de recherche modernes et hautement adaptables.</p><h2>Références</h2><ul><li><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/semantic-text.html">Type de champ texte sémantique</a></p></li><li><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/sparse-vector.html">Type de champ vectoriel épars</a></p></li><li><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/dense-vector.html">Type de champ vectoriel dense</a></p></li><li><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-semantic-query.html">Requête sémantique</a></p></li><li><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-sparse-vector-query.html">Requête sur les vecteurs épars</a></p></li><li><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/knn-search.html">Recherche kNN</a></p></li><li><p><a href="https://www.elastic.co/search-labs/blog/semantic-search-simplified-semantic-text">Nouveau mappage semantic_text d'Elasticsearch : Simplifier la recherche sémantique</a></p></li><li><p><a href="https://www.elastic.co/search-labs/blog/sparse-vector-embedding">Comprendre les encastrements de vecteurs épars à l'aide de modèles ML entraînés</a></p></li></ul>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/mapping-embeddings-to-elasticsearch-field-types</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/mapping-embeddings-to-elasticsearch-field-types</guid>
    <category><![CDATA[Base vectorielle]]></category>
    <category><![CDATA[Mappings]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt72cd3c2601b22886/6a17083b0c4857259901a9dc/f98fdff837db55b466780c0bae672aa6f6c3a966-1200x628.png" length="0" type="image/png"/>
    <pubDate>Tue, 13 May 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Générer des filtres et des facettes à l'aide de la ML]]></title>
    <description><![CDATA[Exploration des avantages et des inconvénients de l'automatisation de la création de filtres et de facettes dans une expérience de recherche à l'aide de modèles ML par rapport à l'approche classique codée en dur.]]></description>
    <content:encoded><![CDATA[<p>Les filtres et les facettes sont des mécanismes utilisés pour affiner les résultats de la recherche et aider les utilisateurs à trouver plus rapidement le contenu ou les produits pertinents. Dans l'approche classique, les règles sont définies manuellement. Par exemple, dans un catalogue de films, des attributs tels que le genre sont prédéfinis pour être utilisés dans les filtres et les facettes. D'autre part, les modèles d'intelligence artificielle permettent d'extraire automatiquement de nouveaux attributs à partir des caractéristiques des films, ce qui rend le processus plus dynamique et plus personnalisé. Dans ce blog, nous explorons les avantages et les inconvénients de chaque méthode, en mettant en évidence leurs applications et leurs défis.</p><h2>Filtres vs facettes</h2><p>Avant de commencer, définissons ce que sont les filtres et les facettes. Les <strong>filtres</strong> sont des attributs prédéfinis utilisés pour restreindre un ensemble de résultats. Sur une place de marché, par exemple, des filtres sont disponibles avant même qu'une recherche ne soit effectuée. L'utilisateur peut sélectionner une catégorie, telle que <strong>"Jeux vidéo"</strong>, avant de rechercher <strong>"PS5"</strong>, ce qui permet d'affiner la recherche à un sous-ensemble plus spécifique plutôt qu'à l'ensemble de la base de données. Cela augmente considérablement les chances d'obtenir des résultats plus pertinents.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0a77b38aae238938/6a170b821949f72a52e7aa51/5ed8868fa5017d034e1273e35c884a5430afdf3c-1600x937.png" alt="Filtres" /><p>Les <strong>facettes</strong> fonctionnent de la même manière que les filtres, mais elles ne sont disponibles qu'une fois la recherche effectuée. En d'autres termes, la recherche renvoie des résultats et, sur la base de ceux-ci, une nouvelle liste d'options d'affinage est générée. Par exemple, lors de la recherche d'une console PS5, des aspects tels que la <strong>capacité de</strong> stockage, les <strong>frais d'expédition</strong> et la <strong>couleur</strong> peuvent être affichés pour aider les utilisateurs à choisir le produit idéal.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt166e356b80d423ef/6a170b840e2e494ca341a10f/c5633fcc5b6fbb916110faf32144d8d43572e33a-1600x937.png" alt="Facettes " /><p>Maintenant que nous avons défini les filtres et les facettes, examinons l'impact de l'approche classique et de l'approche basée sur l'apprentissage automatique sur leur mise en œuvre et leur utilisation. Chaque méthode présente des avantages et des inconvénients qui influencent l'efficacité de la recherche.</p><h2>Approche classique des filtres et des facettes</h2><p>Dans cette approche, les filtres et les facettes sont définis manuellement sur la base de règles prédéfinies. Cela signifie que les attributs disponibles pour affiner la recherche sont fixés et planifiés à l'avance, en tenant compte de la structure du catalogue et des besoins de l'utilisateur.</p><p>Par exemple, sur une place de marché, les catégories telles que "Électronique" ou "Mode" peuvent avoir des filtres spécifiques tels que la marque, le format et la fourchette de prix. Ces règles sont créées de manière statique, ce qui garantit la cohérence de l'expérience de recherche, mais nécessite des ajustements manuels lorsque de nouveaux produits ou de nouvelles catégories apparaissent.</p><p>Bien que cette approche permette de prévoir et de contrôler les filtres et les facettes affichés, elle peut s'avérer limitée lorsque de nouvelles tendances apparaissent et exigent un affinement dynamique.</p><p><strong>Pour :</strong></p><ul><li><p><strong>Prévisibilité et contrôle :</strong> Les filtres et les facettes étant définis manuellement, la gestion devient plus facile.</p></li><li><p><strong>Faible complexité :</strong> Il n'est pas nécessaire de former des modèles.</p></li><li><p><strong>Facilité de maintenance :</strong> Les règles étant prédéfinies, les ajustements et les corrections peuvent être effectués rapidement.</p></li></ul><p><strong>Cons :</strong></p><ul><li><p><strong>Réindexation nécessaire pour les nouveaux filtres :</strong> Chaque fois qu'un nouvel attribut doit être utilisé comme filtre, l'ensemble du jeu de données doit être réindexé pour s'assurer que les documents contiennent cette information.</p></li><li><p><strong>Absence d'adaptation dynamique :</strong> Les filtres sont statiques et ne s'adaptent pas automatiquement aux changements de comportement des utilisateurs.</p></li></ul><h3>Mise en œuvre des filtres/facettes - Approche classique</h3><p>Dans <strong>Dev Tools, Kibana</strong>, nous allons créer une démonstration de filtres/facettes en utilisant l'<strong>approche classique.</strong></p><p>Tout d'abord, nous définissons la correspondance pour structurer l'index :</p>PUT videogames
{
  "mappings": {
    "properties": {
      "name": { "type": "text" },
      "brand": { "type": "keyword" },
      "storage": { "type": "keyword" },
      "price": { "type": "float" },
      "description": { "type": "text" }
    }
  }
}<p>Les champs <strong>marque</strong> et <strong>stockage</strong> sont définis comme des <strong>mots-clés</strong>, ce qui permet de les utiliser directement dans les agrégations<strong>(facettes)</strong>. Le champ <strong>prix</strong> est de type <strong>flottant</strong>, ce qui permet de créer des <strong>fourchettes de prix</strong>.</p><p>L'étape suivante consiste à indexer les données relatives aux produits :</p>POST videogames/_bulk
{ "index": { "_id": 1 } }
{ "name": "Play Station 5", "brand": "Sony", "storage": "1TB", "price": 499.99, "description": "Stunning Gaming: Marvel at stunning graphics and experience the features of the new PS5. Breathtaking Immersion: Discover a deeper gaming experience with support for haptic feedback, adaptive triggers, and 3D Audio technology. Slim Design: With the PS5 Digital Edition, gamers get powerful gaming technology in a sleek, compact design. 1TB of Storage: Have your favorite games ready and waiting for you to play with 1TB of built-in SSD storage. Backward Compatibility and Game Boost: The PS5 console can play over 4,000 PS4 games. With Game Boost, you can even enjoy faster, smoother frame rates in some of the best PS4 console games." }
{ "index": { "_id": 2 } }
{ "name": "Xbox Series X", "brand": "Microsoft", "storage": "1TB", "price": 499.99, "description": "Fastest, most powerful Xbox console ever. Play thousands of titles: Every game looks and plays better on Xbox Series X. At the heart of Series X is the Xbox Velocity. Architecture, which combines a custom SSD and built-in software to significantly reduce load times in and out of game. Switch between multiple games in an instant with Quick Resume. Explore new worlds and experience the action like never before with an unparalleled 12 teraflops of graphics processing power. Enjoy 4K gaming at up to 120 frames per second, premium advanced 3D sound, and more. 4K at 120 FPS: requires compatible content and display X version - with disc drive" }
{ "index": { "_id": 3 } }
{ "name": "Nintendo Switch", "brand": "Nintendo", "storage": "512GB", "price": 299.99, "description": "SHARPER, VIBRANT VISUALS. The new 7-inch screen on the Nintendo Switch OLED takes your gaming to the next level: vibrant colors with sharp contrasts for every moment. INTEGRATED GAMEPLAY. Enjoy the console's many multiplayer modes and connect with other players. Online or locally, the fun on the Nintendo Switch is guaranteed. ENJOY IMMERSION FOR LONGER. In addition to delivering an unparalleled experience, thanks to its improved audio, the Nintendo Switch has a rechargeable battery while you play. From 4.5 hours to 9 hours of battery life. INCLUDES SUPER MARIO BROS. WONDER. Transform your world with the phenomenal flowers in this new Mario game, full of amazing adventures, power-ups and new abilities. NINTENDO SWITCH ONLINE SUBSCRIPTION. Access online games, play with friends and enjoy the exclusive benefits of the Nintendo Switch Online subscription." }
{ "index": { "_id": 4 } }
{ "name": "Steam Deck", "brand": "Valve", "storage": "512GB", "price": 399.99, "description": "You can save games, apps, photos and videos without worrying about space. High-Level Performance: The 4-core processor and graphics ensure a dynamic experience and fast responses. High-Definition Images: Smooth transitions and sharp images provide complete immersion in the game. Wireless Connectivity: Wi-Fi technology allows you to play wherever you want, without wires or cables limiting your fun" }
{ "index": { "_id": 5 } }
{ "name": "Nintendo Switch Lite", "brand": "Nintendo", "storage": "512GB", "price": 299.99, "description": "MADE TO BE PORTABLE. Nintendo Switch Lite is designed specifically for portable gaming. The console lets you jump into your favorite games wherever you are. COMPACT AND LIGHTWEIGHT. With its sleek, lightweight design, this console is ready to hit the road wherever you are. COMPATIBLE GAMES. The Nintendo Switch Lite system plays the library of Nintendo Switch games that work in handheld mode. A WORLD OF COLOR TO CHOOSE FROM. Available in a variety of vibrant and unique colors, Nintendo Switch Lite lets you bring even more personality wherever you go." }<p>Retrouvons maintenant des facettes classiques en regroupant les résultats par marque, rangement et gamme de prix. Dans la requête, la taille:0 a été définie. Dans ce scénario, l'objectif est de récupérer uniquement les résultats de l'agrégation sans inclure les documents correspondant à la requête.</p>POST videogames/_search
{
  "size": 0,
  "aggs": {
    "brands": {
      "terms": { "field": "brand" }
    },
    "storage_sizes": {
      "terms": { "field": "storage" }
    },
    "price_ranges": {
      "range": {
        "field": "price",
        "ranges": [
          { "to": 300 },   
          { "from": 300, "to": 500 },  
          { "from": 500 }  
        ]
      }
    }
  }
}<p>La réponse comprendra des comptes pour la <strong>marque</strong>, le <strong>stockage</strong> et le <strong>prix</strong>, ce qui permettra de créer des filtres et des facettes.</p>"aggregations": {
   "brands": {
     "doc_count_error_upper_bound": 0,
     "sum_other_doc_count": 0,
     "buckets": [
       {
         "key": "Microsoft",
         "doc_count": 1
       },
       {
         "key": "Nintendo",
         "doc_count": 1
       },
       {
         "key": "Sony",
         "doc_count": 1
       },
       {
         "key": "Valve",
         "doc_count": 1
       }
     ]
   },
   "storage_sizes": {
     "doc_count_error_upper_bound": 0,
     "sum_other_doc_count": 0,
     "buckets": [
       {
         "key": "1TB",
         "doc_count": 2
       },
       {
         "key": "512GB",
         "doc_count": 2
       }
     ]
   },
   "price_ranges": {
     "buckets": [
       {
         "key": "*-300.0",
         "to": 300,
         "doc_count": 1
       },
       {
         "key": "300.0-500.0",
         "from": 300,
         "to": 500,
         "doc_count": 3
       },
       {
         "key": "500.0-*",
         "from": 500,
         "doc_count": 0
       }
     ]
   }
 }<h2>Approche basée sur le Machine Learning et l’IA pour les filtres et les facettes</h2><p>Dans cette approche, les modèles d'apprentissage automatique (ML), y compris les techniques d'intelligence artificielle (IA), analysent les attributs des données pour générer des filtres et des facettes pertinents. Au lieu de s'appuyer sur des règles prédéfinies, la ML/AI exploite les caractéristiques des données indexées. Cela permet la découverte dynamique de nouvelles facettes et de nouveaux filtres.</p><p><strong>Pour :</strong></p><ul><li><p><strong>Mises à jour automatiques :</strong> Les nouveaux filtres et facettes sont générés automatiquement, sans qu'il soit nécessaire de procéder à des ajustements manuels.</p></li><li><p><strong>Découverte de nouveaux attributs :</strong> Il peut identifier des caractéristiques de données <strong>précédemment non prises en compte </strong>en tant que filtres, enrichissant ainsi l'expérience de recherche.</p></li><li><p><strong>Réduction des efforts manuels :</strong> L'équipe n'a pas besoin de définir et de mettre à jour en permanence les règles de filtrage, car l'IA apprend à partir des données disponibles.</p></li></ul><p><strong>Cons :</strong></p><ul><li><p><strong>Complexité de la maintenance :</strong> L'utilisation de modèles peut nécessiter une prévalidation pour garantir la cohérence des filtres générés.</p></li><li><p><strong>Nécessite une expertise en ML et en IA :</strong> La solution exige des professionnels qualifiés pour affiner et surveiller les performances du modèle.</p></li><li><p><strong>Risque de filtres non pertinents :</strong> Si le modèle n'est pas bien calibré, il peut générer des facettes qui ne sont pas utiles aux utilisateurs.</p></li><li><p><strong>Coût :</strong> L'utilisation de la ML et de l'IA peut nécessiter des services tiers, ce qui augmente les coûts opérationnels.</p></li></ul><p>Il convient de noter que même avec un modèle bien calibré et une invite bien rédigée, les facettes générées doivent toujours passer par une étape de révision. Cette validation peut être manuelle ou basée sur des règles de modération, garantissant que le contenu est approprié et sûr. Bien qu'il ne s'agisse pas nécessairement d'un inconvénient, il est important de s'assurer de la qualité et de l'adéquation des facettes avant de les mettre à la disposition des utilisateurs.</p><h3>Mise en œuvre de filtres/façades - Approche IA</h3><p>Dans cette démonstration, nous utiliserons un modèle d'intelligence artificielle pour analyser automatiquement les caractéristiques des produits et suggérer des attributs pertinents. Avec une invite bien structurée, nous extrayons des informations du catalogue et les transformons en filtres et facettes. Nous présentons ci-dessous chaque étape du processus.</p><p>Dans un premier temps, nous utiliserons l'<strong>API Inference</strong> pour enregistrer un point de terminaison en vue d'une intégration avec un service de ML. Vous trouverez ci-dessous un exemple d'intégration avec le <strong>service OpenAI</strong>.</p>PUT _inference/completion/generate_filter_ia
{
   "service": "openai",
   "service_settings": {
       "api_key": "your-key",
       "model_id": "gpt-4o-mini"
   }
}<p>Nous définissons maintenant le pipeline permettant d'exécuter l'invite et d'obtenir les nouveaux filtres générés par le modèle.</p>PUT /_ingest/pipeline/generate_filter_ai
{
   "processors": [
     {
       "script": {
         "source": """ctx.prompt = "You are an expert in data organization for search and product categorization. Your task is to analyze the following product and identify the best dynamic facets that can be used in an e-commerce search experience. Product: " + ctx.name + "description: " + ctx.description + "Instructions: - Analyze the product name and description. - Extract only the dynamic facets (technological features or product characteristics that can be inferred from the description, try to create max 3 facets by characteristics found). Put the values into an array. Using key and value, e.g. dynamic_facets: [{ \"name\": \"Gaming Experience\", \"value\": \"Haptic Feedback\" },{ \"name\": \"Gaming Experience\", \"value\": \"Adaptive Triggers\" } - Return only a JSON."
         """
       }
     },
     {
       "inference": {
         "model_id": "generate_filter_ia",
         "input_output": {
           "input_field": "prompt",
           "output_field": "result"
         }
       }
     },
     {
       "gsub": {
         "field": "result",
         "pattern": "```json",
         "replacement": ""
       }
     },
     {
       "json" : {
         "field" : "result",
         "strict_json_parsing": false,
         "add_to_root" : true
       }
     },
     {
       "remove": {
         "field": "result"
       }
     },
     {
       "remove": {
         "field": "prompt"
       }
     }
   ]
}<p>Lancer une simulation de ce pipeline pour le produit "PlayStation 5", avec la description suivante :</p><p><em>Des jeux époustouflants : Admirez des graphismes époustouflants et découvrez les fonctionnalités de la nouvelle PS5.</em></p><p><em>Une immersion à couper le souffle : Découvrez une expérience de jeu plus profonde grâce à la prise en charge du retour haptique, des déclencheurs adaptatifs et de la technologie audio 3D.</em></p><p><em>Un design élancé : Avec la PS5 Digital Edition, les joueurs bénéficient d'une technologie de jeu puissante dans un design élégant et compact.</em></p><p><em>1 To de stockage : Vos jeux préférés sont prêts à être joués grâce à 1 To de stockage SSD intégré.</em></p><p><em>Rétrocompatibilité et boost de jeux : La console PS5 peut lire plus de 4 000 jeux PS4. Avec Game Boost, vous pouvez même profiter de taux de rafraîchissement plus rapides et plus fluides dans certains des meilleurs jeux de la console PS4.</em></p><p>Observons la sortie rapide générée par cette simulation.</p>{
 "docs": [
   {
     "doc": {
       "_index": "index",
       "_version": "-3",
       "_id": "1",
       "_source": {
         "name": "Play Station 5",
         "result": """```json
{
 "dynamic_facets": [
   { "name": "Storage Capacity", "value": "1TB SSD" },
   { "name": "Graphics Technology", "value": "Stunning Graphics" },
   { "name": "Audio Technology", "value": "3D Audio" }
 ]
}
```""",
         "description": "Stunning Gaming: Marvel at stunning graphics and experience the features of the new PS5. Breathtaking Immersion: Discover a deeper gaming experience with support for haptic feedback, adaptive triggers, and 3D Audio technology. Slim Design: With the PS5 Digital Edition, gamers get powerful gaming technology in a sleek, compact design. 1TB of Storage: Have your favorite games ready and waiting for you to play with 1TB of built-in SSD storage. Backward Compatibility and Game Boost: The PS5 console can play over 4,000 PS4 games. With Game Boost, you can even enjoy faster, smoother frame rates in some of the best PS4 console games.",
         "model_id": "generate_filter_ia",
         "prompt": """You are an expert in data organization for search and product categorization. Your task is to analyze the following product and identify the best dynamic facets that can be used in an e-commerce search experience. Product: Play Station 5description: Stunning Gaming: Marvel at stunning graphics and experience the features of the new PS5. Breathtaking Immersion: Discover a deeper gaming experience with support for haptic feedback, adaptive triggers, and 3D Audio technology. Slim Design: With the PS5 Digital Edition, gamers get powerful gaming technology in a sleek, compact design. 1TB of Storage: Have your favorite games ready and waiting for you to play with 1TB of built-in SSD storage. Backward Compatibility and Game Boost: The PS5 console can play over 4,000 PS4 games. With Game Boost, you can even enjoy faster, smoother frame rates in some of the best PS4 console games.Instructions: - Analyze the product name and description. - Extract only the dynamic facets (technological features or product characteristics that can be inferred from the description, try create max 3 facets by characteristics found). Put the values like arrays. Using key and value, e.g. dynamic_facets: [{ "name": "Gaming Experience", "value": "Haptic Feedback" },{ "name": "Gaming Experience", "value": "Adaptive Triggers" } - Return only a JSON."""
       },
       "_ingest": {
         "timestamp": "2025-03-19T22:14:32.0161803Z"
       }
     }
   }
 ]
}<p>Un nouveau champ, <strong>dynamic_facets</strong>, sera ajouté au nouvel index pour stocker les facettes générées par l'IA.</p>PUT videogames_1
{
 "mappings": {
   "properties": {
     "name": { "type": "text" },
     "brand": { "type": "keyword" },
     "storage": { "type": "keyword" },
     "price": { "type": "float" },
     "description": { "type": "text" },
     "dynamic_facets": { "type": "nested",
     "properties": { "name": { "type": "keyword" },
                     "value": { "type": "keyword" } } }
   }
 }
}<p>En utilisant l'<strong>API Reindex</strong>, nous allons réindexer l'index <strong>videogames</strong> en <strong>videogames_1</strong>, en appliquant le pipeline <strong>generate_filter_ai</strong> pendant le processus. Ce pipeline génère automatiquement des facettes dynamiques lors de l'indexation.</p>POST _reindex?wait_for_completion=false
{
 "source": {
   "index": "videogames"
 },
 "dest": {
   "index": "videogames_1",
   "pipeline": "generate_filter_ai"
 }
}<p>Nous allons maintenant lancer une recherche et obtenir les nouveaux filtres :</p>GET videogames_1/_search
{
 "size": 0,
 "query": {
   "match": {
     "name": "nintendo"
   }
 },
 "aggs": {
   "dynamic_facets": {
     "nested": {
       "path": "dynamic_facets"
     },
     "aggs": {
       "facets": {
         "terms": {
           "field": "dynamic_facets.name"
         },
         "aggs": {
           "facets": {
             "terms": {
               "field": "dynamic_facets.value"
             }
           }
         }
       }
     }
   }
 }
}<p>Résultats :</p>"aggregations": {
   "dynamic_facets": {
     "doc_count": 3,
     "facets": {
       "doc_count_error_upper_bound": 0,
       "sum_other_doc_count": 0,
       "buckets": [
         {
           "key": "Frame Rate",
           "doc_count": 1,
           "facets": {
             "doc_count_error_upper_bound": 0,
             "sum_other_doc_count": 0,
             "buckets": [
               {
                 "key": "120 FPS",
                 "doc_count": 1
               }
             ]
           }
         },
         {
           "key": "Gaming Resolution",
           "doc_count": 1,
           "facets": {
             "doc_count_error_upper_bound": 0,
             "sum_other_doc_count": 0,
             "buckets": [
               {
                 "key": "4K",
                 "doc_count": 1
               }
             ]
           }
         },
         {
           "key": "Graphics Processing Power",
           "doc_count": 1,
           "facets": {
             "doc_count_error_upper_bound": 0,
             "sum_other_doc_count": 0,
             "buckets": [
               {
                 "key": "12 Teraflops",
                 "doc_count": 1
               }
             ]
           }
         }
       ]
     }
   }
 }<p>Pour illustrer la mise en œuvre des facettes, nous présentons ci-dessous une interface simple :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb0d6aa40caf7a91a/6a170b86ab7f0839afdb9eb6/12b6d9d4f4d0985848d92841545fd22b7253ae6d-1600x1288.png" alt="la mise en œuvre des facettes" /><p>Le code de l'interface utilisateur présenté est <a href="https://gist.github.com/andreluiz1987/06d9ec1b381e942e9def0e969bd811a0">ici.</a></p><h2>Conclusion</h2><p>Les deux approches de la création de filtres et de facettes ont leurs avantages et leurs inconvénients. L'approche classique, basée sur des règles manuelles, permet de contrôler et de réduire les coûts, mais elle nécessite des mises à jour constantes et ne s'adapte pas de manière dynamique aux nouveaux produits ou aux nouvelles fonctionnalités.</p><p>D'autre part, l'approche basée sur l'IA et l'apprentissage automatique automatise l'extraction des facettes, ce qui rend la recherche plus flexible et permet de découvrir de nouveaux attributs sans intervention manuelle. Toutefois, cette approche peut être plus complexe à mettre en œuvre et à maintenir, et nécessite un étalonnage pour garantir des résultats cohérents.</p><p>Le choix entre l'approche classique et l'approche basée sur l'IA dépend des besoins et de la complexité de l'entreprise. Pour les scénarios plus simples, où les attributs des données sont stables et prévisibles, l'approche classique peut être plus efficace et plus facile à maintenir, en évitant les coûts inutiles liés à l'infrastructure et aux modèles d'IA. D'autre part, l'utilisation de la ML/AI pour extraire les facettes peut apporter une valeur ajoutée significative, en améliorant l'expérience de recherche et en rendant le filtrage plus intelligent.</p><p>L'important est d'évaluer si l'automatisation justifie l'investissement ou si une solution plus traditionnelle répond déjà efficacement aux besoins de l'entreprise.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/filters-facets-using-ml</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/filters-facets-using-ml</guid>
    <category><![CDATA[Pertinence]]></category>
    <category><![CDATA[Recherche ML]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4084864dcdaa25d3/6a170b880c485781f901aaa9/6f196643d573614fe5124705c7e4db9bfce004b0-1200x628.png" length="0" type="image/png"/>
    <pubDate>Thu, 03 Apr 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Utilisation des modèles Amazon Nova dans Elasticsearch]]></title>
    <description><![CDATA[Découvrez comment utiliser les modèles Amazon Nova dans Elasticsearch pour extraire automatiquement le sentiment, l'authenticité, les résumés et les mots-clés des avis produits dans Elasticsearch.]]></description>
    <content:encoded><![CDATA[<p>Dans cet article, nous aborderons la famille de modèles d'IA d'Amazon, Amazon Nova, et apprendrons à l'utiliser avec Elasticsearch.</p><h2>À propos d'Amazon Nova</h2><p>Amazon Nova est une famille de modèles d'intelligence artificielle d'Amazon, disponibles sur Amazon Bedrock et conçus pour offrir de hautes performances et un bon rapport coût-efficacité. Ces modèles fonctionnent avec des entrées texte, image et vidéo, génèrent des sorties textuelles et sont optimisés pour répondre à différents besoins en termes de précision, de vitesse et de coût.</p><h3>Principaux modèles de l'Amazon Nova</h3><ul><li><p>Amazon Nova Micro : Axé exclusivement sur le texte, ce modèle rapide et économique est idéal pour la traduction, le raisonnement, la complétion de codes et la résolution de problèmes mathématiques. Sa production dépasse les 200 jetons par seconde, ce qui en fait un outil idéal pour les applications nécessitant des réponses instantanées.</p></li><li><p>Amazon Nova Lite : un modèle multimodal économique capable de traiter rapidement des images, des vidéos et du texte. Il se distingue par sa rapidité et sa précision, et convient plus particulièrement aux applications interactives et à fort volume où le coût est un facteur déterminant.</p></li><li><p>Amazon Nova Pro : L'option la plus avancée, combinant haute précision, vitesse et rentabilité. Idéal pour les tâches complexes telles que le résumé de vidéos, les questions et réponses, le développement de logiciels et les agents d'intelligence artificielle. Les avis d'experts attestent de son excellence en matière de compréhension textuelle et visuelle, ainsi que de sa capacité à suivre des instructions et à exécuter des flux de travail automatisés.</p></li></ul><p>Les modèles Amazon Nova sont adaptés à une variété d'applications, de la création de contenu et de l'analyse de données au développement de logiciels et à l'automatisation des processus alimentés par l'IA.</p><p>Ci-dessous, nous allons montrer comment utiliser les modèles Amazon Nova en conjonction avec Elasticsearch pour l'analyse automatisée des avis sur les produits.</p><p>Ce que nous ferons :</p><ol><li><p>Créer un point de terminaison via Inference API, intégrant Amazon Bedrock avec Elasticsearch.</p></li><li><p>Créer un pipeline à l'aide du processeur d'inférence, qui fera des appels au point d'extrémité de l'API d'inférence.</p></li><li><p>Indexer les avis sur les produits et générer automatiquement une analyse des avis à l'aide du pipeline.</p></li><li><p>Analyser les résultats de l'intégration.</p></li></ol><h2>Création d'un point de terminaison dans l'API d'inférence avec Amazon Nova Lite</h2><p>Tout d'abord, nous configurons l'API Inference pour intégrer Amazon Bedrock à Elasticsearch. Nous définissons Amazon Nova Lite, id <strong>amazon.nova-lite-v1:0,</strong> comme le modèle à utiliser, car il offre un équilibre entre la vitesse, la précision et le coût.</p><p><strong>Remarque :</strong> vous devez disposer d'informations d'identification valides pour utiliser Amazon Bedrock. Vous pouvez consulter la documentation relative à l'obtention des clés d'accès <a href="https://docs.aws.amazon.com/keyspaces/latest/devguide/create.keypair.html">ici :</a></p>PUT _inference/completion/bedrock_completion_amazon_nova-lite
{
   "service": "amazonbedrock",
   "service_settings": {
       "access_key": "#access_key#",
       "secret_key": "#secret_key#",
       "region": "us-east-1",
       "provider": "amazontitan",
       "model": "amazon.nova-lite-v1:0"
   }
}<h2>Création du pipeline d'analyse de l'examen</h2><p>Nous allons maintenant créer un pipeline de traitement qui utilisera le processeur d'inférence pour exécuter une invite d'analyse de révision. Cette invite enverra les données d'évaluation à Amazon Nova Lite, qui les exécutera :</p><ul><li><p>Classification du sentiment (positif, négatif ou neutre).</p></li><li><p>Résumé de l'examen.</p></li><li><p>Génération de mots-clés.</p></li><li><p>Mesure de l'authenticité (authentique | suspecte | générique).</p></li></ul>PUT /_ingest/pipeline/review_analyzer_ai
{
      "processors": [
      {
        "script": 
            {
            "source": """ctx.prompt = "Analyze the following product review and return a structured JSON. Task: - Summarize the review concisely. - Detect and classify the sentiment as positive, neutral, or negative.- Generate relevant tags (keywords) based on the review content and detected sentiment. - Evaluate the authenticity of the review (authentic, suspicious, or generic). Review: " + ctx.review + " Respond in JSON format with the following fields: \"review_analyze\": {\"sentiment\": \"&lt;positive | neutral | negative&gt;\", \"authenticity\": \"&lt;authentic | suspicious | generic&gt;\",\"summary\": \"&lt;short review summary&gt;\", \"keywords\": [\"&lt;keyword 1&gt;\", \"&lt;keyword 2&gt;\", \"...\"]}}}"
            """
            }
      },
      {
        "inference": {
          "model_id": "bedrock_completion_amazon_nova-lite",
          "input_output": {
            "input_field": "prompt",
            "output_field": "result"
          }
        }
      },
      {
        "gsub": {
          "field": "result",
          "pattern": "```json",
          "replacement": ""
        } 
      },
      {
        "json" : {
          "field" : "result",
          "strict_json_parsing": false,
          "add_to_root" : true
        }
      },
      {
        "remove": {
          "field": "result"
        }
      },
      {
        "remove": {
          "field": "prompt"
        }
      }
    ]
}<h2>Révision de l'indexation</h2><p>Nous indexons maintenant les avis sur les produits à l'aide de l'API Bulk. Le pipeline créé précédemment sera automatiquement appliqué, ajoutant l'analyse générée par le modèle Nova aux documents indexés.</p>POST bulk/
{ "index": { "_index" : "products", "_id": 1, "pipeline":"review_analyzer_ai" } }
{ "product": "Pampers Pants Premium Care Fralda", "review": "Best diaper ever! Great material, lots of cotton, without all that plastic. Doesn't leak! My baby is a boy and every diaper leaked around the waist, this model solved the problem. Even on a small baby it's worth the effort of putting on the short diaper. I put it on my baby at 9 pm and only take it off in the morning, without any leaks." }
{ "index": { "_index" : "products", "_id": 2, "pipeline":"review_analyzer_ai" } }
{ "product": "Portable Electric Body Massager", "review": "It broke in three months for no apparent reason, thank goodness I didn't review it before. I don't recommend buying it because it has a short lifespan." }
{ "index": { "_index" : "products", "_id": 3, "pipeline":"review_analyzer_ai" } }
{ "product": "Havit Fuxi-H3 Black Quad-Mode Wired and Wireless Gaming Headset", "review": "The sound is good for the price, but the connectivity is horrible. You always need to be playing audio, otherwise it loses connection (I work from home, and this is very annoying). Sometimes it loses connection and you have to turn it off and on again to get it back on. The microphone is very sensitive, so it loses connection frequently and you have to turn the headset off and on for the microphone to work again. The flexibility of the stem is useless, because if you move it, the microphone can turn off. Sometimes I need to use Linux and the headset simply doesn't work. It's light and comfortable, the sound is adequate, but the connectivity is terrible." }
{ "index": { "_index" : "products", "_id": 4, "pipeline":"review_analyzer_ai" } }
{ "product": "Air Fryer 4L Oil Free Fryer Mondial", "review": "For those looking for value for money, it's a good option, but the tray (which is underneath the perforated basket) is already peeling a lot. My mother has one just like it and said that hers is even rusting, in other words, the material is MUCH inferior. There's also something that bothers me, because it looks like a microwave, it doesn't fry evenly, it's weaker in the middle and stronger on the sides. Buy at your own risk." }<h2>Interrogation et analyse des résultats</h2><p>Enfin, nous lançons une requête pour voir comment le modèle Amazon Nova Lite analyse et classe les avis. En exécutant GET products/_search, nous obtenons les documents déjà enrichis des champs générés à partir du contenu de la revue.</p><p>Le modèle identifie le sentiment prédominant (positif, neutre ou négatif), génère des résumés concis, extrait les mots-clés pertinents et estime l'authenticité de chaque avis. Ces champs permettent de comprendre l'opinion du client sans avoir à lire le texte complet.</p><p>Pour interpréter les résultats, nous examinons</p><ul><li><p>Le sentiment, qui indique la perception globale du produit par le consommateur.</p></li><li><p>Le résumé, qui met en évidence les principaux points mentionnés.</p></li><li><p>Les mots-clés, qui peuvent être utilisés pour regrouper des avis similaires ou identifier des modèles de retour d'information.</p></li><li><p>L'authenticité, qui indique si l'avis semble digne de confiance. Cette fonction est utile pour la curation ou la modération.</p></li></ul>   "hits": [
      {
        "_index": "products",
        "_id": "1",
        "_score": 1,
        "_ignored": [
          "review.keyword"
        ],
        "_source": {
          "product": "Pampers Pants Premium Care Fralda",
          "model_id": "bedrock_completion_amazon_nova-lite",
          "review_analyze": {
            "summary": "The reviewer praises the diaper for its great material, high cotton content, and leak-proof design, especially highlighting its effectiveness for their baby.",
            "sentiment": "positive",
            "keywords": [
              "best diaper",
              "great material",
              "cotton",
              "no plastic",
              "leak-proof",
              "baby",
              "effective"
            ],
            "authenticity": "authentic"
          },
          "review": "Best diaper ever! Great material, lots of cotton, without all that plastic. Doesn't leak! My baby is a boy and every diaper leaked around the waist, this model solved the problem. Even on a small baby it's worth the effort of putting on the short diaper. I put it on my baby at 9 pm and only take it off in the morning, without any leaks."
        }
      },
      {
        "_index": "products",
        "_id": "2",
        "_score": 1,
        "_source": {
          "product": "Portable Electric Body Massager",
          "model_id": "bedrock_completion_amazon_nova-lite",
          "review_analyze": {
            "summary": "The product broke in three months for no apparent reason and the reviewer does not recommend it due to its short lifespan.",
            "sentiment": "negative",
            "keywords": [
              "broke",
              "short lifespan",
              "not recommend"
            ],
            "authenticity": "authentic"
          },
          "review": "It broke in three months for no apparent reason, thank goodness I didn't review it before. I don't recommend buying it because it has a short lifespan."
        }
      },
      {
        "_index": "products",
        "_id": "3",
        "_score": 1,
        "_ignored": [
          "review.keyword"
        ],
        "_source": {
          "product": "Havit Fuxi-H3 Black Quad-Mode Wired and Wireless Gaming Headset",
          "model_id": "bedrock_completion_amazon_nova-lite",
          "review_analyze": {
            "summary": "The headset has good sound quality for the price but suffers from poor connectivity, especially when using the microphone or moving the headset. It also has compatibility issues with Linux.",
            "sentiment": "negative",
            "keywords": [
              "sound",
              "connectivity",
              "microphone",
              "compatibility",
              "annoying",
              "turn off and on",
              "Linux",
              "flexible stem",
              "work from home"
            ],
            "authenticity": "authentic"
          },
          "review": "The sound is good for the price, but the connectivity is horrible. You always need to be playing audio, otherwise it loses connection (I work from home, and this is very annoying). Sometimes it loses connection and you have to turn it off and on again to get it back on. The microphone is very sensitive, so it loses connection frequently and you have to turn the headset off and on for the microphone to work again. The flexibility of the stem is useless, because if you move it, the microphone can turn off. Sometimes I need to use Linux and the headset simply doesn't work. It's light and comfortable, the sound is adequate, but the connectivity is terrible."
        }
      },
      {
        "_index": "products",
        "_id": "4",
        "_score": 1,
        "_ignored": [
          "review.keyword"
        ],
        "_source": {
          "product": "Air Fryer 4L Oil Free Fryer Mondial",
          "model_id": "bedrock_completion_amazon_nova-lite",
          "review_analyze": {
            "summary": "The product offers value for money but has issues with peeling, rusting, and uneven frying.",
            "sentiment": "negative",
            "keywords": [
              "value for money",
              "peeling",
              "rusting",
              "uneven frying",
              "weaker in the middle"
            ],
            "authenticity": "authentic"
          },
          "review": "For those looking for value for money, it's a good option, but the tray (which is underneath the perforated basket) is already peeling a lot. My mother has one just like it and said that hers is even rusting, in other words, the material is MUCH inferior. There's also something that bothers me, because it looks like a microwave, it doesn't fry evenly, it's weaker in the middle and stronger on the sides. Buy at your own risk."
        }
      }
    ]<h2>Conclusions</h2><p>L'intégration entre Amazon Nova Lite et Elasticsearch a démontré comment les modèles de langage peuvent transformer des avis bruts en informations structurées et précieuses. En traitant les avis par le biais d'un pipeline, nous avons pu extraire le sentiment, l'authenticité, les résumés et les mots-clés de manière automatique et cohérente.</p><p>Les résultats montrent que le modèle peut comprendre le contexte des avis, classer les opinions des utilisateurs et mettre en évidence les points les plus pertinents de chaque expérience. Cela crée un ensemble de données beaucoup plus riche qui peut être exploité pour améliorer les capacités de recherche.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/amazon-nova-models-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/amazon-nova-models-elasticsearch</guid>
    <category><![CDATA[IA]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdbbf13eb690294f1/6a17fddd6df73195190a115a/304713c48b568e17d0bb56b19edb28769f7801b3-721x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Wed, 02 Apr 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Comment automatiser les synonymes et le téléchargement à l'aide de notre API Synonymes ?]]></title>
    <description><![CDATA[Découvrez comment les LLM peuvent être utilisés pour identifier et générer automatiquement des synonymes, permettant ainsi aux termes d'être chargés de manière programmatique dans l'API de synonymes d'Elasticsearch.]]></description>
    <content:encoded><![CDATA[<p>L'amélioration de la qualité des résultats de recherche est essentielle pour offrir une expérience efficace aux utilisateurs. L'un des moyens d'optimiser les recherches consiste à étendre automatiquement les termes recherchés au moyen de synonymes. Cela permet d'interpréter les requêtes de manière plus large, de couvrir les variations linguistiques et donc d'améliorer la concordance des résultats.</p><p>Ce blog explore la manière dont les grands modèles de langage (LLM) peuvent être utilisés pour identifier et générer automatiquement des synonymes, ce qui permet de charger ces termes de manière programmatique dans l'API de synonymes d'Elasticsearch.</p><h2>Quand utiliser des synonymes ?</h2><p>L'utilisation de synonymes peut être une solution plus rapide et plus rentable que la recherche vectorielle. Sa mise en œuvre est plus simple car elle ne nécessite pas de connaissances approfondies en matière d'encastrements ni de processus complexe d'ingestion de vecteurs.</p><p>En outre, la consommation de ressources est plus faible, car la recherche vectorielle nécessite une plus grande capacité de stockage et de mémoire pour l'indexation de l'incorporation et la recherche.</p><p>Un autre aspect important est la régionalisation de la recherche. Grâce aux synonymes, il est possible d'adapter les termes à la langue et aux coutumes locales. Ceci est utile dans les situations où les embeddings peuvent ne pas correspondre à des expressions régionales ou à des termes spécifiques à un pays. Par exemple, certains mots ou acronymes peuvent avoir des significations différentes selon la région, mais sont naturellement traités comme des synonymes par les utilisateurs locaux. Au Brésil, cette situation est assez courante. "Abacaxi" et "ananás" sont le même fruit (ananas), mais le second terme est plus couramment utilisé dans certaines régions du nord-est. "De même, le pão francês", bien connu dans le Sud-Est, peut être appelé "pão careca" dans le Nord-Est.</p><h2>Comment utiliser les LLM pour générer des synonymes ?</h2><p>Pour obtenir automatiquement des synonymes, on peut utiliser des LLM, qui analysent le contexte d'un terme et suggèrent des variations appropriées. Cette approche permet d'étendre dynamiquement les synonymes, ce qui garantit une recherche plus large et plus précise sans dépendre d'un dictionnaire fixe.</p><p>Dans cette démonstration, nous utiliserons un LLM pour générer des synonymes pour des produits de commerce électronique. De nombreuses recherches ne donnent que peu ou pas de résultats en raison de variations dans les termes recherchés. Les synonymes permettent de résoudre ce problème. Par exemple, une recherche sur "smartphone" peut englober différents modèles de téléphones mobiles, ce qui permet aux utilisateurs de trouver les produits qu'ils recherchent.</p><h3>Produits requis</h3><p>Avant de commencer, nous devons configurer l'environnement et définir les dépendances nécessaires. Nous utiliserons la solution fournie par Elastic pour <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/run-elasticsearch-locally.html">exécuter Elasticsearch et Kibana localement dans Docker</a>. Le code sera écrit en Python, v3.9.6, avec les dépendances suivantes :</p>pip install openai==1.59.8 elasticsearch==8.15.1<h3>Création de l'index des produits</h3><p>Dans un premier temps, nous créerons un index des produits sans support de synonymes. Cela nous permettra de valider les requêtes et de les comparer à un index comprenant des synonymes.</p><p>Pour créer l'index, nous chargeons en masse un jeu de données de produits à l'aide de la commande suivante dans Kibana DevTools :</p>POST _bulk
{"index": {"_index": "products", "_id": 10001}}
{"category": "Electronics", "name": "iPhone 14 Pro"}
{"index": {"_index": "products", "_id": 10007}}
{"category": "Electronics", "name": "MacBook Pro 16-inch"}
{"index": {"_index": "products", "_id": 10013}}
{"category": "Electronics", "name": "Samsung Galaxy Tab S8"}
{"index": {"_index": "products", "_id": 10037}}
{"category": "Electronics", "name": "Apple Watch Series 8"}
{"index": {"_index": "products", "_id": 10049}}
{"category": "Electronics", "name": "Kindle Paperwhite"}
{"index": {"_index": "products", "_id": 10067}}
{"category": "Electronics", "name": "Samsung QLED 4K TV"}
{"index": {"_index": "products", "_id": 10073}}
{"category": "Electronics", "name": "HP Spectre x360 Laptop"}
{"index": {"_index": "products", "_id": 10079}}
{"category": "Electronics", "name": "Apple AirPods Pro"}
{"index": {"_index": "products", "_id": 10115}}
{"category": "Electronics", "name": "Amazon Echo Show 10"}
{"index": {"_index": "products", "_id": 10121}}
{"category": "Electronics", "name": "Apple iPad Air"}
{"index": {"_index": "products", "_id": 10127}}
{"category": "Electronics", "name": "Apple AirPods Max"}
{"index": {"_index": "products", "_id": 10151}}
{"category": "Electronics", "name": "Sony WH-1000XM4 Headphones"}
{"index": {"_index": "products", "_id": 10157}}
{"category": "Electronics", "name": "Google Pixel 6 Pro"}
{"index": {"_index": "products", "_id": 10163}}
{"category": "Electronics", "name": "Apple MacBook Air"}
{"index": {"_index": "products", "_id": 10181}}
{"category": "Electronics", "name": "Google Pixelbook Go"}
{"index": {"_index": "products", "_id": 10187}}
{"category": "Electronics", "name": "Sonos Beam Soundbar"}
{"index": {"_index": "products", "_id": 10199}}
{"category": "Electronics", "name": "Apple TV 4K"}
{"index": {"_index": "products", "_id": 10205}}
{"category": "Electronics", "name": "Samsung Galaxy Watch 4"}
{"index": {"_index": "products", "_id": 10211}}
{"category": "Electronics", "name": "Apple MacBook Pro 16-inch"}
{"index": {"_index": "products", "_id": 10223}}
{"category": "Electronics", "name": "Amazon Echo Dot (4th Gen)"}<h3>Générer des synonymes avec LLM</h3><p>Dans cette étape, nous utiliserons un LLM pour générer dynamiquement des synonymes. Pour ce faire, nous intégrerons l'API OpenAI, en définissant un modèle et une invite appropriés. Le LLM recevra la catégorie et le nom du produit, en veillant à ce que les synonymes soient pertinents du point de vue contextuel.</p>import json
import logging

from openai import OpenAI

def call_gpt(prompt, model):
    try:
        logging.info("generate synonyms by llm...")
        response = client.chat.completions.create(
            model=model,
            messages=[{"role": "user", "content": prompt}],
            temperature=0.7,
            max_tokens=1000
        )
        content = response.choices[0].message.content.strip()
        return content
    except Exception as e:
        logging.error(f"Failed to use model: {e}")
        return None

def generate_synonyms(category, products):
   synonyms = {}

   for product in products:
       prompt = f"You are an expert in generating synonyms for products. Based on the category and product name provided, generate synonyms or related terms. Follow these rules:\n"
       prompt += "1. **Format**: The first word should be the main item (part of the product name, excluding the brand), followed by up to 3 synonyms separated by commas.\n"
       prompt += "2. **Exclude the brand**: Do not include the brand name in the synonyms.\n"
       prompt += "3. **Maximum synonyms**: Generate a maximum of 3 synonyms per product.\n\n"
       prompt += f"The category is: **{category}**, and the product is: **{product}**. Return only the synonyms in the requested format, without additional explanations."

       response = call_gpt(prompt, "gpt-4o")
       synonyms[product] = response

   return synonyms<p>À partir de l'index des produits créé, nous récupérerons tous les articles de la catégorie "Electronics" et enverrons leurs noms au LLM. Le résultat attendu sera quelque chose comme :</p>{
  "iPhone 14 Pro": ["iPhone", "smartphone", "mobile", "handset"],
  "MacBook Pro 16-inch": ["MacBook", "Laptop", "Notebook", "Ultrabook"],
  "Samsung Galaxy Tab S8": ["Tab", "Tablet", "Slate", "Pad"],
  "Bose QuietComfort 35 Headphones": ["Headphones", "earphones", "earbuds", "headset"]
}<p>Avec les synonymes générés, nous pouvons les enregistrer dans Elasticsearch à l'aide de l'API Synonyms.</p><h3>Gestion des synonymes avec l'API Synonyms</h3><p>L'API Synonymes offre un moyen efficace de gérer les ensembles de synonymes directement dans le système. Chaque ensemble de synonymes se compose de règles de synonymie, selon lesquelles un groupe de mots est traité comme équivalent dans les recherches.</p><p><strong>Exemple de création d'un jeu de synonymes</strong></p>PUT _synonyms/my-synonyms-set
{
  "synonyms_set": [
    {
      "id": "rule-1",
      "synonyms": "hello, hi"
    },
    {
      "synonyms": "bye, goodbye"
    }
  ]
}<p>
Cela crée un ensemble appelé "my-synonyms-set," où "hello" et "hi" sont traités comme des équivalents, ainsi que "bye" et "goodbye."</p><h2>Mise en œuvre de la création de synonymes pour le catalogue de produits</h2><p>Vous trouverez ci-dessous la méthode permettant de construire un ensemble de synonymes et de l'insérer dans Elasticsearch. Les règles de synonymie sont générées sur la base du mappage des synonymes suggérés par le LLM. Chaque règle possède un identifiant, correspondant au nom du produit au format "slug", et la liste des synonymes calculée par le LLM.</p>import json
import logging

from elasticsearch import Elasticsearch
from slugify import slugify

es = Elasticsearch(
    "http://localhost:9200",
    api_key="your_api_key"
)

def mount_synonyms(results):
   synonyms_set = [{"id": slugify(product), "synonyms": synonyms} for product, synonyms in
                   results.items()]

   try:
       response = es.synonyms.put_synonym(id="products-synonyms-set",
                                                 synonyms_set=synonyms_set)

       logging.info(json.dumps(response.body, indent=4))
       return response.body
   except Exception as e:
       logging.error(f"Error create synonyms: {str(e)}")
       return None<p>Vous trouverez ci-dessous la demande de création d'un ensemble de synonymes :</p>{
   "synonyms_set":[
      {
         "id": "iphone-14-pro",
         "synonyms": "iPhone, smartphone, mobile, handset"
      },
      {
         "id": "macbook-pro-16-inch",
         "synonyms": "MacBook, Laptop, Notebook, Computer"
      },
      {
         "id": "samsung-galaxy-tab-s8",
         "synonyms": "Tablet, Slate, Pad, Device"
      },
      {
         "id": "garmin-forerunner-945",
         "synonyms": "Forerunner, smartwatch, fitness watch, GPS watch"
      },
      {
         "id": "bose-quietcomfort-35-headphones",
         "synonyms": "Headphones, Earphones, Headset, Cans"
      }
   ]
}<p>Une fois l'ensemble de synonymes créé dans le cluster, nous pouvons passer à l'étape suivante, qui consiste à créer un nouvel index avec prise en charge des synonymes à l'aide de l'ensemble défini.</p><p>Le code Python complet avec les synonymes générés par LLM et la création d'ensembles de synonymes définie par l'API Synonyms est ci-dessous :</p>import json
import logging

from elasticsearch import Elasticsearch
from openai import OpenAI
from slugify import slugify

logging.basicConfig(level=logging.INFO)

client = OpenAI(
   api_key="your-key",
)

es = Elasticsearch(
    "http://localhost:9200",
    api_key="your_api_key"
)


def call_gpt(prompt, model):
   try:
       logging.info("generate synonyms by llm...")
       response = client.chat.completions.create(
           model=model,
           messages=[{"role": "user", "content": prompt}],
           temperature=0.7,
           max_tokens=1000
       )
       content = response.choices[0].message.content.strip()
       return content
   except Exception as e:
       logging.error(f"Failed to use model: {e}")
       return None


def generate_synonyms(category, products):
   synonyms = {}

   for product in products:
       prompt = f"You are an expert in generating synonyms for products. Based on the category and product name provided, generate synonyms or related terms. Follow these rules:\n"
       prompt += "1. **Format**: The first word should be the main item (part of the product name, excluding the brand), followed by up to 3 synonyms separated by commas.\n"
       prompt += "2. **Exclude the brand**: Do not include the brand name in the synonyms.\n"
       prompt += "3. **Maximum synonyms**: Generate a maximum of 3 synonyms per product.\n\n"
       prompt += f"The category is: **{category}**, and the product is: **{product}**. Return only the synonyms in the requested format, without additional explanations."

       response = call_gpt(prompt, "gpt-4o")
       synonyms[product] = response

   return synonyms


def get_products(category):
   query = {
       "size": 50,
       "_source": ["name"],
       "query": {
           "bool": {
               "filter": [
                   {
                       "term": {
                           "category.keyword": category
                       }
                   }
               ]
           }
       }
   }
   response = es.search(index="products", body=query)

   if response["hits"]["total"]["value"] &gt; 0:
       product_names = [hit["_source"]["name"] for hit in response["hits"]["hits"]]
       return product_names
   else:
       return []


def mount_synonyms(results):
   synonyms_set = [{"id": slugify(product), "synonyms": synonyms} for product, synonyms in
                   results.items()]

   try:
       es_client = get_client_es()
       response = es_client.synonyms.put_synonym(id="products-synonyms-set",
                                                 synonyms_set=synonyms_set)

       logging.info(json.dumps(response.body, indent=4))
       return response.body
   except Exception as e:
       logging.error(f"Erro update synonyms: {str(e)}")
       return None


if __name__ == '__main__':
   category = "Electronics"
   products = get_products("Electronics")
   llm_synonyms = generate_synonyms(category, products)
   mount_synonyms(llm_synonyms)<h3>Création d'un index avec prise en charge des synonymes</h3><p>Un nouvel index sera créé dans lequel toutes les données de l'index <code>products</code> seront réindexées. Cet index utilisera le <code>synonyms_filter</code>, qui applique le <code>products-synonyms-set</code> créé précédemment.</p><p>Vous trouverez ci-dessous le mappage de l'index configuré pour utiliser les synonymes :</p>PUT products_02
{
  "settings": {
    "analysis": {
      "filter": {
        "synonyms_filter": {
          "type": "synonym",
          "synonyms_set": "products-synonyms-set",
          "updateable": true
        }
      },
      "analyzer": {
        "synonyms_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "synonyms_filter"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "ID": {
        "type": "long"
      },
      "category": {
        "type": "keyword"
      },
      "name": {
        "type": "text",
        "analyzer": "standard",
        "search_analyzer": "synonyms_analyzer"
      }
    }
  }
}<h3>Réindexation de l'index <code>products</code></h3><p>Nous allons maintenant utiliser l'<strong>API Reindex</strong> pour migrer les données de l'index <code>products</code> vers le nouvel index <code>products_02</code>, qui prend en charge les synonymes. Le code suivant a été exécuté dans Kibana DevTools :
</p>POST _reindex
{
  "source": {
    "index": "products"
  },
  "dest": {
    "index": "products_02"
  }
}<p>Après la migration, l'index <code>products_02</code> sera alimenté et prêt à valider les recherches à l'aide du jeu de synonymes configuré.</p><h3>Valider la recherche avec des synonymes</h3><p>Comparons les résultats de recherche entre les deux index. Nous allons exécuter la même requête sur les deux index et vérifier si les synonymes sont utilisés pour récupérer les résultats.</p><h4>Recherche dans l'index <code>products</code> (sans synonymes)</h4><p>Nous utiliserons Kibana pour effectuer des recherches et analyser les résultats. Dans le menu Analytics &gt; Discovery, nous allons créer une vue de données pour visualiser les données des index que nous avons créés.</p><p>Dans Discovery, cliquez sur Data View et définissez un nom et un modèle d'index. Pour l'index "<strong>products</strong>", nous utiliserons le modèle "<strong>products</strong>". Ensuite, nous répéterons le processus pour créer une nouvelle vue de données pour l'index "<strong>products_02</strong>", en utilisant le modèle "<strong>products_02".</strong></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte826fd932cfeb9df/6a17fdffec0f8912aa5a6841/3ad4a6891a3905e96532a312932fdf3a8216aec2-1600x599.png" alt="" /><p>Une fois les vues de données configurées, nous pouvons retourner sur Analytics &gt; Discovery et commencer les validations.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltba3729c60068e8a0/6a17fe01e9ea87ba2aa9c82a/422c4b2b51abae6580cad25085d1b8a365fc6b9e-1294x850.png" alt="" /><p>Ici, après avoir sélectionné les produits DataView et effectué une recherche pour le terme "tablet", nous n'obtenons aucun résultat, même si nous savons qu'il existe des produits tels que "Kindle Paperwhite" et "Apple iPad Air".</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2c6a383dd4cb0157/6a17fe02577262671d1bce0c/e4ae3a785fdd93f48d7c7d204185ded149126f2c-1600x862.png" alt="" /><h4>Recherche dans l'index <code>products_02</code> (support des synonymes)</h4><p>Lors de l'exécution de la même requête sur la vue de données "<strong>products_synonyms</strong>", qui prend en charge les synonymes, les produits ont été récupérés avec succès. Cela prouve que le jeu de synonymes configuré fonctionne correctement, en garantissant que les différentes variations des termes recherchés renvoient les résultats escomptés.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt986b4706e2f70014/6a17fe043e9e454edbba16d3/e609749c39e90d5c82fa846af6124679dd62bcb8-1600x526.png" alt="" /><p>Nous pouvons obtenir le même résultat en exécutant la même requête directement dans Kibana DevTools. Il suffit d'effectuer une recherche dans l'index products_02 à l'aide de l'API de recherche Elasticsearch :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltbe829a3c4d7aac60/6a17fe05e8fbce03d73a1bd7/504d0d1f96dcfbceb309063dc0716bcee64ad2f8-1600x870.png" alt="" /><h2>Conclusion</h2><p>La mise en œuvre de synonymes dans Elasticsearch a permis d'améliorer la précision et la couverture des recherches dans les catalogues de produits. Le principal facteur de différenciation était l'utilisation d'un <strong>LLM</strong>, qui générait des synonymes automatiquement et en fonction du contexte, éliminant ainsi le besoin de listes prédéfinies. Le modèle a analysé les noms et les catégories de produits, en veillant à ce que les synonymes soient pertinents pour le commerce électronique.</p><p>En outre, l'<strong>API Synonymes</strong> a simplifié la gestion des dictionnaires, en permettant de modifier dynamiquement les ensembles de synonymes. Grâce à cette approche, la recherche est devenue plus souple et plus adaptable aux différents types de requêtes des utilisateurs.</p><p>Ce processus peut être continuellement amélioré grâce à de nouvelles données et à des ajustements de modèles, ce qui garantit une expérience de recherche de plus en plus efficace.</p><h2>Références</h2><p><strong>Exécuter Elasticsearch localement</strong></p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/run-elasticsearch-locally.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/run-elasticsearch-locally.html</a></p><p><strong>Synonymes API</strong></p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/synonyms-apis.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/synonyms-apis.html</a></p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-synonyms-automate</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-synonyms-automate</guid>
    <category><![CDATA[Pertinence]]></category>
    <category><![CDATA[Les bases]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0f0247b9bc1d1ccd/6a17fe07ec0f891c745a6845/05a3cfeaa387561d5334ca3f1609035ddfff7481-1200x628.png" length="0" type="image/png"/>
    <pubDate>Thu, 27 Mar 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Comment ingérer des données dans Elasticsearch via Airbyte ?]]></title>
    <description><![CDATA[Utilisation d'Airbyte pour ingérer des données dans Elasticsearch. Nous aborderons les conditions préalables, la configuration d'Airbyte et l'intégration étape par étape.]]></description>
    <content:encoded><![CDATA[<p>Airbyte est un outil d'intégration de données qui vous permet de déplacer des informations de différentes sources vers différentes destinations de manière automatisée et évolutive. Il vous permet d'extraire des données à partir d'API, de bases de données et d'autres systèmes et de les charger dans des plateformes telles qu'Elasticsearch, qui offre des fonctions de recherche avancée et d'analyse efficace.</p><p>Dans cet article, nous expliquerons comment configurer Airbyte pour ingérer des données dans Elasticsearch, en abordant les concepts clés, les conditions préalables et l'intégration étape par étape.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt99eabff95c587c00/6a17e300e8fbce2d303a18a9/ea7af907dfd4c0b7e8673164467ee236623282d2-1360x802.png" alt="Configurer Airbyte pour ingérer des données dans Elasticsearch" /><h2>Concepts fondamentaux de l'airbyte</h2><p>L'utilisation d'Airbyte repose sur plusieurs concepts essentiels. Nous en présentons ci-dessous les principales :</p><ul><li><p>Sources : Définit l'origine des données qui seront extraites.</p></li><li><p>Destinations : Définit l'endroit où les données seront envoyées et stockées.</p></li><li><p>Connexions : Configure la relation entre la source et la destination, y compris la fréquence de synchronisation.</p></li></ul><h2>Intégration d'Airbyte avec Elasticsearch</h2><p>Dans cette démonstration, nous allons réaliser une intégration où les données stockées dans un bucket S3 seront migrées vers un index Elasticsearch. Nous allons montrer comment configurer la source (S3) et la destination (Elasticsearch) dans Airbyte.</p><h3>Produits requis</h3><p>Pour suivre cette démonstration, les conditions suivantes doivent être remplies :</p><ol><li><p>Créez un godet dans AWS, où les fichiers JSON contenant les données seront stockés.</p></li><li><p><a href="https://docs.airbyte.com/using-airbyte/getting-started/oss-quickstart">Installez Airbyte localement</a> à l'aide de Docker.</p></li><li><p>Créer un cluster Elasticsearch dans Elastic Cloud pour stocker les données ingérées.</p></li></ol><p>Nous détaillons ci-dessous chacune de ces étapes.</p><h4>Installation d'Airbyte</h4><p>Airbyte peut être exécuté localement à l'aide de Docker ou dans le nuage, où des coûts sont associés à l'utilisation. Pour cette démonstration, nous utiliserons la version locale avec Docker.</p><p>L'installation peut prendre quelques minutes. Après avoir suivi les instructions d'installation, Airbyte sera disponible à l'adresse suivante : http://localhost:8000.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0f9149be887b5500/6a17e302abe0f2b1c6dfe956/66147b5121413ad9baecb10c6886288e917f7c09-1600x1102.png" alt="Installation d'Airbyte" /><p></p><p>Après s'être connecté, nous pouvons commencer à configurer l'intégration.</p><h4>Création du seau</h4><p>Dans cette étape, vous aurez besoin d'un compte AWS pour créer un seau S3. En outre, il est essentiel de définir les autorisations correctes en créant une politique et un utilisateur IAM pour permettre l'accès au seau.</p><p>Dans le seau, nous téléchargerons des fichiers JSON contenant différents enregistrements de journaux, qui seront ensuite migrés vers Elasticsearch. Les fichiers journaux ont ce contenu :</p>{
   "timestamp": "2025-02-15T14:00:12Z",
   "level": "INFO",
   "service": "data_pipeline",
   "message": "Pipeline execution started",
   "details": {
       "pipeline_id": "abc123",
       "source": "MySQL",
       "destination": "Elasticsearch"
   }
}<p>Vous trouverez ci-dessous les fichiers chargés dans le seau :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltbf769c5e9bdb5dfe/6a17e3043e9e45a360ba13f7/f3e7f5889002e3a804121a880d97f1d93044e2f7-1600x680.png" alt="Fichiers chargés dans le seau en Airbyte" /><h4>Configuration de l'Elastic Cloud</h4><p>Pour faciliter la démonstration, nous utiliserons Elastic Cloud. Si vous n'avez pas encore de compte, vous pouvez créer un compte d'essai gratuit ici : <a href="https://cloud.elastic.co/registration">Enregistrement Elastic Cloud</a>.</p><p>Après avoir configuré le déploiement dans Elastic Cloud, vous devrez obtenir :</p><ul><li><p>L'URL du serveur Elasticsearch.</p></li><li><p>Un utilisateur pour accéder à Elasticsearch.</p></li></ul><p>Pour obtenir l'URL, allez sur Deployments &gt; My deployment, dans application, trouvez Elasticsearch et cliquez sur 'Copy endpoint'.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltddfaaf863168e2bb/6a17e305faa913e29793c7e4/2e38c0bfb2cea83d9ef90dba0e673559fe358199-1368x1056.png" alt="Configuration de l'Elastic Cloud" /><p>Pour créer l'utilisateur, suivez les étapes ci-dessous :</p><ol><li><p>Accès à Kibana &gt; Gestion de la pile &gt; Utilisateurs.</p></li><li><p>Créer un nouvel utilisateur avec le rôle de superutilisateur.</p></li><li><p>Remplissez les champs pour créer l'utilisateur.</p></li></ol><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltca15b0d3084f4c67/6a17e3073e9e4507e2ba13fb/54d098805087a2d60772475cbb31784083a38c25-1600x1026.png" alt="Création d'utilisateurs dans Elastic Cloud" /><p>Maintenant que tout est en place, nous pouvons commencer à configurer les connecteurs dans Airbyte.</p><h3>Configuration du connecteur source</h3><p>Dans cette étape, nous allons créer le connecteur source pour S3. Pour ce faire, nous accédons à l'interface Airbyte et sélectionnons l'option Source dans le menu. Ensuite, nous rechercherons le connecteur S3. Nous détaillons ci-dessous les étapes nécessaires à la configuration du connecteur :</p><ol><li><p>Accédez à Airbyte et allez dans le menu Sources.</p></li><li><p>Rechercher et sélectionner le connecteur S3.</p></li><li><p>Configurez les paramètres suivants :</p><ol><li><p>Source Name (Nom de la source) : Définir un nom pour la source de données.</p></li><li><p>Méthode de livraison : Sélectionnez Replicate Records (recommandé pour les données structurées).</p></li><li><p>Format des données : Choisissez le format JSON.</p></li><li><p>Stream Name (Nom du flux) : Définir le nom de l'index dans Elasticsearch.</p></li><li><p>Bucket Name : Saisissez le nom du réservoir dans AWS.</p></li><li><p>Clé d'accès AWS et clé secrète AWS : Saisissez les informations d'accès.</p></li></ol></li></ol><p>Cliquez sur Set up source et attendez la validation.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdca1fb8d8f5d034f/6a17e30963baff75bc741bb2/f83566ab5ebad07ad9fd61dc20353ca5a95c8c92-1600x1099.png" alt="Attendre la validation pour l'ingestion des données Airbyte et Elasticsearch" /><h3>Connecteur de destination de la configuration</h3><p>Dans cette étape, nous allons configurer le connecteur de destination, qui sera Elasticsearch. Pour ce faire, nous accédons au menu et sélectionnons l'option Destination. Ensuite, nous rechercherons Elasticsearch et cliquerons sur le résultat obtenu. Nous allons maintenant procéder à la configuration de cette connexion :</p><ol><li><p>Accédez à Airbyte et allez dans le menu Destinations.</p></li><li><p>Recherchez et sélectionnez le connecteur Elasticsearch.</p></li><li><p>Configurez les paramètres suivants :</p><ol><li><p>Méthode d'authentification : Choisissez Nom d'utilisateur/Mot de passe.</p></li><li><p>Nom d'utilisateur et mot de passe : utilisez les informations d'identification créées dans Kibana.</p></li><li><p>Server Endpoint : Collez l'URL copiée depuis Elastic Cloud.</p></li></ol></li></ol><p>Cliquez sur <strong>Configurer la destination</strong> et attendez la validation.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt72056179d048e027/6a17e30b033c8d5d9d6bb115/f9246b54cc77e0589c0bf658ffc274fd28f766d5-1600x941.png" alt="Créer une destination dans Elastic Cloud pour l'ingestion de données Airbyte" /><h3>Création de la connexion source et de la connexion destination</h3><p>Une fois la source et la destination créées, la connexion entre elles sera créée, achevant ainsi la création de l'intégration. </p><p>Vous trouverez ci-dessous les instructions pour créer la connexion :</p><p>1. Dans le menu, allez dans Connexions et cliquez sur Créer une première connexion.</p><p>2. Dans l'écran suivant, vous pouvez sélectionner une source existante ou en créer une nouvelle. Comme nous avons déjà créé une source, nous allons sélectionner la source S3.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc7f1e01215a7a328/6a17e30c63baff53d7741bb6/14937ccb2686bbde7cb99ffe7e13f7f4e35d7a31-1600x393.png" alt="Sélectionner une source existante ou en créer une nouvelle dans Airbyte" /><p>3. L'étape suivante consiste à sélectionner la destination. Comme nous avons déjà créé le connecteur Elasticsearch, il sera sélectionné pour finaliser la configuration.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltece5c720f28eee00/6a17e30d505ac3dc68ad8aa3/d10962bc175f9ce0b2745ea913d739d3c40ba3b6-1600x431.png" alt="Sélectionner la destination dans Airbyte" /><p>Dans l'étape suivante, il sera nécessaire de définir le mode de synchronisation et le schéma qui sera utilisé. Étant donné que seul le schéma d'enregistrement a été créé, il s'agit de la seule option disponible pour la sélection.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7cbcccad9cfd5a8d/6a17e30f414c64d32d9450e9/d5d3a2e20038d17ef701822fe7ccc38d6e175c50-1600x805.png" alt="Définir le mode de synchronisation dans Airbyte" /><p>4. Nous allons passer à l'étape de la configuration de la connexion. Ici, nous pouvons définir le nom de la connexion et la fréquence d'exécution de l'intégration. La fréquence peut être configurée de trois manières :</p><ul><li><p><strong>Cron</strong>: Exécute les synchronisations en fonction de l'expression cron définie par l'utilisateur (par exemple 0 0 15 * * ?, à 15:00 tous les jours) ;</p></li><li><p><strong>Planifié</strong>: Exécute les synchronisations à l'intervalle de temps spécifié (par ex. toutes les 24 heures, toutes les 2 heures) ;</p></li><li><p><strong>Manuel</strong>: Exécuter les synchronisations manuellement.</p></li></ul><p>Pour cette démonstration, nous sélectionnerons l'option Manuel.</p><p>Enfin, en cliquant sur <strong>Établir la connexion</strong>, la connexion entre la source et la destination sera établie.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4f5fc0e51035b733/6a17e311af47b67ac8cddeff/1a0470f6dff341cb90e6ecfd8ae87a7d2243cbf4-1600x626.png" alt="Cliquer sur Établir la connexion dans Airbyte" /><h3>Synchronisation des données de S3 vers Elasticsearch</h3><p>Lorsque vous revenez à l'écran Connexions, vous pouvez voir la connexion qui a été créée. Pour exécuter le processus, il suffit de cliquer sur Sync. À partir de ce moment, la migration des données de S3 vers Elasticsearch commencera.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9b0ad7a7446f9d58/6a17e3121d1b83b4c593e3c3/c1ce54b129eafb2533b638e4df2b96f3a266ad62-1600x347.png" alt="Synchronisation des données de S3 vers Elasticsearch sur Airbyte" /><p>Si tout se passe bien, vous obtiendrez l'état de synchronisation.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt857cdad5bd7fe03f/6a17e313be608646e00046b9/6fe9d5826787066bd8bf0f5e17905df9f8d698e6-1600x361.png" alt="Synchronisation des statuts de S3 vers Elasticsearch dans Airbyte" /><h3>Visualisation des données dans Kibana</h3><p>Nous allons maintenant aller dans Kibana pour analyser les données et vérifier si elles ont été indexées correctement. Dans la section Kibana Discovery, nous allons créer une vue de données appelée logs. Ainsi, nous pourrons explorer les données existant uniquement dans l'index des journaux, qui a été créé après la synchronisation.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1bc137f7c04e50ee/6a17e3151480094f2eb486cf/6b6909647ac3187d0fee477cfd732741314f82cf-1600x566.png" alt="Visualiser les données dans Kibana : Airbyte et Elastic" /><p>Nous pouvons maintenant visualiser les données indexées et les analyser. De cette manière, nous avons validé l'ensemble du flux de migration en utilisant Airbyte, où nous avons chargé les données présentes dans le seau et les avons indexées dans Elasticsearch.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd8c0a36a83ee4bb1/6a17e317b1e1135ea679f20e/ca8e9b3d7f7112291af58acf514f4573b44037e8-1600x806.png" alt="Airbyte et Elastic : visualisez les données indexées et effectuez des analyses sur celles-ci dans Kibana" /><h2>Conclusion : Airbyte &amp; Intégration d'Elasticsearch</h2><p>Airbyte s'est avéré être un outil efficace pour l'intégration des données, nous permettant de connecter plusieurs sources et destinations de manière automatisée. Dans ce tutoriel, nous avons montré comment ingérer des données d'un bucket S3 vers un index Elasticsearch, en mettant en évidence les principales étapes du processus.</p><p>Cette approche facilite l'ingestion de grands volumes de données et permet des analyses au sein d'Elasticsearch, telles que des recherches complexes, des agrégations et des visualisations de données.</p><h2>Références</h2><p><strong>Démarrage rapide Airbyte :</strong></p><p><a href="https://docs.airbyte.com/using-airbyte/getting-started/oss-quickstart#part-1-install-abctl">https://docs.airbyte.com/using-airbyte/getting-started/oss-quickstart#part-1-install-abctl</a></p><p><strong>Concepts de base :</strong></p><p><a href="https://docs.airbyte.com/using-airbyte/core-concepts/">https://docs.airbyte.com/using-airbyte/core-concepts/</a></p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/airbyte-elasticsearch-ingest-data</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/airbyte-elasticsearch-ingest-data</guid>
    <category><![CDATA[Indexer des données]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5defe5e12935b233/6a17e318505ac3ed7fad8aa7/dce2bad9949006163af95ed05b5a1eacf5393dc7-1200x628.png" length="0" type="image/png"/>
    <pubDate>Fri, 14 Mar 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Comment ingérer des données dans Elasticsearch via LlamaIndex]]></title>
    <description><![CDATA[Une étape par étape sur la façon d'ingérer des données et de faire des recherches en utilisant RAG avec LlamaIndex.]]></description>
    <content:encoded><![CDATA[<p>Dans cet article, nous allons mettre en place un moteur de recherche pour les FAQ en utilisant LlamaIndex pour indexer les données. Elasticsearch servira de base de données vectorielle, permettant une recherche vectorielle, tandis que RAG (Retrieval-Augmented Generation) enrichira le contexte, fournissant des réponses plus précises.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte5895fbc057ffc1b/6a17f4cf3e9e45288bba15ef/7ac65a686bdd76c145e903f5c3110c62875a525f-972x501.png" alt="LlamaIndex &amp; Elasticsearch : Ingestion de documents et construction d'une recherche de FAQ" /><h2>Qu'est-ce que le LlamaIndex ?</h2><p>LlamaIndex est un cadre qui facilite la création d'agents et de flux de travail alimentés par de grands modèles linguistiques (LLM) pour interagir avec des données spécifiques ou privées. Il permet l'intégration de données provenant de diverses sources (API, PDF, bases de données) avec les LLM, permettant des tâches telles que la recherche, l'extraction d'informations et la génération de réponses contextualisées.</p><p><strong>Concepts clés :</strong></p><ul><li><p>Agents : Assistants intelligents qui utilisent des LLM pour effectuer des tâches, allant de simples réponses à des actions complexes.</p></li><li><p>Flux de travail : Processus en plusieurs étapes qui combinent des agents, des connecteurs de données et des outils pour des tâches avancées.</p></li><li><p>Augmentation du contexte : Une technique qui enrichit le LLM avec des données externes, en surmontant ses limites de formation.</p></li></ul><p>Intégration de<strong>LlamaIndex</strong> <strong>avec Elasticsearch :</strong></p><p>Elasticsearch peut être utilisé de différentes manières avec LlamaIndex :</p><ul><li><p>Source de données : Utilisez le lecteur Elasticsearch pour extraire les documents.</p></li><li><p>Modèle d'encastrement : Encoder les données en vecteurs pour les recherches sémantiques.</p></li><li><p>Stockage vectoriel : Utilisez Elasticsearch comme référentiel pour la recherche de documents vectorisés.</p></li><li><p>Stockage avancé : Configurez des structures telles que des résumés de documents ou des graphes de connaissances.</p></li></ul><h2>Utiliser LlamaIndex et Elasticsearch pour construire une recherche de FAQ </h2><h3>Préparation des données</h3><p>Nous utiliserons la <a href="https://www.elastic.co/guide/en/cloud/current/ec-faq-getting-started.html">FAQ du service Elasticsearch</a> comme exemple. Chaque question a été extraite du site web et enregistrée dans un fichier texte individuel. Vous pouvez utiliser n'importe quelle approche pour organiser les données ; dans cet exemple, nous avons choisi d'enregistrer les fichiers localement.</p><p>Exemple de fichier :</p>File Name: what-is-elasticsearch-service.txt
Content: Elasticsearch Service is hosted and managed Elasticsearch and Kibana brought to you by the creators of Elasticsearch. Elasticsearch Service is part of Elastic Cloud and ships with features that you can only get from the company behind Elasticsearch, Kibana, Beats, and Logstash. Elasticsearch is a full text search engine that suits a range of uses, from search on websites to big data analytics and more.<p>Après avoir enregistré toutes les questions, le répertoire ressemblera à ceci :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt43467eb9c5579103/6a17f4d02f4a5cc60bfa8a62/1f367d57f2e650334671a2c03156ef4412c0c615-962x704.png" alt="" /><h3>Installation des dépendances</h3><p>Nous allons mettre en œuvre l'ingestion et la recherche en utilisant le langage Python, la version que j'ai utilisée étant la 3.9. Comme prérequis, il sera nécessaire d'installer les dépendances suivantes :</p>llama-index-vector-stores-elasticsearch
llama-index
openai<p>Elasticsearch et Kibana seront créés avec Docker, configurés via docker-compose.yml pour exécuter la version 8.16.2. Cela facilite la création de l'environnement local.</p>version: '3.8'
services:

 elasticsearch:
   image: docker.elastic.co/elasticsearch/elasticsearch:8.16.2
   container_name: elasticsearch-8.16.2
   environment:
     - node.name=elasticsearch
     - xpack.security.enabled=false
     - discovery.type=single-node
     - "ES_JAVA_OPTS=-Xms1024m -Xmx1024m"
   ports:
     - 9200:9200
   networks:
     - shared_network

 kibana:
   image: docker.elastic.co/kibana/kibana:8.16.2
   container_name: kibana-8.16.2
   restart: always
   environment:
     - ELASTICSEARCH_URL=http://elasticsearch:9200
   ports:
     - 5601:5601
   depends_on:
     - elasticsearch
   networks:
     - shared_network

networks:
 shared_network:<h3>L'ingestion de documents à l'aide de LlamaIndex</h3><p>Les documents seront indexés dans Elasticsearch à l'aide de LlamaIndex. Tout d'abord, nous chargeons les fichiers avec <strong>SimpleDirectoryReader</strong>, qui permet de charger des fichiers à partir d'un répertoire local. Après avoir chargé les documents, nous les indexons à l'aide du <strong>VectorStoreIndex</strong>.</p>documents = SimpleDirectoryReader("./faq").load_data()

storage_context = StorageContext.from_defaults(vector_store=es)
index = VectorStoreIndex(documents, storage_context=storage_context, embed_model=embed_model)<p>Les magasins de vecteurs de LlamaIndex sont responsables du stockage et de la gestion des incorporations de documents. LlamaIndex supporte différents types de Vector Stores, et dans ce cas, nous utiliserons Elasticsearch. Dans le StorageContext, nous configurons l'instance Elasticsearch. Le contexte étant local, aucun paramètre supplémentaire n'a été requis. Pour les configurations dans d'autres environnements, se référer à la documentation pour vérifier les paramètres nécessaires : <a href="https://docs.llamaindex.ai/en/stable/examples/vector_stores/ElasticsearchIndexDemo/#configuring-elasticsearchstore">ElasticsearchStore Configuration</a>.</p><p>Par défaut, LlamaIndex utilise le modèle OpenAI <strong>text-embedding-ada-002</strong> pour générer des embeddings. Toutefois, dans cet exemple, nous utiliserons le modèle <strong>text-embedding-3-small</strong>. Il est important de noter qu'une clé API OpenAI sera nécessaire pour utiliser le modèle.</p><p>Vous trouverez ci-dessous le code complet pour l'ingestion de documents.</p>import openai
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, StorageContext
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.vector_stores.elasticsearch import ElasticsearchStore

openai.api_key = os.environ["OPENAI_API_KEY"]

es = ElasticsearchStore(
   index_name="faq",
   es_url="http://localhost:9200"
)

def format_title(filename):
   filename_without_ext = filename.replace('.txt', '')
   text_with_spaces = filename_without_ext.replace('-', ' ')
   formatted_text = text_with_spaces.title()

   return formatted_text


embed_model = OpenAIEmbedding(model="text-embedding-3-small")

documents = SimpleDirectoryReader("./faq").load_data()

for doc in documents:
   doc.metadata['title'] = format_title(doc.metadata['file_name'])

storage_context = StorageContext.from_defaults(vector_store=es)
index = VectorStoreIndex(documents, storage_context=storage_context, embed_model=embed_model)<p>Après l'exécution, les documents seront indexés dans l'index <strong>faq</strong> comme indiqué ci-dessous :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt391ae1bfc1daefbf/6a17f4d22f4a5c9887fa8a66/d59b85ed1f57bf80e84d6cb0d6d722a2d12ae4c0-1600x745.png" alt="" /><h3>Recherche avec RAG</h3><p>Pour effectuer des recherches, nous configurons le client <strong>ElasticsearchStore</strong>, en définissant les champs <strong>index_name</strong> et <strong>es_url</strong> avec l'URL d'Elasticsearch. Dans <strong>retrieval_strategy</strong>, nous avons défini la <strong>stratégie AsyncDenseVectorStrategy</strong> pour les recherches vectorielles. D'autres stratégies, telles que <strong>AsyncBM25Strategy</strong> (recherche par mots-clés) et <strong>AsyncSparseVectorStrategy</strong> (vecteurs épars), sont également disponibles. Plus de détails peuvent être trouvés dans la <a href="https://docs.llamaindex.ai/en/stable/api_reference/storage/vector_store/elasticsearch/">documentation officielle</a>.</p>es = ElasticsearchStore(
   index_name="faq",
   es_url="http://localhost:9200",
   retrieval_strategy=AsyncDenseVectorStrategy(
   )
)<p>Ensuite, un objet <strong>VectorStoreIndex</strong> sera créé, où nous configurerons le <strong>vector_store</strong> en utilisant l'objet ElasticsearchStore. Avec la méthode <strong>as_retriever</strong>, nous recherchons les documents les plus pertinents pour une requête, en fixant le nombre de résultats renvoyés à 5 par le biais du paramètre <strong>similarity_top_k.</strong></p>   index = VectorStoreIndex.from_vector_store(vector_store=es)
   retriever = index.as_retriever(similarity_top_k=5)
   results = retriever.retrieve(query)<p>L'étape suivante est le GCR. Les résultats de la recherche vectorielle sont incorporés dans une invite formatée pour le LLM, permettant une réponse contextualisée basée sur les informations récupérées.</p><p>Dans le PromptTemplate, nous définissons le format de l'invite, qui inclut :</p><ul><li><p>Contexte ({context_str}) : documents récupérés par le chercheur.</p></li><li><p>Query ({query_str}) : la question de l'utilisateur.</p></li><li><p>Instructions : lignes directrices permettant au modèle de répondre en fonction du contexte, sans s'appuyer sur des connaissances externes.</p></li></ul>qa_prompt = PromptTemplate(
   "You are a helpful and knowledgeable assistant."
   "Your task is to answer the user's query based solely on the context provided below."
   "Do not use any prior knowledge or external information.\n"
   "---------------------\n"
   "Context:\n"
   "{context_str}\n"
   "---------------------\n"
   "Query: {query_str}\n"
   "Instructions:\n"
   "1. Carefully read and understand the context provided.\n"
   "2. If the context contains enough information to answer the query, provide a clear and concise answer.\n"
   "3. Do not make up or guess any information.\n"
   "Answer: "
)<p>Enfin, le LLM traite l'invite et renvoie une réponse précise et contextuelle.</p>llm = OpenAI(model="gpt-4o")
context_str = "\n\n".join([n.node.get_content() for n in results])
response = llm.complete(
   qa_prompt.format(context_str=context_str, query_str=query)
)

print("Answer:")
print(response)<p>Le code complet se trouve ci-dessous :</p>es = ElasticsearchStore(
   index_name="faq",
   es_url="http://localhost:9200",
   retrieval_strategy=AsyncDenseVectorStrategy(
   )
)


def print_results(results):
   for rank, result in enumerate(results, start=1):
       title = result.metadata.get("title")
       score = result.get_score()
       text = result.get_text()
       print(f"{rank}. title={title} \nscore={score} \ncontent={text}")


def search(query: str):
   index = VectorStoreIndex.from_vector_store(vector_store=es)

   retriever = index.as_retriever(similarity_top_k=10)
   results = retriever.retrieve(QueryBundle(query_str=query))
   print_results(results)

   qa_prompt = PromptTemplate(
       "You are a helpful and knowledgeable assistant."
       "Your task is to answer the user's query based solely on the context provided below."
       "Do not use any prior knowledge or external information.\n"
       "---------------------\n"
       "Context:\n"
       "{context_str}\n"
       "---------------------\n"
       "Query: {query_str}\n"
       "Instructions:\n"
       "1. Carefully read and understand the context provided.\n"
       "2. If the context contains enough information to answer the query, provide a clear and concise answer.\n"
       "3. Do not make up or guess any information.\n"
       "Answer: "
   )

   llm = OpenAI(model="gpt-4o")
   context_str = "\n\n".join([n.node.get_content() for n in results])
   response = llm.complete(
       qa_prompt.format(context_str=context_str, query_str=query)
   )

   print("Answer:")
   print(response)


question = "Elastic services are free?"
print(f"Question: {question}")
search(question)<p>Nous pouvons maintenant effectuer notre recherche, par exemple, "Les services Elastic sont gratuits ?" et obtenir une réponse contextualisée basée sur les données de la FAQ elle-même.</p>Question: Elastic services are free?
Answer:
Elastic services are not entirely free. However, there is a 14-day free trial available for exploring Elastic solutions. After the trial, access to features and services depends on the subscription level.<p>Les documents suivants ont été utilisés pour élaborer cette réponse :</p>1. title=Can I Try Elasticsearch Service For Free 
score=1.0 
content=Yes, sign up for a 14-day free trial. The trial starts the moment a cluster is created.
During the free trial period get access to a deployment to explore Elastic solutions for Enterprise Search, Observability, Security, or the latest version of the Elastic Stack.

2. title=Do You Offer Elastic S Commercial Products 
score=0.9941274512218439 
content=Yes, all Elasticsearch Service customers have access to basic authentication, role-based access control, and monitoring.
Elasticsearch Service Gold, Platinum and Enterprise customers get complete access to all the capabilities in X-Pack: Security, Alerting, Monitoring, Reporting, Graph Analysis &amp; Visualization. Contact us to learn more.

3. title=What Is Elasticsearch Service 
score=0.9896776845746571 
content=Elasticsearch Service is hosted and managed Elasticsearch and Kibana brought to you by the creators of Elasticsearch. Elasticsearch Service is part of Elastic Cloud and ships with features that you can only get from the company behind Elasticsearch, Kibana, Beats, and Logstash. Elasticsearch is a full text search engine that suits a range of uses, from search on websites to big data analytics and more.

4. title=Can I Run The Full Elastic Stack In Elasticsearch Service 
score=0.9880631561979476 
content=Many of the products that are part of the Elastic Stack are readily available in Elasticsearch Service, including Elasticsearch, Kibana, plugins, and features such as monitoring and security. Use other Elastic Stack products directly with Elasticsearch Service. For example, both Logstash and Beats can send their data to Elasticsearch Service. What is run is determined by the subscription level.

5. title=What Is The Difference Between Elasticsearch Service And The Amazon Elasticsearch Service 
score=0.9835054890793161 
content=Elasticsearch Service is the only hosted and managed Elasticsearch service built, managed, and supported by the company behind Elasticsearch, Kibana, Beats, and Logstash. With Elasticsearch Service, you always get the latest versions of the software. Our service is built on best practices and years of experience hosting and managing thousands of Elasticsearch clusters in the Cloud and on premise. For more information, check the following Amazon and Elastic Elasticsearch Service comparison page.
Please note that there is no formal partnership between Elastic and Amazon Web Services (AWS), and Elastic does not provide any support on the AWS Elasticsearch Service.<h2>Conclusion</h2><p>En utilisant LlamaIndex, nous avons démontré comment créer un système efficace de recherche de FAQ avec le support d'Elasticsearch comme base de données vectorielle. Les documents sont ingérés et indexés à l'aide d'enchâssements, ce qui permet d'effectuer des recherches vectorielles. Grâce à un PromptTemplate, les résultats de la recherche sont intégrés dans le contexte et envoyés au LLM, qui génère des réponses précises et contextualisées sur la base des documents récupérés.</p><p>Ce flux de travail intègre la recherche d'informations et la génération de réponses contextualisées afin de fournir des résultats précis et pertinents.</p><h2>Références</h2><p><a href="https://www.elastic.co/guide/en/cloud/current/ec-faq-getting-started.html">https://www.elastic.co/guide/en/cloud/current/ec-faq-getting-started.html</a></p><p><a href="https://docs.llamaindex.ai/en/stable/api_reference/readers/elasticsearch/">https://docs.llamaindex.ai/en/stable/api_reference/readers/elasticsearch/</a></p><p><a href="https://docs.llamaindex.ai/en/stable/module_guides/indexing/vector_store_index/">https://docs.llamaindex.ai/en/stable/module_guides/indexing/vector_store_index/</a></p><p><a href="https://docs.llamaindex.ai/en/stable/examples/query_engine/custom_query_engine/">https://docs.llamaindex.ai/en/stable/examples/query_engine/custom_query_engine/</a></p><p><a href="https://www.elastic.co/search-labs/integrations/llama-index">https://www.elastic.co/search-labs/integrations/llama-index</a></p><p></p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-llamaindex-ingest-data</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-llamaindex-ingest-data</guid>
    <category><![CDATA[Indexer des données]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf9f88afa92e90390/6a17f4d33e03d7987d4f2dd0/b8b760bfd8694df43fd74ba90ae5fc1edbe4ce76-1150x628.png" length="0" type="image/png"/>
    <pubDate>Fri, 28 Feb 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Recherche à facettes : Utiliser l'IA pour améliorer la portée et les résultats de la recherche]]></title>
    <description><![CDATA[Découvrez comment utiliser la recherche par facettes dans Elasticsearch pour restreindre rapidement les options au sein des catégories.]]></description>
    <content:encoded><![CDATA[<p>Dans cet article, nous verrons comment l'intelligence artificielle (IA), et plus particulièrement l'utilisation de modèles linguistiques avancés tels que GPT-4, peut contribuer à créer des facettes plus contextuelles, les rendant encore plus pertinentes et utiles pour les utilisateurs.</p><p>La recherche par facettes est un outil puissant dans les plateformes de commerce électronique. Il permet d'organiser et d'affiner les résultats de la recherche en fonction des caractéristiques des éléments affichés. Souvent confondues avec les filtres, les facettes fonctionnent différemment. Les filtres sont des attributs fixes, définis par des informations toujours présentes dans l'index, telles que la catégorie ou le format d'un produit. Les facettes, quant à elles, sont dynamiques et générées à partir des résultats renvoyés par la recherche exécutée.</p><p>Imaginez un catalogue de vêtements : des champs tels que "category" (par exemple, t-shirts, pantalons) ou "gender" (par exemple, homme, femme) sont des filtres qui permettent d'affiner les résultats. Les facettes, quant à elles, reflètent des caractéristiques spécifiques des produits apparaissant dans les résultats, telles que les couleurs communes, les tailles disponibles ou les matériaux. Cela permet une expérience de recherche plus adaptable et contextuelle.</p><p>Voici une image dans laquelle nous interagissons avec une facette et pouvons voir les résultats de la recherche filtrés par celle-ci.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc4ce8ca7e5b62ad7/6a17f8ba6864a4534bb68979/74d2159706ab7248ebe5efddc74c882f0693db71-600x420.gif" alt="Exemple de recherche à facettes" /><h2>Comment l'IA peut améliorer la génération de facettes</h2><p>L'intelligence artificielle est souvent associée à la recherche sémantique et aux enchâssements, mais qu'en est-il des facettes ? Comment l'IA peut-elle être exploitée pour rendre les facettes plus utiles et plus adaptées au contexte de chaque recherche ?</p><p>Une possibilité intéressante consiste à utiliser l'IA pour créer de nouvelles catégorisations qui vont au-delà des classifications traditionnelles de l'index. En analysant les caractéristiques spécifiques du contenu, ces nouvelles catégories peuvent fournir une contextualisation plus riche et plus précise, rendant les facettes plus pertinentes et mieux adaptées aux besoins des utilisateurs. Cela permet d'affiner les résultats de manière plus significative par rapport aux catégories de documents originales.</p><h2>Comment l'IA peut affiner les classifications de films pour de meilleures recherches</h2><p>Analysons les films suivants, tous classés actuellement dans le genre dramatique :</p><ul><li><p>Requiem for a Dream
Résumé : Les utopies induites par la drogue de quatre habitants de Coney Island sont brisées lorsque leurs addictions deviennent profondes.</p></li><li><p>American Beauty
CV : Un père de famille de banlieue, sexuellement frustré, traverse une crise de la quarantaine après s'être entiché de la meilleure amie de sa fille.</p></li><li><p>Good Will Hunting
CV : Will Hunting, concierge au M.I.T., est doué pour les mathématiques, mais a besoin de l'aide d'un psychologue pour trouver un sens à sa vie.</p></li></ul><p>Cette classification des genres ne rend pas compte des différences subtiles ou des contextes uniques de chaque film. En exploitant l'IA pour analyser les synopsis et les thèmes centraux, nous pouvons créer de nouvelles catégories qui reflètent mieux le véritable contexte de chaque film. Par exemple :</p><ul><li><p>Requiem for a Dream - Nouvelle catégorie : "Addiction et dépendance"</p></li><li><p>American Beauty - Nouvelle catégorie : "Crise de la quarantaine"</p></li><li><p>Good Will Hunting - Nouvelle catégorie : "Lutte intellectuelle"</p></li></ul><p>Ces nouvelles catégories rendent les recherches beaucoup plus précises tout en offrant aux utilisateurs des filtres plus significatifs pour affiner leurs résultats. Cette approche est particulièrement efficace lorsque les catégories d'origine sont trop génériques, ce qui permet aux utilisateurs de trouver plus facilement ce qu'ils recherchent.</p><h2>Créer de nouvelles catégories avec GPT-4 : exemple de recherche à facettes</h2><p>Dans cet exemple, nous montrerons comment un modèle d'IA peut être utilisé pour créer de nouvelles catégories de films qui sont plus précises et alignées sur le contexte de chaque œuvre. Pour démontrer ce processus, nous utiliserons le pipeline de simulation Elastic avec le service d'inférence OpenAI. Un pipeline comprenant plusieurs processeurs sera créé, dont le processeur de script, qui sera chargé de créer l'invite à exécuter dans le processeur d'inférence, capable de déterminer les nouvelles catégories. Les autres processeurs seront utilisés pour manipuler les données et les champs auxiliaires générés pendant l'exécution du pipeline. Il convient de mentionner que cette logique peut également être appliquée à d'autres outils ou modèles similaires.</p><p>Tout d'abord, nous devons créer le point de terminaison de l'inférence, où nous définissons le service comme OpenAI, le jeton requis pour accéder au service et le modèle. Dans cet exemple, j'utilise gpt-4o-mini. Pour plus de détails sur le service d'inférence OpenAI, cliquez <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/infer-service-openai.html">ici.</a></p>PUT _inference/completion/generate_topics_ia
{
    "service": "openai",
    "service_settings": {
        "api_key": "your-token",
        "model_id": "gpt-4o-mini"
    }
}<p>Le point final étant créé, nous sommes maintenant prêts à l'utiliser pour créer les nouvelles catégories. Vous trouverez ci-dessous un pipeline qui prend en charge l'ensemble du processus de manipulation des données des documents et de génération des messages. Je vais expliquer en détail la fonction de chaque processeur.</p><p>Le premier processeur sera chargé de construire l'invite. Il est très important de détailler clairement les instructions afin que l'IA puisse analyser et identifier correctement les sujets. Dans ce questionnaire, je demande 2 sujets basés sur l'analyse du titre, de la description et des genres des films.</p>{
        "script": {
          "source": """
            ctx.prompt = "You are an expert in semantic analysis and audiovisual content categorization. Your task is to generate only subcategories (max 2 topics) that describe specific aspects of movies based on their genres and descriptions. The output should be like: 'n1, n2, ...n'. Here is a movie info to analyze: Title: " + ctx.title  + "Genres: " + ctx.genres  + "Description: " + ctx.description;
          """
        }<p>Le pipeline suivant est le pipeline d'inférence, il recevra l'invite et l'enverra à notre point de terminaison <strong>generate_topics_ia</strong>. La réponse générée par le modèle sera stockée dans le champ résultat.</p>{
        "inference": {
          "model_id": "generate_topics_ia",
          "input_output": {
            "input_field": "prompt",
            "output_field": "result"
          }
        }
      }<p>Ensuite, nous avons trois processeurs utilisés pour manipuler la réponse et la placer dans le champ des sujets, en plus de supprimer les champs temporaires que j'ai créés.</p><p>En exécutant ce pipeline, nous obtiendrons les résultats ci-dessous :</p>{
  "docs": [
    {
      "doc": {
        "_index": "index",
        "_version": "-3",
        "_id": "1",
        "_source": {
          "description": "While Frodo and Sam edge closer to Mordor with the help of the shifty Gollum, the divided fellowship makes a stand against Sauron's new ally, Saruman, and his hordes of Isengard.",
          "model_id": "generate_topics_ia",
          "title": "The Lord of the Rings: The Fellowship of the Ring",
          "genres": [
            "Action",
            "Adventure",
            "Drama"
          ],
          "topics": [
            "Fantasy",
            "Quest"
          ]
        },
        "_ingest": {
          "timestamp": "2024-11-22T17:51:51.340010257Z"
        }
      }
    },
    {
      "doc": {
        "_index": "index",
        "_version": "-3",
        "_id": "2",
        "_source": {
          "description": "A team of explorers travel through a wormhole in space in an attempt to ensure humanity's survival.",
          "model_id": "generate_topics_ia",
          "title": "Interstellar",
          "genres": [
            "Adventure",
            "Drama",
            "Sci-Fi"
          ],
          "topics": [
            "space exploration",
            "human survival"
          ]
        },
        "_ingest": {
          "timestamp": "2024-11-22T17:51:51.340413173Z"
        }
      }
    },
    {
      "doc": {
        "_index": "index",
        "_version": "-3",
        "_id": "3",
        "_source": {
          "description": "An astronaut becomes stranded on Mars after his team assume him dead, and must rely on his ingenuity to find a way to signal to Earth that he is alive.",
          "model_id": "generate_topics_ia",
          "title": "The Martian",
          "genres": [
            "Adventure",
            "Drama",
            "Sci-Fi"
          ],
          "topics": [
            "survival",
            "ingenuity"
          ]
        },
        "_ingest": {
          "timestamp": "2024-11-22T17:51:51.340427965Z"
        }
      }
    }
  ]
}<p>Il est à noter que nous avons de nouvelles catégories qui sont plus en rapport avec le contexte des films, même si certains d'entre eux sont initialement du même genre.</p><p>Nous pouvons maintenant utiliser ces nouvelles catégories et les indexer avec le document. Ainsi, lors de la génération des facettes, en plus de la catégorie principale, nous avons des sous-catégories plus spécifiques qui sont alignées sur le contexte des films.</p><p>En outre, il est possible de vectoriser ces nouvelles catégories et de les utiliser dans des recherches vectorielles. Cela signifie que les nouvelles catégories ne servent pas seulement de filtres, mais qu'elles peuvent également être utilisées pour calculer les similitudes sémantiques avec les termes de recherche, ce qui augmente encore la pertinence des résultats présentés.</p><p>Pipeline complet :</p>POST /_ingest/pipeline/_simulate
{
  "pipeline": {
    "processors": [
      {
        "script": {
          "source": """
            ctx.prompt = "You are an expert in semantic analysis and audiovisual content categorization. Your task is to generate only subcategories (max 2 topics) that describe specific aspects of movies based on their genres and descriptions. The output should be like string: 'n1, n2m ...n'. Here is a movies info to analyze: Title: " + ctx.title  + "Genres: " + ctx.genres  + "Description: " + ctx.description;
          """
        }
      },
      {
        "inference": {
          "model_id": "generate_topics_ia",
          "input_output": {
            "input_field": "prompt",
            "output_field": "result"
          }
        }
      },
      {
        "split": {
          "field": "result",
          "target_field": "topics",
          "separator": ", "
        }
      },
      {
        "remove": {
          "field": "result"
        }
      },
      {
        "remove": {
          "field": "prompt"
        }
      }
    ]
  },
  "docs": [
    {
      "_index": "index",
      "_id": "1",
      "_source": {
        "title": "The Lord of the Rings: The Fellowship of the Ring",
        "description": "While Frodo and Sam edge closer to Mordor with the help of the shifty Gollum, the divided fellowship makes a stand against Sauron's new ally, Saruman, and his hordes of Isengard.",
        "genres": [
          "Action",
          "Adventure",
          "Drama"
        ]
      }
    },
    {
      "_index": "index",
      "_id": "2",
      "_source": {
        "title": "Interstellar",
        "description": "A team of explorers travel through a wormhole in space in an attempt to ensure humanity's survival.",
        "genres": [
          "Adventure", "Drama", "Sci-Fi"
        ]
      }
    },
    {
      "_index": "index",
      "_id": "3",
      "_source": {
        "title": "The Martian",
        "description": "An astronaut becomes stranded on Mars after his team assume him dead, and must rely on his ingenuity to find a way to signal to Earth that he is alive.",
        "genres": [
          "Adventure", "Drama", "Sci-Fi"
        ]
      }
    }
  ]
}<h2>Conclusion</h2><p>L'utilisation de l'IA pour améliorer les facettes peut transformer l'expérience de recherche en rendant les résultats plus spécifiques et contextuels. Contrairement aux catégories fixes, qui sont souvent larges, les catégories générées par l'IA peuvent mieux refléter le contexte. Par exemple, lors de la reclassification des films, nous pouvons saisir le contexte qui échappe aux catégories primaires, ce qui permet d'obtenir des regroupements beaucoup plus pertinents.</p><p>Ces nouvelles catégories peuvent être ajoutées à l'index non seulement pour améliorer les facettes, mais aussi pour permettre des recherches vectorielles. Il en résulte une expérience de recherche plus efficace, avec des filtres mieux adaptés au contexte.</p><h2>Références</h2><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/infer-service-openai.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/infer-service-openai.html</a></p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/simulate-pipeline-api.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/simulate-pipeline-api.html</a></p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/script-processor.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/script-processor.html</a></p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/faceted-search-examples-ai</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/faceted-search-examples-ai</guid>
    <category><![CDATA[IA]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd2838185214162c8/6a17f8bedbb4ff04affb58a5/25c9f9baa2326b5189ce0b1cc6240475781c755d-721x421.jpg" length="0" type="image/jpeg"/>
    <pubDate>Tue, 28 Jan 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Comment ingérer des données dans Elasticsearch via Apache Airflow]]></title>
    <description><![CDATA[Apprenez à ingérer des données dans Elasticsearch grâce à Apache Airflow.]]></description>
    <content:encoded><![CDATA[<h2>Qu'est-ce que le flux d'air Apache ?</h2><p>Apache Airflow est une plateforme conçue pour créer, planifier et contrôler les flux de travail. Il est utilisé pour orchestrer les processus ETL, les pipelines de données et d'autres flux de travail complexes, en offrant flexibilité et évolutivité. Son interface visuelle et ses capacités de suivi en temps réel rendent la gestion des pipelines plus accessible et plus efficace, vous permettant de suivre la progression et les résultats de vos exécutions. Ses quatre principaux piliers sont décrits ci-dessous :</p><ul><li><p><strong>Dynamique : </strong>Les pipelines sont définis en Python, ce qui permet de générer des flux de travail dynamiques et flexibles.</p></li><li><p><strong>Extensible :</strong> Airflow peut être intégré dans une variété d'environnements, des opérateurs personnalisés peuvent être créés et un code spécifique peut être exécuté selon les besoins.</p></li><li><p><strong>Élégant :</strong> Les pipelines sont rédigés de manière claire et explicite.</p></li><li><p><strong>Évolutif :</strong> Son architecture modulaire utilise une file d'attente de messages pour orchestrer un nombre arbitraire de travailleurs.</p></li></ul><p>Dans la pratique, Airflow peut être utilisé dans des scénarios tels que</p><ul><li><p><strong>Importation de données : </strong>Orchestrer l'ingestion quotidienne de données dans une base de données telle qu'Elasticsearch.</p></li><li><p><strong>Surveillance des journaux :</strong> Gérer la collecte et le traitement des fichiers journaux, qui sont ensuite analysés dans Elasticsearch pour identifier les erreurs ou les anomalies.</p></li><li><p><strong>Intégration de sources de données multiples :</strong> Combinez des informations provenant de différents systèmes (API, bases de données, fichiers) en une seule couche dans Elasticsearch, ce qui simplifie la recherche et la création de rapports.</p></li></ul><h2>Comprendre les DAG (Directed Acyclic Graphs) dans Airflow</h2><p>Dans Airflow, les flux de travail sont représentés par des DAG (Directed Acyclic Graphs). Un DAG est une structure qui définit la séquence d'exécution des tâches. Les principales caractéristiques des DAG sont les suivantes</p><ul><li><p><strong>Composition par tâches indépendantes :</strong> Chaque tâche représente une unité de travail et est conçue pour être exécutée de manière indépendante.</p></li><li><p><strong>Séquencement : </strong>L'ordre dans lequel les tâches sont exécutées est explicitement défini dans le DAG.</p></li><li><p><strong>Réutilisation :</strong> Les DAG sont conçus pour être exécutés de manière répétée, ce qui facilite l'automatisation des processus.</p></li></ul><h2>Composants du flux d'air</h2><p>L'écosystème Airflow est composé de plusieurs éléments qui fonctionnent ensemble pour orchestrer les tâches :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt25a23489b8725b3e/6a17dfcfe8fbceba103a1846/bacd83aff625026d62f023e0434baa5782a2761a-1046x628.png" alt="Composants principaux du flux d'air" /><ul><li><p><strong>Ordonnanceur :</strong> Responsable de la programmation des DAG et de l'envoi des tâches à exécuter par les travailleurs.</p></li><li><p><strong>Exécutant :</strong> Il gère l'exécution des tâches et les délègue aux travailleurs.</p></li><li><p><strong>Serveur Web :</strong> Fournit une interface graphique permettant d'interagir avec les DAG et les tâches.</p></li><li><p><strong>Dossier Dags :</strong> Dossier dans lequel nous stockons les DAGs écrits en Python.</p></li><li><p><strong>Métadonnées :</strong> Base de données qui sert de référentiel pour l'outil, utilisée par le planificateur et l'exécuteur pour stocker l'état d'exécution.</p></li></ul><h2>Apache Airflow et Elasticsearch</h2><p>Nous démontrerons l'utilisation d'Apache Airflow et d'Elasticsearch pour orchestrer des tâches et indexer les résultats dans Elasticsearch. L'objectif de cette démonstration est de créer un pipeline de tâches pour mettre à jour les enregistrements dans un index Elasticsearch. Cet index contient une base de données de films, où les utilisateurs peuvent évaluer et attribuer des notes. Imaginons un scénario avec des centaines d'évaluations quotidiennes, il est nécessaire de maintenir l'enregistrement des évaluations à jour. Pour ce faire, un DAG sera développé et exécuté quotidiennement, chargé de récupérer les nouvelles notations consolidées et de mettre à jour les enregistrements dans l'index.</p><p>Dans le flux DAG, nous aurons une tâche pour récupérer les classements, suivie d'une tâche pour valider les résultats. Si les données n'existent pas, le DAG sera dirigé vers une tâche d'échec. Sinon, les données seront indexées dans Elasticsearch. L'objectif est de mettre à jour le champ de classement des films dans un index en récupérant les classements par le biais d'une méthode avec le mécanisme responsable du calcul des scores.</p><h2>Utiliser Apache Airflow et Elasticsearch avec Docker</h2><p>Pour créer un environnement conteneurisé, nous utiliserons Apache Airflow avec Docker. Suivez les instructions du guide <a href="https://airflow.apache.org/docs/apache-airflow/stable/howto/docker-compose/index.html">"Running Airflow in Docker"</a> pour configurer Airflow de manière pratique.</p><p>En ce qui concerne Elasticsearch, j'utiliserai un cluster sur Elastic Cloud, mais si vous préférez, vous pouvez également configurer Elasticsearch avec Docker. Un index a déjà été créé, contenant un catalogue de films, avec les données des films indexées. Le champ "rating" de ces films sera mis à jour.</p><h2>Création du DAG</h2><p>Après l'installation via Docker, une structure de dossiers sera créée, y compris le dossier dags, où nous devons placer nos fichiers DAG pour qu'Airflow les reconnaisse.</p><p>Avant cela, nous devons nous assurer que les dépendances nécessaires sont installées. Voici les dépendances pour ce projet :</p>pip install apache-airflow apache-airflow-providers-elasticsearch<p>Nous allons créer le fichier <code>update_ratings_movies.py</code> et commencer à coder les tâches.</p><p>Maintenant, importons les bibliothèques nécessaires :</p>from airflow import DAG
from airflow.operators.python import PythonOperator, BranchPythonOperator
from airflow.providers.elasticsearch.hooks.elasticsearch import ElasticsearchPythonHook<p>Nous utiliserons <a href="https://airflow.apache.org/docs/apache-airflow-providers-elasticsearch/stable/hooks/elasticsearch_python_hook.html"><strong>ElasticsearchPythonHook</strong></a>, un composant qui simplifie l'intégration entre Airflow et un cluster Elasticsearch en abstrayant la connexion et l'utilisation d'API externes.</p><p>Nous définissons ensuite le DAG en précisant ses principaux arguments :</p><ul><li><p><strong><code>dag_id</code></strong>le nom du DAG.</p></li><li><p><strong><code>start_date</code></strong>: quand le DAG démarrera.</p></li><li><p><strong><code>schedule</code></strong>: définit la périodicité (quotidienne dans notre cas).</p></li><li><p><strong><code>doc_md</code></strong>La documentation : la documentation qui sera importée et affichée dans l'interface Airflow.</p></li></ul><h2>Définition des tâches</h2><p>Définissons maintenant les tâches du DAG. La première tâche consistera à récupérer les données relatives à la classification des films. Nous utiliserons l'<strong>opérateur Python</strong> avec l'adresse <code>task_id</code> fixée à <code>'get_movie_ratings'</code>. Le paramètre <code>python_callable</code> appellera la fonction responsable de la recherche des classements.</p>get_ratings_operator = PythonOperator(
   task_id='get_movie_ratings',
   python_callable=get_movie_ratings_task
)<p>Ensuite, nous devons vérifier si les résultats sont valables. Pour cela, nous utiliserons une conditionnelle avec un <strong>BranchPythonOperator</strong>. L'adresse <code>task_id</code> sera <code>'validate_result'</code>, et l'adresse <code>python_callable</code> appellera la fonction de validation. Le paramètre <code>op_args</code> sera utilisé pour transmettre le résultat de la tâche précédente, <code>'get_movie_ratings'</code>, à la fonction de validation.</p>validate_result = BranchPythonOperator(
   task_id='validate_result',
   python_callable=validate_result,
   op_args=["{{ task_instance.xcom_pull(task_ids='get_movie_ratings') }}"]
)<p>Si la validation est réussie, nous prendrons les données de la tâche <code>'get_movie_ratings'</code> et les indexerons dans Elasticsearch. Pour ce faire, nous allons créer une nouvelle tâche, <code>'index_movie_ratings'</code>, qui utilisera l'<strong>opérateur Python.</strong> Le paramètre <code>op_args</code> transmet les résultats de la tâche <code>'get_movie_ratings'</code> à la fonction d'indexation.</p>index_ratings_operator = PythonOperator(
   task_id='index_movie_ratings',
   python_callable=index_movie_ratings_task,
   op_args=["{{ task_instance.xcom_pull(task_ids='get_movie_ratings') }}"]
)<p>Si la validation indique un échec, le DAG passe à une tâche de notification d'échec. Dans cet exemple, nous nous contentons d'imprimer un message, mais dans un scénario réel, nous pourrions configurer des alertes pour signaler les défaillances.</p>failed_get_rating_operator = PythonOperator(
   task_id='failed_get_rating_operator',
   python_callable=lambda: print('Ratings were False, skipping indexing.')
)<p>Enfin, nous définissons les dépendances des tâches, en veillant à ce qu'elles s'exécutent dans le bon ordre :</p>get_ratings_operator &gt;&gt; validate_result &gt;&gt; [index_ratings_operator, failed_get_rating_operator]<p>Voici maintenant le code complet de notre DAG :</p>"""
DAG update Rating Movies
"""
import ast
import random

from airflow import DAG
from datetime import datetime

from airflow.operators.python import PythonOperator, BranchPythonOperator
from airflow.providers.elasticsearch.hooks.elasticsearch import ElasticsearchPythonHook


def index_movie_ratings_task(movies):
   es_hook = ElasticsearchPythonHook(hosts=None,
                                     es_conn_args={
                                         "cloud_id": "cloud_id"
                                         "api_key": "api-key"
                                     })
   es_client = es_hook.get_conn
   actions = []
   for movie in ast.literal_eval(movies):
       actions.append(
           {
               "update": {
                   "_id": movie["id"],
                   "_index": "movies"
               }
           }
       )
       actions.append(
           {
               "doc": {
                   "rating": movie["rating"]
               },
               "doc_as_upsert": True
           }
       )
   result = es_client.bulk(operations=actions)
   print(f"Ingestion completed.")
   print(result)
   return True


def get_movie_ratings_task():
   movies = [
       {"id": i, "rating": round(random.uniform(1, 10), 1)}
       for i in range(1, 100)
   ]
   return movies

def validate_result(result):
   if not result:
       return 'failed_get_rating_operator'
   else:
       return 'index_movie_ratings'


with DAG(
       dag_id="update_ratings_movies_2024",
       start_date=datetime(2024, 12, 29),
       schedule="@daily",
       doc_md=__doc__,
):
   get_ratings_operator = PythonOperator(
       task_id='get_movie_ratings',
       python_callable=get_movie_ratings_task
   )

   validate_result = BranchPythonOperator(
       task_id='validate_result',
       python_callable=validate_result,
       op_args=["{{ task_instance.xcom_pull(task_ids='get_movie_ratings') }}"],
       provide_context=True
   )

   index_ratings_operator = PythonOperator(
       task_id='index_movie_ratings',
       python_callable=index_movie_ratings_task,
       op_args=["{{ task_instance.xcom_pull(task_ids='get_movie_ratings') }}"]
   )

   failed_get_rating_operator = PythonOperator(
       task_id='failed_get_rating_operator',
       python_callable=lambda: print('Ratings were False, skipping indexing.')
   )

get_ratings_operator &gt;&gt; validate_result &gt;&gt; [index_ratings_operator, failed_get_rating_operator]<h2>Visualisation de l'exécution du DAG</h2><p>Dans l'interface Apache Airflow, nous pouvons visualiser l'exécution des DAGs. Il suffit d'aller sur l'onglet "DAGs" et de localiser le DAG que vous avez créé.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9c5de210a5a264ad/6a17dfd00b0bed0290dd34cf/905b9191c4e3191e8b5608174d4c555370bf25eb-1600x760.png" alt="Visualiser l'exécution des DAGs dans l'interface Apache Airflow avec Elasticsearch" /><p>Ci-dessous, nous pouvons visualiser les exécutions des tâches et leurs statuts respectifs. En sélectionnant une exécution pour une date spécifique, nous pouvons accéder aux journaux de chaque tâche. Notez que dans la tâche <strong><code>index_movie_ratings</code></strong>, nous pouvons voir les résultats de l'indexation dans l'index, et qu'elle s'est déroulée avec succès.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0beddf311a808d24/6a17dfd2033c8d76de6bb0ba/73c3f738d27500cf153377bedf1aa2b67a94a8c8-1600x648.png" alt="visualiser les exécutions des tâches et leurs statuts dans Apache Airflow avec Elasticsearch" /><p>Dans les autres onglets, il est possible d'accéder à des informations supplémentaires sur les tâches et le GDA, ce qui facilite l'analyse et la résolution des problèmes potentiels.</p><h2>Conclusion</h2><p>Dans cet article, nous avons montré comment intégrer Apache Airflow à Elasticsearch pour créer une solution d'ingestion de données. Nous avons montré comment configurer le DAG, définir les tâches responsables de la récupération, de la validation et de l'indexation des données des films, ainsi que contrôler et visualiser l'exécution de ces tâches dans l'interface Airflow.</p><p>Cette approche peut être facilement adaptée à différents types de données et de flux de travail, ce qui fait d'Airflow un outil utile pour orchestrer les pipelines de données dans divers scénarios.</p><h2>Références</h2><p>Apache AirFlow</p><p><a href="https://airflow.apache.org/">https://airflow.apache.org/</a></p><p>Installer Apache Airflow avec Docker</p><p><a href="https://airflow.apache.org/docs/apache-airflow/stable/howto/docker-compose/index.html">https://airflow.apache.org/docs/apache-airflow/stable/howto/docker-compose/index.html</a></p><p>Elasticsearch Python Hook</p><p><a href="https://airflow.apache.org/docs/apache-airflow-providers-elasticsearch/stable/hooks/elasticsearch_python_hook.html">https://airflow.apache.org/docs/apache-airflow-providers-elasticsearch/stable/hooks/elasticsearch_python_hook.html</a></p><p>Opérateur Python</p><p><a href="https://airflow.apache.org/docs/apache-airflow/stable/howto/operator/python.html">https://airflow.apache.org/docs/apache-airflow/stable/howto/operator/python.html</a></p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/apache-airflow-elasticsearch-ingest-data</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/apache-airflow-elasticsearch-ingest-data</guid>
    <category><![CDATA[Indexer des données]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt28475ace97d1d989/6a1704c9286714d6dd93e1ec/5d4b47ac5d2ba453fc19dcc15efa2aed5f55d88b-1440x1355.png" length="0" type="image/png"/>
    <pubDate>Fri, 17 Jan 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Comment ingérer des données dans Elasticsearch via Kafka ?]]></title>
    <description><![CDATA[Un guide pas à pas pour intégrer Apache Kafka avec Elasticsearch pour une ingestion, une indexation et une visualisation efficaces des données en utilisant Python, Docker Compose et Kafka Connect.]]></description>
    <content:encoded><![CDATA[<p>Dans cet article, nous montrons comment intégrer Apache Kafka avec Elasticsearch pour l'ingestion et l'indexation des données. Nous donnerons un aperçu de Kafka, de son concept de producteurs et de consommateurs, et nous créerons un index de logs où les messages seront reçus et indexés par Apache Kafka. Le projet est mis en œuvre en Python, et le code est disponible sur <a href="https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/elasticsearch-through-apache-kafka">GitHub</a>.</p><h3><strong>Produits requis</strong></h3><ul><li><p>Docker et Docker Compose : Assurez-vous que Docker et Docker Compose sont installés sur votre machine.</p></li><li><p>Python 3.x : Pour exécuter les scripts du producteur et du consommateur.</p></li></ul><h3><strong>Introduction à Apache Kafka</strong></h3><p>Apache Kafka est une plateforme de diffusion en continu distribuée qui permet une évolutivité et une disponibilité élevées, ainsi qu'une tolérance aux pannes. Dans Kafka, la gestion des données s'effectue par le biais des principaux composants :</p><ul><li><p><strong>Courtier</strong>: responsable du stockage et de la distribution des messages entre les producteurs et les consommateurs.</p></li><li><p><strong>Zookeeper</strong>: gère et coordonne les courtiers Kafka, en contrôlant l'état de la grappe, les chefs de partition et les informations sur les consommateurs.</p></li><li><p><strong>Sujets</strong>: canaux où les données sont publiées et stockées pour être consommées.</p></li><li><p><strong>Consommateurs et producteurs</strong>: tandis que les producteurs envoient des données aux thèmes, les consommateurs récupèrent ces données.</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4aae32304d7417f6/6a17f7be577262b47c1bcdac/89a37243baec48bbdfa85e3298fc91082322ed4e-1600x868.png" alt="Diagramme Apache Kafka" /><p>Ces composants fonctionnent ensemble pour former l'écosystème Kafka, qui fournit un cadre robuste pour la diffusion de données en continu.</p><h3><strong>Structure du projet</strong></h3><p>Pour comprendre le processus d'ingestion des données, nous l'avons divisé en plusieurs étapes :</p><ul><li><p><strong>Provisionnement de l'infrastructure</strong>: mise en place de l'environnement Docker pour prendre en charge Kafka, Elasticsearch et Kibana.</p></li><li><p><strong>Création du producteur</strong>: mise en œuvre du producteur Kafka, qui envoie des données au sujet des journaux.</p></li><li><p><strong>Création du consommateur</strong>: développement du consommateur Kafka pour lire et indexer les messages dans Elasticsearch.</p></li><li><p><strong>Validation de l'ingestion</strong>: vérification et validation des données envoyées et consommées.</p></li></ul><h3><strong>Configuration de l'infrastructure avec Docker Compose</strong></h3><p>Nous avons utilisé Docker Compose pour configurer et gérer les services nécessaires. Vous trouverez ci-dessous le code Docker Compose qui met en place chaque service nécessaire à l'intégration d'Apache Kafka, Elasticsearch et Kibana, en assurant un processus d'ingestion des données.</p>version: "3"

services:

  zookeeper:
    image: confluentinc/cp-zookeeper:latest
    container_name: zookeeper
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181

  kafka:
    image: confluentinc/cp-kafka:latest
    container_name: kafka
    depends_on:
      - zookeeper
    ports:
      - "9092:9092"
      - "9094:9094"
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST:${HOST_IP}:9092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1

  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.15.1
    container_name: elasticsearch-8.15.1
    environment:
      - node.name=elasticsearch
      - xpack.security.enabled=false
      - discovery.type=single-node
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    volumes:
      - ./elasticsearch:/usr/share/elasticsearch/data
    ports:
      - 9200:9200

  kibana:
    image: docker.elastic.co/kibana/kibana:8.15.1
    container_name: kibana-8.15.1
    ports:
      - 5601:5601
    environment:
      ELASTICSEARCH_URL: http://elasticsearch:9200
      ELASTICSEARCH_HOSTS: '["http://elasticsearch:9200"]'<p>Vous pouvez accéder au fichier directement depuis le repo <a href="https://github.com/andreluiz1987/elasticsearch-labs/tree/supporting-blog/elasticsearch-apache-kafka/supporting-blog-content/elasticsearch-through-apache-kafka">GitHub</a> d'Elasticsearch Labs.</p><h3><strong>Envoi de données avec le producteur Kafka</strong></h3><p>Le producteur est responsable de l'envoi des messages au sujet des journaux. L'envoi de messages par lots augmente l'efficacité de l'utilisation du réseau et permet d'optimiser les paramètres <code>batch_size</code> et <code>linger_ms</code>, qui contrôlent respectivement la quantité et la latence des lots. La configuration <code>acks='all'</code> garantit que les messages sont stockés durablement, ce qui est essentiel pour les données d'enregistrement importantes.</p>producer = KafkaProducer(
   bootstrap_servers=['localhost:9092'],  # Specifies the Kafka server to connect
   value_serializer=lambda x: json.dumps(x).encode('utf-8'),  # Serializes data as JSON and encodes it to UTF-8 before sending
   batch_size=16384,     # Sets the maximum batch size in bytes (here, 16 KB) for buffered messages before sending
   linger_ms=10,         # Sets the maximum delay (in milliseconds) before sending the batch
   acks='all'            # Specifies acknowledgment level; 'all' ensures message durability by waiting for all replicas to acknowledge
)


def generate_log_message():
   levels = ["INFO", "WARNING", "ERROR", "DEBUG"]
   messages = [
       "User login successful",
       "User login failed",
       "Database connection established",
       "Database connection failed",
       "Service started",
       "Service stopped",
       "Payment processed",
       "Payment failed"
   ]
   log_entry = {
       "level": random.choice(levels),
       "message": random.choice(messages),
       "timestamp": time.time()
   }
   return log_entry

def send_log_batches(topic, num_batches=5, batch_size=10):
   for i in range(num_batches):
       logger.info(f"Sending batch {i + 1}/{num_batches}")
       for  in range(batch_size):
           log_message = generate_log_message()
           producer.send(topic, value=log_message)
       producer.flush()


if __name__ == "__main__":
   topic = "logs"
   send_log_batches(topic)
   producer.close()<p>Lors du démarrage du producteur, les messages sont envoyés par lots au sujet, comme indiqué ci-dessous :</p>INFO:kafka.conn:Set configuration …
INFO:log_producer:Sending batch 1/5 
INFO:log_producer:Sending batch 2/5
INFO:log_producer:Sending batch 3/5
INFO:log_producer:Sending batch 4/5<h3><strong>Consommation et indexation des données avec le consommateur Kafka</strong></h3><p>Le consommateur est conçu pour traiter efficacement les messages, en consommant des lots à partir du sujet des journaux et en les indexant dans Elasticsearch. Avec <code>auto_offset_reset='latest'</code>, il s'assure que le consommateur commence à traiter les messages les plus récents, en ignorant les plus anciens, et <code>max_poll_records=10</code> limite le lot à 10 messages. Avec <code>fetch_max_wait_ms=2000</code>, le consommateur attend jusqu'à 2 secondes pour accumuler suffisamment de messages avant de traiter le lot.</p><p>Dans sa boucle principale, le consommateur consomme les messages du journal, traite et indexe chaque lot dans Elasticsearch, assurant ainsi une ingestion continue des données.</p>consumer = KafkaConsumer(
   'logs',                               
   bootstrap_servers=['localhost:9092'],
   auto_offset_reset='latest',            # Ensures reading from the latest offset if the group has no offset stored
   enable_auto_commit=True,               # Automatically commits the offset after processing
   group_id='log_consumer_group',         # Specifies the consumer group to manage offset tracking
   max_poll_records=10,                   # Maximum number of messages per batch
   fetch_max_wait_ms=2000                 # Maximum wait time to form a batch (in ms)
)

def create_bulk_actions(logs):
   for log in logs:
       yield {
           "_index": "logs",
           "_source": {
               'level': log['level'],
               'message': log['message'],
               'timestamp': log['timestamp']
           }
       }

if __name__ == "__main__":
   try:
       print("Starting message processing…")
       while True:

           messages = consumer.poll(timeout_ms=1000)  # Poll receive messages

           # process each batch messages
           for _, records in messages.items():
               logs = [json.loads(record.value) for record in records]
               bulk_actions = create_bulk_actions(logs)
               response = helpers.bulk(es, bulk_actions)
               print(f"Indexed {response[0]} logs.")
   except Exception as e:
       print(f"Erro: {e}")
   finally:
       consumer.close()
       print(f"Finish")<h3><strong>Visualisation des données dans Kibana</strong></h3><p>Avec Kibana, nous pouvons explorer et valider les données ingérées depuis Kafka et indexées dans Elasticsearch. En accédant à <strong>Dev Tools</strong> dans Kibana, vous pouvez visualiser les messages indexés et confirmer que les données sont conformes aux attentes. Par exemple, si notre producteur Kafka a envoyé 5 lots de 10 messages chacun, nous devrions voir un total de 50 enregistrements dans l'index.</p><p>Pour vérifier les données, vous pouvez utiliser la requête suivante dans la section <strong>Outils de développement :</strong></p>GET /logs/_search
{
  "query": {
    "match_all": {}
  }
}<p>Réponse :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc15fb278fe6f984e/6a17f7c0b1e1131ac279f404/f44f95fc27bba50991412d5c7e7728519b9bdec4-688x1024.png" alt="Réponse vérifier les données - Kafka &amp; Elasticsearch​" /><p>En outre, Kibana permet de créer des visualisations et des tableaux de bord qui peuvent rendre l'analyse plus intuitive et interactive. Vous trouverez ci-dessous quelques exemples de tableaux de bord et de visualisations que nous avons créés, qui illustrent les données sous différents formats, améliorant ainsi notre compréhension des informations traitées.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltabc2856c9feedc47/6a17f7c13e9e4522bfba1651/a18e0ebb543e929136d4786651bc6cee32fa69bc-1600x470.png" alt="Visualisation Kibana - Kafka &amp; Elasticsearch​" /><h3><strong>Ingestion de données avec Kafka Connect</strong></h3><p>Kafka Connect est un service conçu pour faciliter l'intégration entre les sources de données et les destinations (puits), telles que les bases de données ou les systèmes de fichiers. Il fonctionne avec des connecteurs prédéfinis qui gèrent automatiquement les mouvements de données. Dans notre cas, Elasticsearch fait office de puits de données.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt53e3acaf62e7dbed/6a17f7c3577262c5151bcdb0/52a6982c864fdc04cb7a8a5fb02e67dca0ba8226-1600x819.png" alt="Ingestion de données avec Kafka Connect" /><p>En utilisant Kafka Connect, nous pouvons simplifier le processus d'ingestion de données, en éliminant la nécessité d'implémenter manuellement le workflow d'ingestion de données dans Elasticsearch. Avec le connecteur approprié, Kafka Connect permet aux données envoyées à un sujet Kafka d'être directement indexées dans Elasticsearch avec une configuration minimale et sans codage supplémentaire.</p><h4><strong>Travailler avec Kafka Connect</strong></h4><p>Pour mettre en œuvre Kafka Connect, nous allons ajouter le<a href="https://github.com/andreluiz1987/es-apache-kafka/blob/main/docker-compose.yml#L31"> service kafka-connect </a>à notre installation Docker Compose. Un élément clé de cette configuration est l'installation du connecteur Elasticsearch, qui se chargera de l'indexation des données.</p><p>Après avoir configuré le service et créé le conteneur Kafka Connect, un fichier de configuration pour le connecteur Elasticsearch sera nécessaire. Ce fichier définit des paramètres essentiels tels que</p><ul><li><p><code>connection.url</code>: URL de connexion pour Elasticsearch.</p></li><li><p><code>topics</code>: Le sujet Kafka que le connecteur surveillera (dans ce cas, "logs").</p></li><li><p><code>type.name</code>: Type de document dans Elasticsearch (typiquement _doc).</p></li><li><p><code>value.converter</code>: Convertit les messages Kafka au format JSON.</p></li><li><p><code>value.converter.schemas.enable</code>: Spécifie si le schéma doit être inclus.</p></li><li><p><code>schema.ignore</code> et <code>key.ignore</code>: Paramètres permettant d'ignorer les schémas et les clés Kafka lors de l'indexation.</p></li></ul><p>Voici la commande <code>curl</code> pour créer le connecteur Elasticsearch dans Kafka Connect :</p>curl --location '{{url}}/connectors' \
--header 'Content-Type: application/json' \
--data '{
    "name": "elasticsearch-sink-connector",
    "config": {
        "connector.class": "io.confluent.connect.elasticsearch.ElasticsearchSinkConnector",
        "topics": "logs",
        "connection.url": "http://elasticsearch:9200",
        "type.name": "_doc",
        "value.converter": "org.apache.kafka.connect.json.JsonConverter",
        "value.converter.schemas.enable": "false",
        "schema.ignore": "true",
        "key.ignore": "true"
    }
}'<p>Avec cette configuration, Kafka Connect commencera automatiquement à ingérer les données envoyées au sujet "logs" et à les indexer dans Elasticsearch. Cette approche permet d'automatiser entièrement l'ingestion et l'indexation des données sans nécessiter de codage supplémentaire, ce qui simplifie l'ensemble du processus d'intégration.</p><h3><strong>Conclusion</strong></h3><p>L'intégration de Kafka et d'Elasticsearch crée un pipeline puissant pour l'ingestion et l'analyse de données en temps réel. Ce guide fournit une approche fondamentale pour construire une architecture d'ingestion de données robuste, avec une visualisation et une analyse transparentes dans Kibana, prête à s'adapter à des exigences plus complexes à l'avenir.</p><p>En outre, l'utilisation de Kafka Connect rend l'intégration entre Kafka et Elasticsearch encore plus rationnelle, en éliminant le besoin de code supplémentaire pour traiter et indexer les données. Kafka Connect permet aux données envoyées à un sujet spécifique d'être automatiquement indexées dans Elasticsearch avec une configuration minimale.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-apache-kafka-ingest-data</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-apache-kafka-ingest-data</guid>
    <category><![CDATA[Indexer des données]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt53e3acaf62e7dbed/6a17f7c3577262c5151bcdb0/52a6982c864fdc04cb7a8a5fb02e67dca0ba8226-1600x819.png" length="0" type="image/png"/>
    <pubDate>Tue, 24 Dec 2024 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Comment utiliser la recherche hybride pour un catalogue de produits de commerce électronique ?]]></title>
    <description><![CDATA[Apprenez à utiliser la recherche hybride pour créer un catalogue de produits de commerce électronique, en utilisant les facettes, les promotions, la personnalisation et l'analyse comportementale.]]></description>
    <content:encoded><![CDATA[<p>Dans cet article, nous allons montrer comment mettre en œuvre une recherche hybride qui combine les résultats de la recherche en texte intégral et de la recherche vectorielle. En unifiant ces deux approches, la recherche hybride améliore l'étendue des résultats, en tirant le meilleur des deux stratégies de recherche.</p><p>Outre l'intégration de la recherche hybride, nous vous montrerons comment ajouter des fonctionnalités qui rendront votre solution de recherche encore plus robuste. Il s'agit notamment des facettes et des promotions de produits personnalisées. En outre, nous vous montrerons comment capturer les interactions des utilisateurs et générer des informations précieuses à l'aide de l'outil d'analyse comportementale d'Elastic.</p><p>Dans cette mise en œuvre, vous verrez comment construire à la fois l'interface qui permet aux utilisateurs de visualiser et d'interagir avec les résultats de la recherche et l'API responsable du retour des informations. Pour accéder aux dépôts contenant le code source, les liens sont fournis ci-dessous :</p><ul><li><p><a href="https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/hybrid-search-for-an-e-commerce-product-catalogue/product-store-search">https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/hybrid-search-for-an-e-commerce-product-catalogue/product-store-search</a></p></li><li><p><a href="https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/hybrid-search-for-an-e-commerce-product-catalogue/app-product-store">https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/hybrid-search-for-an-e-commerce-product-catalogue/app-product-store</a> </p></li></ul><p>Nous avons divisé ce guide en plusieurs étapes, de la création de l'index à la mise en œuvre de fonctionnalités avancées telles que les facettes et la personnalisation des résultats. À la fin, vous aurez une solution de recherche robuste prête à être utilisée dans un scénario de commerce électronique.</p><h2>Configuration de l'environnement pour la recherche hybride dans le domaine du commerce électronique</h2><p>Avant de commencer la mise en œuvre, nous devons mettre en place l'environnement. Vous pouvez choisir d'utiliser un service sur Elastic Cloud ou une solution conteneurisée pour gérer Elasticsearch. Si vous choisissez la conteneurisation, une configuration via Docker Compose peut être trouvée dans ce dépôt : <a href="https://github.com/andreluiz1987/product-store-search/blob/main/docker/docker-compose.yml">docker-compose.yml</a>.</p><h2>Création d'index et ingestion de catalogues de produits</h2><p>L'index sera créé sur la base d'un catalogue de produits cosmétiques, qui comprend des champs tels que le nom, la description, la photo, la catégorie et les étiquettes. Les champs utilisés pour la recherche en texte intégral, tels que "nom" et "description," seront mappés comme <code>text</code>, tandis que les champs utilisés pour les agrégations, tels que "catégorie" et "marque," seront mappés comme <code>keyword</code> pour permettre les facettes.</p><p>Le champ "description" sera utilisé pour la recherche vectorielle, car il fournit plus de détails sur les produits. Ce champ sera défini comme <code>dense_vector,</code> stockant la représentation vectorielle de la description.</p><p>La correspondance de l'index sera la suivante :</p>{
   "mappings":{
      "properties":{
         "id":{
            "type":"keyword"
         },
         "brand":{
            "type":"text",
            "fields":{
               "keyword":{
                  "type":"keyword"
               }
            }
         },
         "name":{
            "type":"text"
         },
         "price":{
            "type":"float"
         },
         "price_sign":{
            "type":"keyword"
         },
         "currency":{
            "type":"keyword"
         },
         "image_link":{
            "type":"keyword"
         },
         "description":{
            "type":"text"
         },
         "description_embeddings":{
            "type":"dense_vector",
            "dims":384
         },
         "rating":{
            "type":"keyword"
         },
         "category":{
            "type":"keyword"
         },
         "product_type":{
            "type":"keyword"
         },
         "tag_list":{
            "type":"keyword"
         }
      }
   }
}<p>Le script de création de l'index est disponible <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/hybrid-search-for-an-e-commerce-product-catalogue/product-store-search/infra/create_index.py">ici.</a></p><h2>Génération de l'intégration</h2><p>Pour vectoriser les descriptions de produits, nous utilisons le modèle all-MiniLM-L6-v2. Dans ce cas, l'application est responsable de la génération des embeddings avant l'indexation. Une autre option serait d'importer le modèle dans le cluster Elasticsearch, mais pour cet environnement local, nous avons choisi d'effectuer la vectorisation directement dans l'application.</p><p>Nous avons utilisé l'ensemble de données sur les cosmétiques disponible sur <a href="https://www.kaggle.com/datasets/shivd24coder/cosmetic-brand-products-dataset">Kaggle</a> pour alimenter l'index, et pour améliorer l'efficacité de l'ingestion des données, nous avons utilisé le traitement par lots. Au cours de cette même étape d'ingestion, nous générerons les embeddings pour le champ "description" et les indexerons dans le nouveau champ "description_embeddings".</p><p>Le processus complet d'ingestion des données peut être suivi et exécuté directement via le <strong>carnet Jupyter</strong> disponible dans le référentiel. Le carnet de notes fournit un guide étape par étape sur la façon dont les données sont lues, traitées et indexées dans Elasticsearch, ce qui permet de les reproduire et de les expérimenter facilement.</p><p>Vous pouvez accéder au carnet en cliquant sur le lien suivant : <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/hybrid-search-for-an-e-commerce-product-catalogue/product-store-search/ingestion/ingestion.ipynb">Cahier d'ingestion.</a></p><h2>Mise en œuvre de la recherche hybride</h2><p>Mettons maintenant en œuvre la recherche hybride. Pour la recherche par mot-clé, nous utilisons la requête <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html">multi_match</a>, ciblant les champs "nom," " catégorie," et "description." Cela permet de s'assurer que les documents contenant le terme de recherche dans n'importe lequel de ces champs sont retrouvés.</p><p>Pour la recherche vectorielle, nous utilisons la <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/knn-search.html">requête KNN</a>. Le terme de recherche doit être vectorisé avant d'exécuter la requête, ce qui est fait à l'aide de la méthode qui vectorise le terme d'entrée. Notez que le modèle utilisé lors de l'ingestion est également utilisé pour le terme de recherche.</p><p>La combinaison des deux recherches est réalisée à l'aide de l'algorithme <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/rrf.html">Reciprocal Rank Fusion (RRF) </a>, qui fusionne les résultats des deux requêtes et augmente la précision de la recherche en réduisant le bruit. RRF permet aux recherches par mots-clés et aux recherches vectorielles de fonctionner ensemble, améliorant ainsi la compréhension de la requête de l'utilisateur.</p>query = {
   "retriever": {
       "rrf": {
           "retrievers": [
               {
                   "standard": {
                       "query": organic_query['query']
                   }
               },
               {
                   "knn": {
                       "field": "description_embeddings",
                       "query_vector": vector,
                       "k": 5,
                       "num_candidates": 20
                   }
               }
           ],
           "rank_window_size": 20,
           "rank_constant": 5
       }
   },
   "_source": organic_query['_source']
}<h3>Comparaison des résultats : recherche par mot-clé et recherche hybride</h3><p>Comparons maintenant les résultats d'une recherche traditionnelle par mot-clé avec ceux d'une recherche hybride. En recherchant "foundation for dry skin" à l'aide de mots-clés, nous obtenons les résultats suivants :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcb5405df787bc8f5/6a17023e961e697ca1c4cdb4/52e717aa3c9c1fadfadb639f5fb77cf8e47e3b34-1600x1021.png" alt="Comparaison des résultats : Recherche par mot-clé vs. recherche hybride" /><ol><li><p><strong>Revlon ColorStay Makeup pour peau normale / sècheDescription</strong>: Le maquillage Revlon ColorStay offre une couverture longue durée grâce à une formule légère qui ne s'étale pas, ne s'estompe pas et ne s'efface pas. Grâce à la technologie Time Release, cette formule sans huile à l'équilibre hydrique est spécialement conçue pour les peaux normales ou sèches afin de leur apporter une hydratation continue : Le maquillage est confortable et tient jusqu'à 24 heures. Couvrance moyenne à complète.
</p></li><li><p><strong>Fond de teint mousse Maybelline Dream SmoothDescription</strong>: Pourquoi vous allez l'adorerUn fond de teint crème fouettée unique qui offre 100% une perfection lisse comme un bébé.\N- Peau L'apparence et la sensation d'hydratation durent 14 heures - jamais rugueuse ou sèche. La formule légère offre une couverture parfaitement hydratante. Elle s'intègre parfaitement et donne une sensation de fraîcheur tout au long de la journée. Sans huile, sans parfum, testée par des dermatologues, testée contre les allergies, non comédogène. pour les peaux sensibles.</p></li></ol><p><strong>Analyse</strong>: Lors de la recherche de "foundation for dry skin," les résultats ont été obtenus par la correspondance exacte entre les mots-clés de la recherche et les titres et descriptions des produits. Cependant, cette correspondance ne reflète pas toujours le meilleur choix. Par exemple, le <strong>maquillage Revlon ColorStay pour peau normale/sèche</strong> est une bonne option, car il est spécifiquement formulé pour les peaux sèches. Bien qu'elle soit sans huile, sa formule est conçue pour offrir une hydratation continue. En revanche, nous avons également reçu le <strong>fond de teint Maybelline Dream Smooth Mousse</strong>, qui, bien que sans huile et mentionnant l'hydratation, est généralement plus recommandé pour les peaux grasses ou mixtes, car les produits sans huile ont tendance à se concentrer sur le contrôle du sébum plutôt qu'à fournir l'hydratation supplémentaire nécessaire aux peaux sèches. Cela met en évidence les limites des recherches par mots clés, qui peuvent renvoyer des produits ne répondant pas entièrement aux besoins spécifiques des personnes ayant la peau sèche.</p><p>Maintenant, si l'on effectue la même recherche en utilisant l'approche hybride :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt412e38b327cf6a4f/6a17024066c4f94c52f8beb9/13b562a5120619355ba0861976102e208964a49f-1600x1021.png" alt="Effectuer une recherche à l'aide de l'approche hybride" /><ol><li><p><strong>CoverGirl Outlast Stay Luminous Foundation Creamy Natural (820):Description</strong>: Le fond de teint Outlast Stay Luminous de CoverGirl est parfait pour obtenir un fini rosé et un éclat subtil. Il est sans huile, avec une formule non grasse qui donne à votre peau une luminosité naturelle qui dure toute la journée ! Ce fond de teint, qui dure toute la journée, hydrate la peau tout en offrant une couverture parfaite.

<strong>Analyse : </strong>Ce produit est pertinent car il met l'accent sur l'hydratation, ce qui est essentiel pour les utilisateurs à la peau sèche. Les termes "hydrates skin" et "dewy finish" correspondent à l'intention de l'utilisateur de trouver un fond de teint pour les peaux sèches. La recherche vectorielle a probablement compris le concept d'hydratation et l'a associé à la nécessité d'un fond de teint qui réponde aux besoins des peaux sèches.
</p></li><li><p><strong>Revlon ColorStay Makeup pour peau normale / sèche:Description :</strong> Le maquillage Revlon ColorStay offre une couverture longue durée grâce à une formule légère qui ne s'estompe pas, ne se décolore pas et ne s'efface pas. Grâce à la technologie Time Release, cette formule sans huile et équilibrant l'hydratation est spécialement conçue pour les peaux normales ou sèches afin de leur apporter une hydratation continue.

<strong>Analyse : </strong>Ce produit répond directement aux besoins des utilisateurs ayant la peau sèche, en mentionnant explicitement qu'il est formulé pour les peaux normales ou sèches. La formule d'équilibre hydrique "" et l'hydratation continue conviennent parfaitement aux personnes à la recherche d'un fond de teint pour les peaux sèches. La recherche vectorielle a permis d'obtenir ce résultat, non seulement en raison de la correspondance des mots clés, mais aussi parce que l'accent est mis sur l'hydratation et que la peau sèche est spécifiquement mentionnée comme cible démographique.
</p></li><li><p><strong>Fond de teint sérumDescription : </strong>Les fonds de teint sérum sont des formules légères à couvrance moyenne, disponibles dans une gamme complète de 21 teintes. Ces fonds de teint offrent une couvrance modérée d'aspect naturel avec une sensation de sérum très léger. Ils ont une très faible viscosité et sont distribués avec la pompe fournie ou avec le compte-gouttes en verre optionnel disponible séparément si vous le souhaitez.

<strong>Analyse :</strong> Dans ce cas, la description met l'accent sur un fond de teint sérum léger au toucher naturel, ce qui correspond aux besoins des personnes ayant la peau sèche, qui recherchent souvent des produits doux, hydratants et offrant un fini non gélifié. La recherche vectorielle a probablement pris en compte le contexte plus large de la couverture légère et naturelle et de la texture semblable à celle d'un sérum, qui est associée à la rétention de l'humidité et à une application confortable, ce qui la rend pertinente pour les peaux sèches, même si le terme "dry skin" n'est pas explicitement mentionné.</p></li></ol><h2>Mise en œuvre des facettes</h2><p>Les facettes sont essentielles pour affiner et filtrer efficacement les résultats de la recherche, en offrant aux utilisateurs une navigation plus ciblée, en particulier dans les scénarios comportant une grande variété de produits, tels que le commerce électronique. Ils permettent aux utilisateurs d'ajuster les résultats en fonction d'attributs tels que la catégorie, la marque ou le prix, ce qui rend la recherche plus précise. Pour mettre en œuvre cette fonctionnalité, nous utilisons des <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html">agrégations de termes</a> sur les champs <code>category</code> et <code>brand</code>, qui ont été définis comme <code>keyword</code> lors de la phase de création de l'index.</p>    query = build_query(term, categories, product_types, brands)
    query["aggs"] = {
        "product_types": {"terms": {"field": "product_type"}},
        "categories": {"terms": {"field": "category"}},
        "brands": {"terms": {"field": "brand.keyword"}}
    }<p>Le code complet de la mise en œuvre est disponible <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/hybrid-search-for-an-e-commerce-product-catalogue/product-store-search/api/api.py#L144">ici.</a></p><p>Voir ci-dessous les résultats de la recherche de "foundation for dry skin":</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt31080652a60d8600/6a1702416234e0af7ddb18e7/e8907af359c021eaa38ec7a6a53f10c325ee8ade-1146x1248.png" alt="Résultats de la recherche de &quot;foundation for dry skin&quot;" /><h2>Personnalisation des résultats : requêtes épinglées</h2><p>Dans certains cas, il peut être avantageux de promouvoir certains produits dans les résultats de recherche. Pour ce faire, nous utilisons les <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-pinned-query.html"><strong>requêtes épinglées</strong></a>, qui permettent à des produits spécifiques d'apparaître en tête des résultats. Ci-dessous, nous effectuerons une recherche sur le terme "Foundation" sans promouvoir aucun produit :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt31e75c815262993e/6a170243509168ae42e1b95d/9396c4ed358e7a68eed47f17dd6915d0bad492aa-1600x1157.png" alt="Recherchez le terme &quot;Foundation&quot; sans promouvoir de produits." /><p>Dans notre exemple, nous pouvons promouvoir les produits qui portent l'étiquette "Gluten Free." En utilisant les identifiants des produits, nous nous assurons qu'ils sont prioritaires dans les résultats de recherche. Plus précisément, nous ferons la promotion des produits suivants : <strong>Fond de teint sérum</strong> (ID : 1043), <strong>Fond de teint couvrance</strong> (ID : 1042) et <strong>Poudre fixante invisible Realist</strong> (ID : 1039).</p>{
   "query":{
      "pinned":{
         "ids":[
            "1043",
            "1042",
            "1039"
         ],
         "organic":{
            "bool":{
               "must":[
                  {
                     "multi_match":{
                        "query":"foundation",
                        "fields":[
                           "name",
                           "category",
                           "description"
                        ]
                     }
                  }
               ]
            }
         }
      }
   }
}<p>Nous utilisons des identifiants de produits spécifiques pour nous assurer qu'ils sont prioritaires dans les résultats de la recherche. La structure de la requête comprend une liste d'ID de produits qui doivent être "épinglés" en haut (dans ce cas, les ID 1043, 1042 et 1039), tandis que les autres résultats suivent le flux organique de la recherche, en utilisant une combinaison de conditions telles que le texte de la requête dans les champs "nom", "catégorie", et "description". Il est ainsi possible de promouvoir des éléments de manière contrôlée, en assurant leur visibilité, tout en maintenant le reste de la recherche sur la base de la pertinence habituelle.</p><p>Ci-dessous, vous pouvez voir le résultat de l'exécution de la requête avec les produits promus :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt53a6d5cbef227f16/6a1702458b73cb68f0189ef3/8c1a547bfe31360c405eae0891c666635051a51b-1600x1039.png" alt="Résultat de l'exécution de la requête avec les produits promus" /><p>Le code d'interrogation complet est disponible <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/hybrid-search-for-an-e-commerce-product-catalogue/product-store-search/api/api.py#L112">ici.</a></p><h2>Analyser le comportement de recherche avec l'analyse comportementale</h2><p>Jusqu'à présent, nous avons déjà ajouté des fonctionnalités pour améliorer la pertinence des résultats de recherche et faciliter la découverte des produits. Nous allons maintenant finaliser notre solution de recherche en incluant une fonctionnalité qui nous aidera à analyser le comportement de recherche des utilisateurs, en identifiant des modèles tels que les requêtes avec ou sans résultats et les clics sur les résultats de la recherche.pour cela, nous utiliserons la fonctionnalité <strong>Behavioral Analytics</strong> fournie par Elastic. Grâce à lui, en quelques étapes seulement, nous pouvons surveiller et analyser le comportement de recherche des utilisateurs, en obtenant des informations précieuses pour optimiser l'expérience de recherche.</p><h3>Création de la collection d'analyses comportementales</h3><p>Notre première action sera de créer une collection, qui sera responsable de la réception de tous les événements d'analyse du comportement. Pour créer la collection, accédez à l'interface Kibana dans <strong>Search &gt; Behavioral Analytics</strong>. Dans l'exemple ci-dessous, nous avons créé une collection nommée <code>tracking-search</code>.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9b4cb5480ab0bfef/6a1702474a531b189936a7e7/c05e533212a3690c5ea9f2d5226cbcdc901c482a-1600x1009.png" alt="Analyse comportementale - nommer votre collection" /><h3>Intégrer l'analyse comportementale dans l'interface</h3><p>Notre application <a href="https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/hybrid-search-for-an-e-commerce-product-catalogue/app-product-store">frontale</a> a été développée en JavaScript, et pour intégrer Behavioral Analytics, nous suivrons les étapes décrites dans la documentation officielle d'Elastic pour installer le <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/behavioral-analytics-start.html#behavioral-analytics-start-ui-integration-js-client"><strong>Behavioral Analytics JavaScript Tracker</strong></a>.</p><h3>Mise en œuvre du tracker JavaScript</h3><p>Nous allons maintenant importer le client tracker dans notre application et utiliser les méthodes <code>trackPageView</code>, <code>trackSearch</code>, et <code>trackSearchClick</code> pour capturer les interactions des utilisateurs.</p><p><strong>Avertissement</strong>: Bien que nous utilisions un outil pour collecter les données d'interaction des utilisateurs, il est essentiel d'assurer la conformité avec le <strong>GDPR</strong>. Cela signifie qu'il faut informer clairement les utilisateurs des données collectées et de la manière dont elles seront utilisées, et leur donner la possibilité de refuser le suivi. En outre, nous devons mettre en œuvre de solides mesures de sécurité pour protéger les informations collectées et respecter les droits des utilisateurs, tels que l'accès aux données et leur suppression, en veillant à ce que toutes les étapes soient conformes aux principes du GDPR.
</p><p><strong>Étape 1 : Création de l'instance de suivi</strong></p><p>Tout d'abord, nous allons créer l'instance de suivi qui surveillera les interactions. Dans cette configuration, nous définissons le point de terminaison cible, le nom de la collection et la clé API :</p>createTracker({
  endpoint: "https://endpoint:443",
  collectionName: "tracking-search",
  apiKey: "api-key"
});<p><strong>Étape 2 : Capturer les pages vues</strong></p><p>Pour suivre les pages vues, nous pouvons configurer l'événement <code>trackPageView</code>:</p>    trackPageView({
      page: {
        title: "home-page"
      },
    });<p>Pour plus de détails sur l'événement <code>trackPageView</code>, vous pouvez consulter cette <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/behavioral-analytics-event-reference.html#behavioral-analytics-event-reference-pageview-fields">documentation</a>.</p><p><strong>Étape 3 : Saisir les requêtes de recherche</strong></p><p>Pour suivre les actions de recherche des utilisateurs, nous utiliserons la méthode <code>trackSearch</code>:</p>      trackSearch({
        search: {
          query: searchTerm,
          results: {
            items: documents,
            total_results: response.data.length,
          },
        },
      });<p>Ici, nous collectons le terme de recherche et les résultats de la recherche.</p><p><strong>Étape 4 : Suivi des clics sur les résultats de recherche</strong></p><p>Enfin, pour capturer les clics sur les résultats de recherche, nous utiliserons la méthode <code>trackSearchClick</code>:</p>trackSearchClick({
      document: { id: product.id, index: "products-catalog"},
      search: {
        query: searchTerm,
        page: {
          current: 1,
          size: products.length,
        },
        results: {
          items: documents,
          total_results: products.length,
        },
        search_application: "app-product-store"
      },
    });<p>Nous recueillons des informations sur l'identifiant du document cliqué, ainsi que sur le terme et les résultats de la recherche.</p><h3>Analyse des données dans Kibana</h3><p>Maintenant que les événements d'interaction avec l'utilisateur sont capturés, nous pouvons obtenir des données précieuses sur les actions de recherche. Kibana utilise l'outil d'analyse comportementale pour visualiser et analyser ces données comportementales. Pour afficher les résultats, il suffit de naviguer vers <strong>Search &gt; Behavioral Analytics &gt; My Collection</strong>, où une vue d'ensemble des événements capturés s'affichera.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdab4f4507c5a4732/6a17024860084b34ca3c4411/e219c4af2e01b0ccc1b9079459a07832835abc75-1600x1155.png" alt="Analyse des données dans Kibana" /><p>Cette vue d'ensemble nous donne un aperçu général des événements capturés pour chaque action intégrée dans notre interface. Ces informations nous permettent d'obtenir des informations précieuses sur le comportement de recherche des utilisateurs. Cependant, si vous souhaitez créer des tableaux de bord personnalisés avec des mesures plus pertinentes pour votre scénario spécifique, Kibana offre des outils puissants pour construire des tableaux de bord, vous permettant de créer diverses visualisations de vos mesures.</p><p>Ci-dessous, j'ai créé quelques visualisations et graphiques pour suivre, par exemple, les termes les plus recherchés au fil du temps, les requêtes qui n'ont donné aucun résultat, un nuage de mots mettant en évidence les termes les plus recherchés et, enfin, une visualisation géographique pour identifier d'où vient l'accès à la recherche.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt04ced4406436f942/6a17024a5091685116e1b961/84a2c39dab77a3f9366c258a3a45d2cbc7df125e-1600x689.png" alt="Visualisations et graphiques pour le suivi" /><h2>Conclusion</h2><p>Dans cet article, nous avons mis en œuvre une solution de recherche hybride qui combine la recherche par mot-clé et la recherche vectorielle, offrant ainsi des résultats plus précis et plus pertinents aux utilisateurs. Nous avons également étudié comment utiliser des fonctionnalités supplémentaires, telles que les facettes et la personnalisation des résultats avec les requêtes épinglées, afin de créer une expérience de recherche plus complète et plus efficace.</p><p>En outre, nous avons intégré l'<strong>analyse comportementale</strong> d'Elastic pour capturer et analyser le comportement des utilisateurs au cours de leurs interactions avec le moteur de recherche. En utilisant des méthodes telles que <code>trackPageView</code>, <code>trackSearch</code>, et <code>trackSearchClick</code>, nous avons pu suivre les requêtes de recherche, les clics sur les résultats de recherche et les pages consultées, ce qui nous a permis d'obtenir des informations précieuses sur le comportement de recherche.</p><h2>Références</h2><p>Ensemble de données</p><p><a href="https://www.kaggle.com/datasets/shivd24coder/cosmetic-brand-products-dataset">https://www.kaggle.com/datasets/shivd24coder/cosmetic-brand-products-dataset</a></p><p>Transformateur</p><p><a href="https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2">https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2</a></p><p>Fusion de rangs réciproques</p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/rrf.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/rrf.html</a></p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/retriever.html#rrf-retriever">https://www.elastic.co/guide/en/elasticsearch/reference/current/retriever.html#rrf-retriever</a></p><p>Requête Knn</p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/knn-search.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/knn-search.html</a></p><p>Requête épinglée</p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-pinned-query.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-pinned-query.html</a></p><p>API d'analyse comportementale</p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/behavioral-analytics-apis.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/behavioral-analytics-apis.html</a></p><p>https://www.elastic.co/guide/en/elasticsearch/reference/current/behavioral-analytics-overview.html</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/hybrid-search-ecommerce</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/hybrid-search-ecommerce</guid>
    <category><![CDATA[Base vectorielle]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt63c711d1bf9b2501/6a17024c66c4f9c2b7f8bebd/05578fc595a12f6b1ebf88a10a2a31e9971b545e-1200x628.png" length="0" type="image/png"/>
    <pubDate>Tue, 12 Nov 2024 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Mise en œuvre de la recherche sémantique : Construire une recherche de recettes avec Elasticsearch]]></title>
    <description><![CDATA[Mise en œuvre de la recherche sémantique dans le contexte des sites de commerce électronique.]]></description>
    <content:encoded><![CDATA[<h2>Introduction</h2><p>De nombreux sites de commerce électronique souhaitent améliorer leur expérience en matière de recherche de recettes. La recherche sémantique, lorsqu'elle est appliquée correctement, permet aux clients de trouver rapidement les ingrédients nécessaires sur la base de requêtes plus naturelles, telles que "quelque chose pour la Saint-Valentin" ou "les repas de Thanksgiving."</p><p>Dans cet article, nous allons montrer comment utiliser Elasticsearch pour mettre en œuvre une recherche sémantique qui prend en charge de telles requêtes. Nous configurerons un index pour stocker le catalogue des ingrédients et des produits d'un supermarché et nous montrerons comment cet index peut être utilisé pour améliorer les recherches de recettes. Tout au long de cet article, nous expliquerons comment créer cette structure de données et appliquer des techniques de traitement du langage naturel pour fournir des résultats pertinents correspondant à l'intention du client.</p><p>Tout le code présenté dans cet article a été développé en Python et est disponible sur <a href="https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/building-a-recipe-search-with-elasticsearch">GitHub</a>. Vous pouvez accéder au référentiel pour examiner le code source, faire les ajustements nécessaires et mettre en œuvre les solutions directement dans votre environnement de développement.</p><h2>Démarrer la mise en œuvre de la recherche sémantique</h2><p>Pour commencer à mettre en œuvre la recherche sémantique, nous devons d'abord définir le modèle de langage naturel. Elastic fournit son propre modèle, <a href="https://www.elastic.co/guide/en/machine-learning/8.15/ml-nlp-elser.html"><strong>ELSER</strong></a>, mais offre également un support pour l'intégration de modèles NLP provenant de divers fournisseurs, tels que Hugging Face. Cette flexibilité vous permet de choisir l'option qui répond le mieux à vos besoins.</p><p>Dans cet article, nous utiliserons <strong>ELSER</strong>, qui réduit la complexité du déploiement et de la gestion des modèles NLP. En outre, Elastic propose la fonction <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/semantic-search-semantic-text.html"><strong>semantic_text</strong></a>, qui simplifie grandement le processus. Avec <strong>semantic_text</strong>, l'ensemble du processus de génération d'encarts devient simple et automatisé. Il vous suffit de définir un point d'inférence et de spécifier le champ qui recevra les embeddings dans votre mappage d'index. Lors de l'indexation des documents, des embeddings seront générés et automatiquement associés au champ spécifié.</p><h3>Étapes de la configuration</h3><p>Voici les étapes à suivre pour créer un index prenant en charge la recherche sémantique. En suivant ces instructions, vous aurez un index configuré et prêt pour les recherches sémantiques :</p><ol><li><p><strong>Créer le </strong><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/infer-service-elser.html"><strong>point d'inférence</strong></a>.</p></li><li><p><a href="https://github.com/andreluiz1987/semantic-search-market/blob/main/infra.py"><strong>Créer l'index</strong></a>, en définissant le champ description comme semantic_text afin qu'il puisse recevoir les embeddings.</p></li><li><p><a href="https://github.com/andreluiz1987/semantic-search-market/blob/main/ingestion.py"><strong>Indexer les données</strong></a> dans l'index "grocery-catalog", qui stockera un catalogue de produits. Ce catalogue a été obtenu à partir d'un ensemble de données disponible <a href="https://www.kaggle.com/datasets/bhavikjikadara/grocery-store-dataset?select=GroceryDataset.csv">ici.</a></p></li></ol><h2>Application de la recherche sémantique dans les supermarchés</h2><p>Maintenant que l'index est alimenté par les données sur les produits de l'épicerie, nous testons et validons les requêtes afin d'améliorer les résultats de recherche à l'aide de la recherche sémantique. Notre objectif est de fournir une expérience de recherche plus intelligente qui comprend le contexte et l'intention de l'utilisateur, en fournissant des résultats plus pertinents et plus précis.</p><h3>Défis résolus par la recherche sémantique</h3><p>Sur la base du catalogue de produits, examinons comment la recherche sémantique peut transformer l'expérience de recherche dans les magasins d'alimentation en abordant les questions de vocabulaire et de contexte avec lesquelles la recherche lexicale traditionnelle a souvent du mal à composer.</p><h4><strong>1. Interprétation des intentions culinaires</strong></h4><p><strong>Problème 01</strong>: Un client peut rechercher "seafood for grilling", mais un système de recherche lexicale peut ne pas comprendre entièrement l'intention qui sous-tend la requête. Il se peut qu'il ne parvienne pas à identifier tous les produits de la mer adaptés aux grillades et qu'il ne renvoie que les produits dont le titre contient le terme exact "seafood" ou "grill".</p><p>Dans un premier temps, nous effectuerons une recherche lexicale et analyserons les résultats. Ensuite, nous ferons la même chose avec une recherche sémantique, en comparant les résultats pour le même terme de recherche.</p><p><strong>Recherche lexicale</strong></p> response = client.search(
        index="grocery-catalog",
        size=5,
        source_excludes="description_embedding",
        query={
            "multi_match": {
                "query": "seafood for grilling",
                "fields": [
                    "name",
                    "description"]
            }
        }
    )<p><strong>Résultats :</strong></p><p>Type de recherche</p><p>Nom</p><p>Score</p><p>Lexique</p><p>Crabe des neiges Bairdi d'Alaska de Northwest Fish</p><p>10.453125</p><p>Lexique</p><p>M. Yoshida's, Sauce Original Gourmet</p><p>7.2289705</p><p>Lexique</p><p>Premium Seafood Variety Pack - 20 pièces</p><p>7.1924105</p><p>Lexique</p><p>Vivaneau rouge américain - entier, étêté, nettoyé</p><p>6.998647</p><p>Lexique</p><p>Pinces de homard &amp; Arms, Sustainable Wild Caught</p><p>6.438654</p><p>La recherche lexicale a permis de trouver des produits de la mer adaptés à la cuisson au gril, tels que le vivaneau rouge américain et le crabe des neiges Bairdi de Northwest Fish Alaskan. Yoshida, qui n'est pas un produit de la mer mais une sauce pour la viande, ce qui suggère que l'algorithme lexical a eu du mal à comprendre le contexte de "pour les grillades."</p><p><strong>Solution de recherche sémantique</strong></p><p>Nous utilisons une requête qui combine le terme "seafood" avec des contextes de préparation tels que "grilling" pour obtenir une liste complète d'options, telles que les filets de poisson, les crevettes et les coquilles Saint-Jacques, qui sont idéales pour les grillades, même si les mots "grill" ou "seafood" n'apparaissent pas directement dans le nom du produit. Cela garantit que les résultats de la recherche correspondent mieux à l'intention du client.</p><p><strong>Recherche sémantique de requêtes :</strong></p>es_client.search(
   index="grocery-catalog-elser",
   size=size,
   source_excludes="description_embedding",
   query={
       "semantic": {
           "field": "description_embedding",
           "query": "seafood for grilling"

       }
   })<p>Type de recherche</p><p>Nom</p><p>Score</p><p>Sémantique</p><p>Branzino entier étêté et nettoyé</p><p>16.175909</p><p>Sémantique</p><p>Morue noire d'Alaska (morue charbonnière)</p><p>15.855331</p><p>Sémantique</p><p>Vivaneau rouge américain - entier, avec tête</p><p>15.454779</p><p>Sémantique</p><p>Crabe des neiges Bairdi d'Alaska de Northwest Fish</p><p>15.855331</p><p>Sémantique</p><p>Vivaneau rouge américain - entier, avec tête</p><p>15.3892355</p><p>La recherche sémantique a permis non seulement de trouver des produits directement liés au terme "seafood,", mais aussi de comprendre le contexte de "grilling," et de trouver des poissons entiers et des filets adaptés à la cuisson sur le gril. L'essentiel ici est la précision des résultats, qui incluent des poissons entiers tels que le branzino et le cabillaud noir d'Alaska, tous deux couramment utilisés pour les grillades.</p><p><strong>Problème 02 </strong>: De nombreux clients recherchent des solutions rapides et faciles pour dîner après une longue journée de travail, en utilisant des termes tels que "easy weeknight meals." La recherche lexicale traditionnelle peut ne pas saisir pleinement le concept de repas rapide, en se concentrant souvent sur les produits dont le nom contient le mot "easy".</p><p>Comme dans le problème précédent, nous commencerons par effectuer une recherche lexicale. Ensuite, nous appliquerons une solution utilisant la recherche sémantique.</p><p><strong>Recherche lexicale</strong></p> response = client.search(
        index="grocery-catalog",
        size=5,   
        source_excludes="description_embedding",
        query={
            "multi_match": {
                "query": "easy weeknight meals",
                "fields": [
                    "name",
                    "description"]
            }
        }
    )<p><strong>Résultats :</strong></p><p>Type de recherche</p><p>Nom</p><p>Score</p><p>Lexique</p><p>Étiquettes d'adresse Avery Easy Peel, 4200 pièces</p><p>8.017723</p><p>Lexique</p><p>Repas autochauffés d'urgence/portables 32</p><p>6.592727</p><p>Lexique</p><p>Poke de thon à nageoires jaunes en cubes de Coastal Seafood</p><p>5.836883</p><p>Lexique</p><p>Hefty Super Weight 12 oz Foam</p><p>5.8116536</p><p>Lexique</p><p>Serviette de table Vanity Fair Everyday, 2 plis, 110 unités</p><p>5.752989</p><p>La recherche lexicale a donné des résultats beaucoup moins pertinents, notamment des articles n'ayant aucun rapport avec les repas, tels que les étiquettes d'adresse Avery Easy Peel et les serviettes Vanity Fair Everyday Napkins. Ces produits ne répondent pas aux besoins des utilisateurs en matière de repas rapides. Si la recherche lexicale a permis de trouver un produit utile (Omeals Self Heating Emergency Meals), d'autres résultats, comme les serviettes et les étiquettes, ne correspondaient qu'aux mots "easy" ou "weeknight" dans leurs descriptions, sans vraiment répondre à l'intention de l'utilisateur de trouver une solution de repas rapide.</p><p><strong>Solution de recherche sémantique</strong></p><p>Nous avons mis en œuvre une requête qui comprend l'intention derrière les repas rapides et faciles. Il associe les produits qui peuvent être préparés rapidement, tels que les viandes précuites, les pâtes surgelées ou les kits repas, même s'ils ne comportent pas explicitement le mot "easy" dans leur nom. Cette approche permet aux clients de trouver les options les plus appropriées pour des dîners rapides en semaine, répondant ainsi à leur besoin de commodité.</p><p><strong>Recherche sémantique</strong></p>es_client.search(
   index="grocery-catalog-elser",
   size=size,
   source_excludes="description_embedding",
   query={
       "semantic": {
           "field": "description_embedding",
           "query": "easy weeknight meals"

       }
   })<p><strong>Résultats :</strong></p><p>Type de recherche</p><p>Nom</p><p>Score</p><p>Sémantique</p><p>Repas autochauffés d'urgence/portables 32</p><p>14.610006</p><p>Sémantique</p><p>Nissin, Cup Noodles, Crevettes, 2.5 oz</p><p>13.751424</p><p>Sémantique</p><p>Mélange pour gaufres sans gluten Namaste &amp; Mélange pour crêpes</p><p>13.73376</p><p>Sémantique</p><p>Idaho Spuds, pommes de terre rissolées Golden Grill</p><p>12.549422</p><p>Sémantique</p><p>Nissin, nouilles en coupe, poulet, 24 pièces</p><p>12.034527</p><p>La recherche sémantique a permis de trouver des produits clairement liés à des repas rapides et pratiques, tels que des nouilles instantanées (Cup Noodles), des pommes de terre précuites et des préparations pour crêpes, qui sont des choix typiques pour les dîners faciles en semaine. Cela démontre que la recherche sémantique peut saisir le concept derrière l'expression "easy weeknight meals," capturant l'intention de l'utilisateur de trouver des repas rapides et pratiques. Il est intéressant de noter que des produits appartenant à d'autres catégories, telles que "soda," peuvent également être inclus lorsqu'ils sont pertinents dans le contexte (par exemple, les boissons accompagnant les repas).</p><h4><strong>2. Termes régionaux et variations de vocabulaire</strong></h4><p><strong>Problème</strong>: un client peut rechercher "soda," alors qu'un autre client peut utiliser "pop" pour le même produit. La recherche lexicale traditionnelle ne tient pas compte du fait que les deux termes renvoient au même élément.</p><p><strong>Recherche lexicale</strong></p> response = client.search(
        index="grocery-catalog",
        size=5,
        source_excludes="description_embedding",
        query={
            "multi_match": {
                "query": "refreshing pop drink low sugar",
                "fields": [
                    "name",
                    "description"]
            }
        }
    )<p><strong>Résultats :</strong></p><p>Type de recherche</p><p>Nom</p><p>Score</p><p>Lexique</p><p>Prime Hydration+ Sticks Mélange pour boisson à base d'électrolytes</p><p>14.492869</p><p>Lexique</p><p>Capri Sun, 100% Jus, Variety Pack</p><p>12.340851</p><p>Lexique</p><p>Boisson énergétique Joyburst, Frose Rose, 12</p><p>11.839179</p><p>Lexique</p><p>Pop-Tarts de Kellogg, givrés sucre brun cannelle</p><p>9.97788</p><p>Lexique</p><p>Mini barres Kind, emballage varié, 0.7</p><p>9.336912</p><p>La recherche lexicale se concentre sur les correspondances exactes entre les mots. Si des produits comme Prime Hydration et Capri Sun sont apparus, la correspondance directe avec le terme "pop" a également donné lieu à des résultats non pertinents, tels que Kellogg's Pop-Tarts, qui est un en-cas et non une boisson. Cela montre que la recherche lexicale peut être moins efficace lorsqu'un terme a plusieurs significations ou peut être ambigu.</p><p><strong>Solution de recherche sémantique</strong></p><p>Les requêtes sémantiques permettent de résoudre le problème des variations de vocabulaire que la recherche lexicale ne parvient pas à résoudre. En élargissant les termes de recherche, nous sommes en mesure d'obtenir des résultats basés sur la signification contextuelle, ce qui permet de fournir des réponses plus pertinentes et plus complètes.</p><p><strong>Requête :</strong></p>es_client.search(
   index="grocery-catalog-elser",
   size=size,
   source_excludes="description_embedding",
   query={
       "semantic": {
           "field": "description_embedding",
           "query": "refreshing pop drink low sugar"

       }
   })<p><strong>Résultats :</strong></p><p>Type de recherche</p><p>Nom</p><p>Score</p><p>Sémantique</p><p>Olipop 12 oz Soda Prébiotique Variété</p><p>14.776867</p><p>Sémantique</p><p>Cocofusion antioxydante Bai, paquet de variétés, 18</p><p>14.663253</p><p>Sémantique</p><p>Boisson énergétique Monster, Zéro Ultra, 24</p><p>14.486348</p><p>Sémantique</p><p>Joyburst Energy Variété, 12 fl oz</p><p>14.007214</p><p>Sémantique</p><p>Boisson énergétique Joyburst, Frose Rose, 12</p><p>13.641038</p><p>La recherche sémantique renvoie des produits qui correspondent directement au concept de "pop" en tant que synonyme de "soda" (comme Olipop Prebiotics Soda), même si le terme exact "pop" n'est pas présent dans le nom du produit. La recherche a compris l'intention de l'utilisateur - une boisson rafraîchissante à faible teneur en sucre - et a pu renvoyer des produits pertinents, y compris des options telles que des sodas prébiotiques (Olipop) et des boissons énergisantes sans sucre (Monster Energy Drink).</p><h2>Conclusion</h2><p>La mise en œuvre de la recherche sémantique dans le contexte des magasins d'alimentation s'est avérée très efficace pour comprendre des requêtes complexes telles que "fruits de mer à griller" et "repas faciles à préparer en semaine." Cette approche nous a permis d'interpréter plus précisément les intentions des utilisateurs et de leur renvoyer des produits très pertinents.</p><p>En utilisant Elasticsearch et en simplifiant le processus avec ELSER, nous avons pu appliquer la recherche sémantique rapidement et efficacement, ce qui a permis d'améliorer considérablement les résultats de recherche et d'offrir une expérience d'achat plus souple et plus ciblée. Cela a permis non seulement d'optimiser le processus de recherche, mais aussi d'accroître la pertinence des résultats proposés aux clients.</p><h2>Références</h2><p>Modèle ELSER :</p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/put-inference-api.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/put-inference-api.html</a></p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/infer-service-elser.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/infer-service-elser.html</a></p><p></p><p>Texte sémantique :</p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/semantic-text.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/semantic-text.html</a></p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/semantic-search.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/semantic-search.html</a></p><p></p><p>Ensemble de données :</p><p><a href="https://www.kaggle.com/datasets/bhavikjikadara/grocery-store-dataset?select=GroceryDataset.csv">https://www.kaggle.com/datasets/bhavikjikadara/grocery-store-dataset?select=GroceryDataset.csv</a></p><p></p><p>Recherche sémantique :</p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/semantic-search.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/semantic-search.html</a></p><p><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/semantic-search-semantic-text.html">https://www.elastic.co/guide/en/elasticsearch/reference/current/semantic-search-semantic-text.html</a></p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/semantic-search-elasticsearch-ecommerce</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/semantic-search-elasticsearch-ecommerce</guid>
    <category><![CDATA[Les bases]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5c545fc80b6d79d6/6a170214839dfad776dcfd6f/d968e646240cd3ef7c79b5124d562a5f951d812b-1440x840.png" length="0" type="image/png"/>
    <pubDate>Thu, 07 Nov 2024 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Comment ingérer des données dans Elasticsearch via Apache Camel ?]]></title>
    <description><![CDATA[Apprenez à ingérer des données dans Elasticsearch via Apache Camel à l'aide d'un exemple pratique.]]></description>
    <content:encoded><![CDATA[<p>L'ingestion de données dans Elasticsearch à l'aide d'Apache Camel est un processus qui combine la robustesse d'un moteur de recherche et la flexibilité d'un cadre d'intégration. Dans cet article, nous allons voir comment Apache Camel peut simplifier et optimiser l'ingestion de données dans Elasticsearch. Pour illustrer cette fonctionnalité, nous allons mettre en œuvre une application d'introduction qui démontre, étape par étape, comment configurer et utiliser Apache Camel pour envoyer des données à Elasticsearch.</p><h2>Qu'est-ce qu'Apache Camel ?</h2><p>Apache Camel est un cadre d'intégration open-source qui simplifie la connexion de divers systèmes, permettant aux développeurs de se concentrer sur la logique commerciale sans se préoccuper des complexités de la communication entre les systèmes. Le concept central de Camel est "routes," qui définit le chemin suivi par un message de l'origine à la destination, en incluant éventuellement des étapes intermédiaires telles que des transformations, des validations et des filtrages.</p><h3>Architecture d'Apache Camel</h3><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt05652327efd4d5d1/6a17e6dafbc5f8a588491a8b/bef8145623a8fa80f929f9faa57ce0c460be2d0b-884x458.png" alt="Architecture d'Apache Camel" /><p>Camel utilise les composants "" pour se connecter à différents systèmes et protocoles, tels que les bases de données et les services de messagerie, et les points d'extrémité "" pour représenter les points d'entrée et de sortie des messages. Ces concepts offrent une conception modulaire et flexible, facilitant la configuration et la gestion d'intégrations complexes de manière efficace et évolutive.</p><h2>Utilisation d'Elasticsearch et d'Apache Camel</h2><p>Nous allons montrer comment configurer une application Java simple qui utilise Apache Camel pour ingérer des données dans un cluster Elasticsearch. Les processus de création, de mise à jour et de suppression de données dans Elasticsearch à l'aide de routes définies dans Apache Camel seront également abordés.</p><h3>1. Ajout de dépendances</h3><p>La première étape de la configuration de cette intégration consiste à ajouter les dépendances nécessaires au fichier <code>pom.xml</code> de votre projet. Cela inclut les bibliothèques Apache Camel et Elasticsearch. Nous utiliserons la nouvelle bibliothèque Java API Client, nous devons donc importer le composant <code>camel-elasticsearch</code> et la version doit être la même que celle de la bibliothèque <code>camel-core</code>.</p><p>Si vous souhaitez utiliser le Java Low level Rest Client, vous devez utiliser le composant Elasticsearch Low level Rest Client.</p>&lt;dependency&gt;
   &lt;groupId&gt;org.apache.camel&lt;/groupId&gt;
   &lt;artifactId&gt;camel-core&lt;/artifactId&gt;
   &lt;version&gt;4.7.0&lt;/version&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
   &lt;groupId&gt;org.apache.camel&lt;/groupId&gt;
   &lt;artifactId&gt;camel-elasticsearch&lt;/artifactId&gt;
   &lt;version&gt;4.7.0&lt;/version&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
   &lt;groupId&gt;org.apache.camel&lt;/groupId&gt;
   &lt;artifactId&gt;camel-jackson&lt;/artifactId&gt;
   &lt;version&gt;4.7.0&lt;/version&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
   &lt;groupId&gt;co.elastic.clients&lt;/groupId&gt;
   &lt;artifactId&gt;elasticsearch-java&lt;/artifactId&gt;
   &lt;version&gt;8.14.3&lt;/version&gt;
&lt;/dependency&gt;
<h3>2. Configuration et exécution du contexte Camel</h3><p>La configuration commence par la création d'un nouveau contexte Camel à l'aide de la classe <code>DefaultCamelContext</code>, qui sert de base à la définition et à l'exécution des itinéraires. Ensuite, nous configurons le composant Elasticsearch, qui permettra à Apache Camel d'interagir avec un cluster Elasticsearch. L'instance <code>ESlasticsearchComponent</code> est configurée pour se connecter à l'adresse <code>localhost:9200</code>, qui est l'adresse par défaut d'un cluster Elasticsearch local. Dans le cas d'un environnement nécessitant une authentification, il convient de lire la documentation relative à la configuration du composant et à l'activation de l'authentification de base, appelée <strong>". Configurer le composant et activer l'authentification de base"</strong>.</p>public class ESComponent {

    public static ElasticsearchComponent getInstance() {
        var elasticsearch = new ElasticsearchComponent();
        elasticsearch.setHostAddresses("localhost:9200");
        return elasticsearch;
    }

    public static String getName() {
        return "elasticsearch";
    }
}
<p>Ce composant est ensuite ajouté au contexte Camel, ce qui permet aux routes définies d'utiliser ce composant pour effectuer des opérations dans Elasticsearch.</p>try (var context = new DefaultCamelContext()) {
   context.addComponent(ESComponent.getName(), ESComponent.getInstance());
   context.addRoutes(new OperationBulkRoute());
   context.start();
}
<p>Ensuite, les itinéraires sont ajoutés au contexte. Nous allons créer des itinéraires pour l'indexation, la mise à jour et la suppression de documents en masse.</p><h3>3. Configuration des itinéraires Camel</h3><h4>Indexation des données</h4><p>La première route que nous allons configurer est destinée à l'indexation des données. Nous utiliserons un fichier JSON contenant un catalogue de films. La route sera configurée pour lire le fichier situé à l'adresse <a href="https://gist.github.com/andreluiz1987/40756874b5fbea0a29586f9376d7f1f4"><code>src/main/resources/movies.json</code></a>, désérialiser le contenu JSON en objets Java, puis appliquer une stratégie d'agrégation pour combiner plusieurs messages en un seul, permettant ainsi des opérations par lots dans Elasticsearch. La taille de 500 éléments par message a été configurée, c'est-à-dire que le bulk indexera 500 films à la fois.</p><p>Route Elasticsearch Operation Bulk</p>String URI_BULK_OPERATION = String
       .format("elasticsearch://elasticsearch?operation=%s&amp;indexName=%s",
               IndexOperationConfig.BULK_OPERATION,
               INDEX_NAME);
public class OperationBulkRoute extends RouteBuilder {
   private static final Log log = LogFactory.getLog(OperationBulkRoute.class);
   private static final int BULK_SIZE = 500;

   @Override
   public void configure() {
       from("file:src/main/resources?fileName=movies.json&amp;noop=true")
               .routeId("route-bulk-ingest")
               .unmarshal().json()
               .split(body())
               .aggregate(constant(true), new BulkAggregationStrategy())
               .completionSize(BULK_SIZE)
               .to(URI_BULK_OPERATION)
               .process(exchange -&gt; {
                   var body = exchange.getIn().getBody(String.class);
                   log.info(String.format("Response: %s", body));
               })
               .end();
   }
}
<p>Le lot de documents sera envoyé au point de terminaison de l'opération en bloc d'Elasticsearch. Cette approche garantit l'efficacité et la rapidité du traitement de grands volumes de données.</p><h4>Mise à jour des données</h4><p>La prochaine étape consistera à mettre à jour les documents. Nous avons indexé quelques films dans l'étape précédente et nous allons maintenant créer de nouvelles routes pour rechercher un document par code de référence et mettre à jour le champ "rating".</p><p>Nous mettons en place un contexte Camel <code>(DefaultCamelContext)</code>, dans lequel un composant Elasticsearch est enregistré et une route personnalisée IngestionRoute est ajoutée. L'opération commence par l'envoi du code du document par le ProducerTemplate, qui lance la route à partir du point de terminaison direct:update-ingestion.</p>try (var context = new DefaultCamelContext()) {
    context.addComponent(ESComponent.getName(), ESComponent.getInstance());
    context.addRoutes(new IngestionRoute());
    context.start();
    ProducerTemplate producerTemplate = context.createProducerTemplate();
    producerTemplate.sendBody("direct:update-ingestion", documentCode);
    Thread.sleep(5000);
}
<p>Ensuite, nous avons l'IngestionRoute, qui est le point d'entrée de ce flux. La route effectue plusieurs opérations en pipeline. Tout d'abord, une recherche dans Elasticsearch est effectuée pour localiser le document par code <code>(direct:search-by-id)</code>, où le SearchByCodeProcessor assemble la requête sur la base du code. Ensuite, le document récupéré est traité par l'UpdateRatingProcessor, qui convertit le résultat en objets Movie, met à jour la classification du film avec une valeur spécifique et prépare le document mis à jour à renvoyer à Elasticsearch pour la mise à jour.</p>public class IngestionRoute extends RouteBuilder {
    private static final Log log = LogFactory.getLog(IngestionRoute.class);

    @Override
    public void configure() throws Exception {

        from("direct:update-ingestion")
                .pipeline()
                .to("direct:search-by-id")
                .to(URI_SEARCH_OPERATION)
                .to("direct:update-rating")
                .to(URI_UPDATE_OPERATION)
                .process(exchange -&gt; {
                    var body = exchange.getIn().getBody(String.class);
                    log.info(String.format("Response: %s", body));
                })
                .end();

        from("direct:search-by-id")
                .process(new SearchByCodeProcessor());

        from("direct:update-rating")
                .process(new UpdateRatingProcessor());
    }
}
<p>Le processeur <code>SearchByCodeProcessor</code> a été configuré uniquement pour exécuter la requête de recherche :</p>public class SearchByCodeProcessor implements Processor {
    @Override
    public void process(Exchange exchange) throws Exception {
        var code = exchange.getIn().getBody();

        String query = "{\n" +
                "  \"query\": {\n" +
                "   \"term\": {\n" +
                "     \"code\": {\n" +
                "       \"value\":" + code + "\n" +
                "     }\n" +
                "   }\n" +
                "  }\n" +
                "}";
        exchange.setProperty("document_code", code);
        exchange.getIn().setBody(query);
    }
}
<p>Le processeur <code>UpdateRatingProcessor</code> est responsable de la mise à jour du champ "rating".</p>public class UpdateRatingProcessor implements Processor {

    private final ObjectMapper objectMapper;

    public UpdateRatingProcessor() {
        this.objectMapper = new ObjectMapper();
        this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    @Override
    public void process(Exchange exchange) throws Exception {

        HitsMetadata response = exchange.getIn().getBody(HitsMetadata.class);
        var code = Long.parseLong(exchange.getProperty("document_code").toString());

        if (response != null &amp;&amp; response.hits() != null) {

            var documents = parseToMovies(response);

            var optionalMovie = documents.stream()
                    .filter(document -&gt; code == (document.getSource().getCode())).findAny();

            optionalMovie.ifPresent(document -&gt; {
                document.getSource().setRating(13.0);
                Map&lt;String, Object&gt; updateMap = new HashMap&lt;&gt;();
                updateMap.put("doc", document.getSource());
                exchange.getIn().setHeader("indexId", document.getId());
                exchange.getIn().setBody(updateMap);
            });
        }
    }
<h4>Suppression des données</h4><p>Enfin, l'itinéraire de suppression des documents est configuré. Ici, nous allons supprimer un document en utilisant son ID. Dans Elasticsearch, pour supprimer un document, il faut connaître l'identifiant du document, l'index dans lequel le document est stocké et exécuter une requête Delete. Dans Apache Camel, nous effectuerons cette opération en créant une nouvelle route, comme indiqué ci-dessous.</p><p>L'itinéraire part du point d'arrivée direct:op-delete, qui sert de point d'entrée. Lorsqu'un document doit être supprimé, son identifiant <code>(_id)</code> est reçu dans le corps du message. La route définit ensuite l'en-tête indexId avec la valeur de cet identifiant en utilisant le simple<code>("${body}")</code>, qui extrait l'_id du corps du message.</p>public class OperationDeleteRoute extends RouteBuilder {
   private static final Log log = LogFactory.getLog(OperationDeleteRoute.class);

   @Override
   public void configure() {
       from("direct:op-delete")
               .routeId("route-delete")
               .setHeader("indexId", simple("${body}"))
               .to(URI_DELETE_OPERATION)
               .process(exchange -&gt; {
                   var body = exchange.getIn().getBody(String.class);
                   log.info(String.format("Response: %s", body));
               })
               .end();
       ;
   }
}
String URI_DELETE_OPERATION = String
       .format("elasticsearch://elasticsearch?operation=%s&amp;indexName=%s",
               IndexOperationConfig.DELETE_OPERATION,
               INDEX_NAME);
<p>Enfin, le message est dirigé vers le point de terminaison spécifié par URI_DELETE_OPERATION, qui se connecte à Elasticsearch pour effectuer l'opération de suppression du document dans l'index correspondant.
Maintenant que nous avons créé la route, nous pouvons créer un contexte Camel <code>(DefaultCamelContext)</code>, qui est configuré pour inclure le composant Elasticsearch.</p>try (var context = new DefaultCamelContext()) {
   context.addComponent(ESComponent.getName(), ESComponent.getInstance());
   context.addRoutes(new OperationDeleteRoute());
   context.start();
   ProducerTemplate producerTemplate = context.createProducerTemplate();
   producerTemplate.sendBody("direct:op-delete", documentId);
}
<p>Ensuite, la route de suppression, définie par la classe <code>OperationDeleteRoute</code>, est ajoutée au contexte. Une fois le contexte initialisé, une adresse <code>ProducerTemplate</code> est utilisée pour transmettre l'identifiant du document à supprimer à l'adresse <code>direct:op-delete</code>, qui déclenche la procédure de suppression.</p><h2>Conclusion</h2><p>L'intégration entre Apache Camel et Elasticsearch permet une ingestion robuste et efficace des données, en tirant parti de la flexibilité de Camel pour définir des itinéraires capables de gérer différents scénarios de manipulation des données, tels que l'indexation, la mise à jour et la suppression. Grâce à cette configuration, vous pouvez orchestrer et automatiser des processus complexes de manière évolutive, en veillant à ce que vos données soient gérées efficacement dans Elasticsearch. Cet exemple montre comment ces outils peuvent être utilisés ensemble pour créer une solution efficace et adaptable pour l'ingestion de données.</p><h2>Références</h2><ul><li><p><a href="https://camel.apache.org/manual/">Apache Camel</a></p></li><li><p><a href="https://camel.apache.org/manual/architecture.html">Architecture d'Apache Camel</a></p></li><li><p><a href="https://camel.apache.org/components/4.4.x/eips/aggregate-eip.html">Agrégation Apache Camel</a></p></li><li><p><a href="https://camel.apache.org/components/4.4.x/file-component.html">Composant du dossier</a></p></li><li><p><a href="https://camel.apache.org/components/4.4.x/elasticsearch-component.html">Composant Elasticsearch</a></p></li></ul>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-apache-camel-ingest-data</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-apache-camel-ingest-data</guid>
    <category><![CDATA[Indexer des données]]></category>
    <dc:creator><![CDATA[Andre Luiz]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt05652327efd4d5d1/6a17e6dafbc5f8a588491a8b/bef8145623a8fa80f929f9faa57ce0c460be2d0b-884x458.png" length="0" type="image/png"/>
    <pubDate>Mon, 09 Sep 2024 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>