<?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[Pertinence - 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[Pertinence - 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/blog/category/relevance</link>
    </image>
    <link>https://www.elastic.co/fr/search-labs/blog/category/relevance</link>
    <atom:link href="https://www.elastic.co/fr/search-labs/rss/category/relevance.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[fr]]></language>
    <lastBuildDate>Mon, 28 Sep 2026 07:34:07 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Garantir une précision sémantique avec un score minimum]]></title>
    <description><![CDATA[Améliorez la précision sémantique en utilisant des seuils de score minimum. Cet article présente des exemples concrets de recherche sémantique et hybride. ]]></description>
    <content:encoded><![CDATA[<p>La recherche sémantique a ouvert un monde d'opportunités pour améliorer la pertinence des recherches. Les modèles clairsemés et denses de haute qualité, tels qu'ELSER, E5 et Jina Embedding v4, renvoient des résultats pertinents en fonction du sens des mots, plutôt que de la correspondance de mots-clés. Cependant, la recherche sémantique renvoie parfois des résultats non pertinents en fin de liste ou pour des requêtes dont l'index ne contient aucun résultat pertinent. Cette caractéristique des modèles clairsemés et denses peut induire les utilisateurs en erreur ou gaspiller des jetons précieux pour les grands modèles de langage (LLM).</p><p>Dans cet article, vous apprendrez comment utiliser le paramètre de score minimum pour augmenter la précision de vos résultats de recherche sémantique. Si vous souhaitez tester les exemples fournis dans cet article de blog, accédez au <a href="https://github.com/elastic/elasticsearch-labs/blob/main/supporting-blog-content/ensuring-semantic-precision-with-minimum-score/ensuring_semantic_precision_with_minimum_score.ipynb">notebook Jupyter associé</a>.</p><h2>Contexte : précision et rappel</h2><p>En matière de pertinence de recherche, la <em>précision </em>et le <em>rappel </em>sont des concepts clés. Nous encourageons vivement les lecteurs qui ne les connaissent pas encore à se familiariser avec ces concepts. Voici un résumé.</p><ul><li><p><strong>Précision</strong> : la fraction des résultats de recherche renvoyés qui sont pertinents pour l'utilisateur.</p></li><li><p><strong>Rappel</strong> : la fraction de tous les documents pertinents du corpus inclus dans l'ensemble des résultats de recherche.</p></li></ul><p>En d'autres termes, la précision consiste à <strong>ne renvoyer </strong>que les résultats pertinents, tandis que le rappel consiste à <strong>renvoyer tous </strong>les résultats pertinents. Comme vous pouvez l'imaginer, ces deux exigences sont souvent contradictoires. La recherche sémantique a généralement un rappel très élevé, mais peut être à la peine en termes de précision. Poursuivez votre lecture pour découvrir comment contourner ce problème.</p><h2>Présentation du paramètre de score minimum</h2><p>Le paramètre "min_score" nous permet d'améliorer la précision en fixant un score minimum, ce qui tronquera le résultat en supprimant toutes les correspondances dont le score est inférieur au seuil défini. Voici un exemple simple :</p>GET search-movies/_search
{
  "retriever": {
    "linear": {
      "min_score": 4,
      "retrievers": [
        ...
      ]
    }
  }
}<h2>Normalisation du score</h2><p>Définir un score minimum est une bonne chose ; cependant, tous les modèles sémantiques ne renvoient pas un score adapté à un seuil statique. ELSER, par exemple, renvoie un score qui n'est pas limité. <a href="https://huggingface.co/intfloat/e5-small#faq">Certains</a> scores de modèles denses sont fortement regroupés et n'ont de sens que dans le contexte de la requête spécifique.</p><p>Pour la plupart des cas de recherche sémantique, nous recommandons d'utiliser une approche de normalisation avant d'appliquer le "min_score". La normalisation garantit que le score du document se situe dans un intervalle défini. Les extracteurs Elasticsearch proposent deux <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/retrievers/linear-retriever#linear-retriever-normalizers">normalisateurs</a> de ce type, "l2_norm" et "minmax". Le plus couramment utilisé est "minmax", car il est facile à comprendre et fonctionne bien dans de nombreux scénarios. Voici les principales propriétés de "minmax" :</p><ul><li><p>Les scores des documents sont distribués entre 0 et 1.</p></li><li><p>Le document ayant le score le plus élevé est toujours noté 1.</p></li><li><p>Le document ayant obtenu le score le plus bas est toujours noté 0.</p><ul><li><p>Cela peut le rendre moins adapté à la recherche par mots-clés. Voir la section "Recherche hybride" pour plus de détails.</p></li></ul></li></ul><p>Voici un exemple de requête sémantique normalisée avec <code>min_score</code>. La taille de la fenêtre de classement a été augmentée à 500 pour nous permettre de renvoyer une liste plus longue de résultats de recherche, en commençant à 100.</p>GET search-movies/_search
{
  "size": 100,
  "_source": [
    "title", "overview"
  ],
  "retriever": {
    "linear": {
      "rank_window_size": 500,
      "min_score": 0.25,
      "retrievers": [
        {
          "normalizer": "minmax",
          "retriever": {
            "standard": {
              "query": {
                "semantic": {
                  "field": "overview_vector",
                  "query": "superhero movie"
                }
              }
            }
          }
        }
      ]
    }
  }
}<p>La taille a été définie sur une valeur plus élevée que celle habituellement observée en production. Cela nous permet de contrôler la qualité des résultats de recherche et de les optimiser.</p><h2>Recherche hybride utilisant l'extracteur linéaire</h2><p>Pour la recherche hybride, l'approche la plus simple consiste à normaliser tous les scores, à leur attribuer des pondérations et à appliquer un score minimal. Notez qu'en choisissant des pondérations dont la somme est égale à 1, le score total reste compris entre 0 et 1. Cela facilite l'interprétation des scores finaux et l'ajustement de <code>min_score</code>. Voici un exemple :</p>GET search-movies/_search
{
  "size": 100,
  "_source": ["title", "overview","keywords"],
  "retriever": {
    "linear": {
      "rank_window_size": 500,
      "min_score": 0.25,
      "retrievers": [
        {
          "weight": 0.6,
          "normalizer": "minmax",
          "retriever": {
            "standard": {
              "query": {
                "semantic": {
                  "field": "overview_vector",
                  "query": "superhero movie"
                }
              }
            }
          }
        },
        {
          "weight": 0.4,
          "normalizer": "minmax",
          "retriever": {
            "standard": {
              "query": {
                "multi_match": {
                  "query": "superhero movie",
                  "fields": ["overview","keywords", "title"],
                  "type": "cross_fields",
                  "minimum_should_match": "2"
                }
              }
            }
          }
        }
      ]
    }
  }
}<h2>Recherche hybride à l'aide de la RRF</h2><p>Avec le BM25, nous contrôlons souvent la précision par d'autres moyens, par exemple en utilisant l'opérateur <code>AND</code> ou <code>minimum_should_match</code>. De plus, les requêtes composées de termes uniques, précis et rares entraîneront naturellement des résultats de recherche peu nombreux, souvent tous très pertinents. Cela peut causer les problèmes suivants :</p><ul><li><p>Les résultats situés plus loin dans le classement reçoivent un score normalisé faible dans l'extracteur BM25, même si le score BM25 absolu est proche des meilleurs résultats.</p></li><li><p>Si l'on ajoute un score BM25 très faible au score sémantique, le total peut être considéré comme le score sémantique.</p></li><li><p>L'absence de contribution au score BM25 peut entraîner la suppression du document par le <code>min_score threshold</code>.</p></li></ul><p>Comme solution, nous pouvons plutôt utiliser la fusion des rangs réciproques (RRF) pour combiner les résultats BM25 et sémantiques. RRF contourne la difficulté de comparer les scores de différents algorithmes de recherche en se concentrant plutôt sur la position dans chaque ensemble de résultats. Dans ce scénario, le <code>min_score</code> est uniquement appliqué à l'extracteur sémantique.</p>GET search-movies/_search
{
  "_source": ["title", "overview","keywords"],
  "retriever": {
    "rrf": {
      "rank_window_size": 500,
      "retrievers": [
        {
          "linear": {
            "rank_window_size": 500,
            "min_score": 0.25,
            "retrievers": [
              {
                "normalizer": "minmax",
                "retriever": {
                  "standard": {
                    "query": {
                      "semantic": {
                        "field": "overview_vector",
                        "query": "superhero movie"
                      }
                    }
                  }
                }
              }
            ]
          }
        },
        {
          "standard": {
            "query": {
              "multi_match": {
                "query": "superhero movie",
                "fields": ["overview", "keywords","title"],
                "type": "cross_fields",
                "minimum_should_match": "2"
              }
            }
          }
        }
      ]
    }
  }
}<h2>Conclusion</h2><p>En utilisant <code>min_score</code>, nous avons montré comment réduire le nombre de faux positifs dans nos ensembles de résultats causés par le fort rappel des algorithmes de recherche sémantique. Pour en savoir plus sur les extracteurs, veuillez consulter cet <a href="https://www.elastic.co/search-labs/blog/elasticsearch-retrievers">article de blog</a> et la <a href="https://www.elastic.co/docs/solutions/search/retrievers-overview">documentation d'Elasticsearch</a>.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/semantic-precision-minimum-score</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/semantic-precision-minimum-score</guid>
    <category><![CDATA[Pertinence]]></category>
    <category><![CDATA[Recherche hybride]]></category>
    <dc:creator><![CDATA[Mattias Brunnert]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd4a3fba607900049/6a170e0fcdacbf8fe17d2a7a/8b3b5910abfe16d48d309341a0027008b16c4340-720x420.jpg" length="0" type="image/jpeg"/>
    <pubDate>Fri, 20 Feb 2026 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Évaluer la pertinence des requêtes de recherche à l’aide de listes de jugement]]></title>
    <description><![CDATA[Découvrez comment créer des listes de jugement pour évaluer objectivement la pertinence des requêtes de recherche et améliorer des indicateurs de performance comme le rappel, dans le cadre de tests de recherche scalable avec Elasticsearch.]]></description>
    <content:encoded><![CDATA[<p>Les développeurs travaillant sur des moteurs de recherche rencontrent souvent le même problème : l’équipe métier n’est pas satisfaite d’un résultat de recherche, car les documents attendus en tête des résultats apparaissent en troisième ou quatrième position.</p><p>Mais en corrigeant ce cas précis, vous risquez de détériorer d’autres requêtes, faute de pouvoir tester chaque cas manuellement. Mais comment vérifier, vous ou votre équipe QA, si une modification d’une requête a un effet en cascade sur les autres ? Et surtout, comment s’assurer que les modifications apportées ont réellement amélioré une requête ?</p><h2>Vers une évaluation systématique</h2><p>C’est là que les listes de jugement prennent tout leur sens. Plutôt que de recourir à des tests manuels et subjectifs à chaque changement, vous pouvez définir un ensemble fixe de requêtes pertinentes pour votre cas d’usage, avec leurs résultats attendus.</p><p>Cet ensemble vous sert de référence. À chaque modification, vous l’utilisez pour déterminer si votre recherche s’est effectivement améliorée ou non.</p><p>Ce qui rend cette approche si précieuse :</p><ul><li><p><strong>Élimine l’incertitude</strong> : plus besoin de vous demander si vos changements impactent d’autres requêtes – les données vous le diront.</p></li><li><p><strong>Met fin aux tests manuels</strong> : une fois les ensembles de jugement enregistrés, le test devient automatique.</p></li><li><p><strong>Accompagne les changements</strong> : vous pouvez mettre en évidence des métriques claires qui confirment les bénéfices d’une modification.</p></li></ul><h2>Comment constituer votre liste de jugement</h2><p>L’une des façons les plus simples de commencer consiste à choisir une requête représentative et à sélectionner manuellement les documents pertinents. Deux approches sont possibles pour construire cette liste :</p><ul><li><p><strong>Jugements binaires :</strong> Chaque document associé à une requête reçoit une <strong>étiquette simple</strong> : <em>pertinent</em> (1) ou non pertinent (0).</p></li><li><p><strong>Jugements gradués :</strong> chaque document reçoit ici un score selon différents niveaux. Exemple : une échelle de 0 à 4, semblable à une <a href="https://en.wikipedia.org/wiki/Likert_scale">échelle de Likert</a>, où 0 signifie « pas du tout pertinent » et 4 « totalement pertinent », avec des nuances comme « pertinent », « plus ou moins pertinent », etc.</p></li></ul><p>Les jugements binaires sont adaptés lorsque l’intention de recherche est bien définie : ce document doit-il apparaître dans les résultats ou non ?</p><p>Les jugements gradués sont utiles lorsque la frontière est plus floue : certains résultats sont meilleurs que d’autres. On peut ainsi distinguer des résultats « très pertinents », « pertinents » ou « inutiles », et utiliser des métriques qui prennent en compte l’ordre des résultats ainsi que les retours des utilisateurs. Mais les échelles graduées présentent aussi des inconvénients : les évaluateurs peuvent interpréter différemment les niveaux de notation, ce qui nuit à la cohérence des jugements. De plus, comme les métriques graduées accordent plus de poids aux notes élevées, une légère variation (par exemple, noter 3 au lieu de 4) peut entraîner un changement bien plus important dans la métrique que ce que l’évaluateur avait anticipé. Cette part de subjectivité rend les jugements gradués plus bruyants et plus difficiles à gérer dans le temps.</p><h2>Dois-je classer les documents moi-même ?</h2><p>Pas forcément, car il existe plusieurs façons de créer votre liste de jugement, chacune avec ses avantages et ses inconvénients :</p><ul><li><p><strong>Jugements explicites :</strong> des experts métier examinent chaque couple requête/document et évaluent manuellement le niveau de pertinence. Cela garantit qualité et contrôle, mais c’est moins scalable.</p></li><li><p><strong>Jugements implicites :</strong> cette méthode déduit les documents pertinents à partir du comportement réel des utilisateurs : clics, taux de rebond, achats, etc. Elle permet de collecter automatiquement des données, mais celles-ci peuvent être biaisées. Par exemple, les utilisateurs ont tendance à cliquer plus souvent sur les premiers résultats, même s’ils ne sont pas pertinents.</p></li><li><p><strong>Jugements générés par l’IA :</strong> cette dernière option utilise des modèles (comme les LLM) pour évaluer automatiquement les requêtes et les documents – on parle souvent de<a href="https://en.wikipedia.org/wiki/LLM-as-a-Judge"> jurys LLM</a>. C’est rapide et facilement scalable, mais la qualité des données dépend du modèle utilisé et de la pertinence de ses données d’entraînement vis-à-vis de vos <a href="http://interests.as/">objectifs</a> métier. Comme pour les évaluations humaines, les jurys LLM peuvent introduire leurs propres biais ou incohérences. Il est donc essentiel de valider leurs résultats à l’aide d’un ensemble restreint de jugements de confiance. Les modèles LLM sont de nature probabiliste, il n’est donc pas rare de voir un modèle LLM attribuer des scores différents à un même résultat, même avec un paramètre de <a href="https://www.ibm.com/think/topics/llm-temperature">température</a> réglé sur 0.</p></li></ul><p>Voici quelques recommandations pour choisir la méthode la plus adaptée à la création de votre ensemble de jugement :</p><ul><li><p>Décidez des fonctionnalités critiques pour lesquelles seuls les utilisateurs peuvent vraiment juger (prix, marque, langue, style, détails du produit, etc.). Si ces éléments sont critiques, vous avez besoin de <strong>jugements explicites</strong> – au moins pour une partie de votre <em>liste de jugement</em>.</p></li><li><p>Utilisez des <strong>jugements implicites</strong> lorsque votre moteur de recherche génère déjà suffisamment de trafic pour que vous puissiez exploiter les clics, conversions et temps passés comme métriques de tendance. Il reste essentiel d’interpréter ces résultats avec prudence, en les comparant à des jugements explicites afin d’éviter tout biais (ex. : les utilisateurs ont tendance à cliquer sur les premiers résultats, même si des documents plus pertinents apparaissent plus bas).</p></li></ul><p>Pour y remédier, des techniques de réduction des biais de position permettent d’ajuster ou de repondérer les données de clics afin de mieux refléter l’intérêt réel des utilisateurs. Parmi les approches possibles :</p><ul><li><p><strong>Changement d’ordre des résultats</strong> : permet de modifier l’ordre des résultats de recherche pour un sous-ensemble d’utilisateurs afin d’évaluer l’effet de la position sur les clics.</p></li><li><p>Les <strong>modèles de clic</strong> incluent<a href="https://wiki.math.uwaterloo.ca/statwiki/index.php?title=a_Dynamic_Bayesian_Network_Click_Model_for_web_search_ranking"> : Dynamic Bayesian Network </a><a href="https://wiki.math.uwaterloo.ca/statwiki/index.php?title=a_Dynamic_Bayesian_Network_Click_Model_for_web_search_ranking"><strong>(DBN)</strong></a>, <a href="https://rsrikant.com/papers/kdd10.pdf">User Browsing Model</a> <a href="https://rsrikant.com/papers/kdd10.pdf"><strong>(UBM)</strong></a>, etc. Ces modèles statistiques estiment la probabilité qu’un clic reflète un véritable intérêt et non simplement une position dans la page, en prenant en compte des facteurs comme le défilement, la durée du clic, la séquence de navigation, et le retour aux résultats.</p></li></ul><h2>Exemple : application de notation de films</h2><h3>Produits requis</h3><p>Pour exécuter cet exemple, vous avez besoin d'un cluster Elasticsearch 8.x en cours d'exécution, <a href="https://www.elastic.co/downloads/elasticsearch">en local</a> ou sur <a href="https://www.elastic.co/cloud/cloud-trial-overview">Elastic Cloud Hosted</a> (hébergé ou sans serveur), ainsi que d'un accès à l'<a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis">API REST</a> ou à Kibana.</p><p>Imaginez une application dans laquelle les utilisateurs peuvent publier leurs avis sur des films et aussi rechercher des films à regarder. Comme ces textes sont rédigés par les utilisateurs eux-mêmes, ils peuvent contenir des fautes de frappe ou de nombreuses variations dans la façon de s’exprimer. Il est donc essentiel que le moteur de recherche puisse interpréter cette diversité et fournir des résultats utiles aux utilisateurs.</p><p>Afin de pouvoir tester différentes requêtes sans impacter le comportement global de la recherche, l’équipe métier de votre entreprise a créé l’ensemble de jugement binaire suivant, basé sur les recherches les plus fréquentes :</p><p>Requête</p><p>DocID</p><p>Texte</p><p>Performance de DiCaprio</p><p>doc1</p><p>La performance de DiCaprio dans The Revenant était époustouflante.</p><p>Performance de DiCaprio</p><p>doc2</p><p>Inception montre Leonardo DiCaprio dans l’un de ses rôles les plus emblématiques.</p><p>Performance de DiCaprio</p><p>doc3</p><p>Brad Pitt offre une performance solide dans ce thriller criminel.</p><p>Performance de DiCaprio</p><p>doc4</p><p>Une aventure riche en action avec des effets visuels impressionnants.</p><p>films tristes qui vous font pleurer</p><p>doc5</p><p>Une histoire bouleversante d’amour et de perte qui m’a fait pleurer pendant des heures.</p><p>films tristes qui vous font pleurer</p><p>doc6</p><p>Un des films les plus tristes jamais réalisés — apportez des mouchoirs !</p><p>films tristes qui vous font pleurer</p><p>doc7</p><p>Une comédie légère qui vous fera rire</p><p>films tristes qui vous font pleurer</p><p>doc8</p><p>Une épopée de science-fiction pleine d’action et de rebondissements.</p><p>Création de l'index :</p>PUT movies
{
  "mappings": {
    "properties": {
      "text": {
        "type": "text"
      }
    }
  }
}<p>Requête BULK :</p>POST /movies/_bulk
{ "index": { "_id": "doc1" } }
{ "text": "DiCaprio performance in The Revenant was breathtaking." }
{ "index": { "_id": "doc2" } }
{ "text": "Inception shows Leonardo DiCaprio in one of his most iconic roles." }
{ "index": { "_id": "doc3" } }
{ "text": "Brad Pitt delivers a solid performance in this crime thriller." }
{ "index": { "_id": "doc4" } }
{ "text": "An action-packed adventure with stunning visual effects." }
{ "index": { "_id": "doc5" } }
{ "text": "A heartbreaking story of love and loss that made me cry for hours." }
{ "index": { "_id": "doc6" } }
{ "text": "One of the saddest movies ever made -- bring tissues!" }
{ "index": { "_id": "doc7" } }
{ "text": "A lighthearted comedy that will make you laugh." }
{ "index": { "_id": "doc8" } }
{ "text": "A science-fiction epic full of action and excitement." }<p>Voici la requête Elasticsearch utilisée par l’application :</p>GET movies/_search
{
 "query": {
   "match": {
     "text": {
       "query": "DiCaprio performance",
       "minimum_should_match": "100%"
     }
   }
 }
}<h3>Du jugement aux métriques</h3><p>À elles seules, les listes de jugement fournissent peu d’informations : elles ne font qu’exprimer une attente vis-à-vis des résultats de nos requêtes. Elles révèlent tout leur intérêt lorsqu’elles servent à calculer des métriques objectives pour évaluer les performances de la recherche.</p><p>Aujourd’hui, la plupart des métriques les plus courantes incluent</p><ul><li><p><a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/search-rank-eval#k-precision"><strong>Précision</strong></a><strong> : </strong>mesure la proportion de résultats réellement pertinents parmi tous les résultats de recherche.</p></li><li><p><a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/search-rank-eval#k-recall"><strong>Rappel</strong></a><strong> : </strong>mesure la proportion de documents pertinents que le moteur de recherche a trouvés parmi tous les résultats.</p></li><li><p><a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/search-rank-eval#_discounted_cumulative_gain_dcg"><strong>Gain Cumulé Actualisé (DCG)</strong></a><strong> : </strong>mesure la qualité du classement des résultats, en tenant compte du fait que les documents les plus pertinents devraient apparaître en haut de la liste.</p></li><li><p><a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/search-rank-eval#_mean_reciprocal_rank"><strong>Rang réciproque moyen (MRR) :</strong></a> mesure la position du premier résultat pertinent. Plus un document est haut dans la liste, plus son score est élevé.</p></li></ul><p>En reprenant l’exemple de l’application de notation de films, nous allons calculer la métrique de rappel pour vérifier si des informations sont ignorées par nos requêtes.</p><p>Dans Elasticsearch, nous pouvons utiliser les <em>listes de jugement</em> pour calculer ces métriques via l’<a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/search-rank-eval">API Ranking Evaluation</a>. Cette API prend en entrée la liste de jugement, la requête et la métrique à évaluer, puis retourne une valeur qui correspond à une comparaison du résultat de la requête avec la liste de jugement.</p><p>Lançons la liste de jugement pour les deux requêtes dont nous disposons :</p>POST /movies/_rank_eval
{
 "requests": [
   {
     "id": "dicaprio-performance",
     "request": {
       "query": {
         "match": {
           "text": {
             "query": "DiCaprio performance",
             "minimum_should_match": "100%"
           }
         }
       }
     },
     "ratings": [
       {
         "_index": "movies",
         "_id": "doc1",
         "rating": 1
       },
       {
         "_index": "movies",
         "_id": "doc2",
         "rating": 1
       },
       {
         "_index": "movies",
         "_id": "doc3",
         "rating": 0
       },
       {
         "_index": "movies",
         "_id": "doc4",
         "rating": 0
       }
     ]
   },
   {
     "id": "sad-movies",
     "request": {
       "query": {
         "match": {
           "text": {
             "query": "sad movies that make you cry",
             "minimum_should_match": "100%"
           }
         }
       }
     },
     "ratings": [
       {
         "_index": "movies",
         "_id": "doc5",
         "rating": 1
       },
       {
         "_index": "movies",
         "_id": "doc6",
         "rating": 1
       },
       {
         "_index": "movies",
         "_id": "doc7",
         "rating": 0
       },
       {
         "_index": "movies",
         "_id": "doc8",
         "rating": 0
       }
     ]
   }
 ],
 "metric": {
   "recall": {
     "k": 10,
     "relevant_rating_threshold": 1
     }
 }
}<p>Nous allons utiliser deux requêtes avec rank_eval : une pour la requête sur DiCaprio et une autre pour les films tristes. Chaque requête est accompagnée de sa propre liste de jugement (notations). Il n’est pas nécessaire d’évaluer tous les documents : ceux qui ne figurent pas dans la liste de notation sont simplement considérés comme non jugés. Pour effectuer les calculs, la métrique de rappel ne prend en compte que l’« ensemble pertinent », c’est-à-dire les documents jugés pertinents dans l’évaluation.</p><p>Dans ce cas, la requête sur DiCaprio obtient un rappel de 1, tandis que celle sur les films tristes obtient 0. Autrement dit, nous avons récupéré tous les résultats pertinents pour la première requête, et aucun pour la seconde. Le rappel moyen est donc de 0,5.</p>{
 "metric_score": 0.5,
 "details": {
   "dicaprio-performance": {
     "metric_score": 1,
     "unrated_docs": [],
     "hits": [
       {
         "hit": {
           "_index": "movies",
           "_id": "doc1",
           "_score": 2.4826927
         },
         "rating": 1
       },
       {
         "hit": {
           "_index": "movies",
           "_id": "doc2",
           "_score": 2.0780432
         },
         "rating": 1
       }
     ],
     "metric_details": {
       "recall": {
         "relevant_docs_retrieved": 2,
         "relevant_docs": 2
       }
     }
   },
   "sad-movies": {
     "metric_score": 0,
     "unrated_docs": [],
     "hits": [],
     "metric_details": {
       "recall": {
         "relevant_docs_retrieved": 0,
         "relevant_docs": 2
       }
     }
   }
 },
 "failures": {}
}<p>Peut-être que nous sommes trop stricts avec le paramètre minimum_should_match : en exigeant que 100 % des mots de la requête soient présents dans les documents, nous risquons d’écarter des résultats pertinents. Supprimons le paramètre <strong>minimum_should_match</strong>, afin qu’un document soit considéré comme pertinent dès qu’un seul mot de la requête est présent.</p>POST /movies/_rank_eval
{
 "requests": [
   {
     "id": "dicaprio-performance",
     "request": {
       "query": {
         "match": {
           "text": {
             "query": "DiCaprio performance"
           }
         }
       }
     },
     "ratings": [
       {
         "_index": "movies",
         "_id": "doc1",
         "rating": 1
       },
       {
         "_index": "movies",
         "_id": "doc2",
         "rating": 1
       },
       {
         "_index": "movies",
         "_id": "doc3",
         "rating": 0
       },
       {
         "_index": "movies",
         "_id": "doc4",
         "rating": 0
       }
     ]
   },
   {
     "id": "sad-movies",
     "request": {
       "query": {
         "match": {
           "text": {
             "query": "sad movies that make you cry"
           }
         }
       }
     },
     "ratings": [
       {
         "_index": "movies",
         "_id": "doc5",
         "rating": 1
       },
       {
         "_index": "movies",
         "_id": "doc6",
         "rating": 1
       },
       {
         "_index": "movies",
         "_id": "doc7",
         "rating": 0
       },
       {
         "_index": "movies",
         "_id": "doc8",
         "rating": 0
       }
     ]
   }
 ],
 "metric": {
   "recall": {
     "k": 10,
     "relevant_rating_threshold": 1
     }
 }
}<p>Comme vous pouvez le constater, en supprimant le paramètre <strong>minimum_should_match</strong> dans l'une des deux requêtes, nous obtenons maintenant un rappel moyen de 1 dans les deux cas.</p>{
  "metric_score": 1,
  "details": {
    "dicaprio-performance": {
      "metric_score": 1,
      "unrated_docs": [],
      "hits": [
        {
          "hit": {
            "_index": "movies",
            "_id": "doc1",
            "_score": 2.0661702
          },
          "rating": 1
        },
        {
          "hit": {
            "_index": "movies",
            "_id": "doc3",
            "_score": 0.732218
          },
          "rating": 0
        },
        {
          "hit": {
            "_index": "movies",
            "_id": "doc2",
            "_score": 0.6271719
          },
          "rating": 1
        }
      ],
      "metric_details": {
        "recall": {
          "relevant_docs_retrieved": 2,
          "relevant_docs": 2
        }
      }
    },
    "sad-movies": {
      "metric_score": 1,
      "unrated_docs": [],
      "hits": [
        {
          "hit": {
            "_index": "movies",
            "_id": "doc7",
            "_score": 2.1307156
          },
          "rating": 0
        },
        {
          "hit": {
            "_index": "movies",
            "_id": "doc5",
            "_score": 1.3160692
          },
          "rating": 1
        },
        {
          "hit": {
            "_index": "movies",
            "_id": "doc6",
            "_score": 1.190063
          },
          "rating": 1
        }
      ],
      "metric_details": {
        "recall": {
          "relevant_docs_retrieved": 2,
          "relevant_docs": 2
        }
      }
    }
  },
  "failures": {}
}<p>En résumé, supprimer la clause minimum_should_match : 100 % permet d’obtenir un rappel parfait pour les deux requêtes.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltaf4f08a8a2915180/6a170df61949f76cbfe7aaba/24d055da4348c63827ba7046fe8cafb6f47cadd8-546x628.png" alt="" /><p>Nous l'avons fait ! N'est-ce pas ?</p><p>Pas si vite !</p><p>En augmentant le rappel, on élargit la gamme des résultats possibles. Cependant, chaque ajustement implique un compromis. D’où l’importance de définir des cas de test complets, en utilisant plusieurs métriques pour évaluer les changements.</p><p>Les listes de jugement et les métriques vous évitent d’avancer à l’aveugle lorsque vous apportez des modifications, car vous disposez désormais de données pour les justifier. La validation n’est plus manuelle ni répétitive, et vous pouvez tester vos changements sur plusieurs cas d’usage, et non plus un seul. Les tests A/B vous permettent également de tester en conditions réelles la configuration qui convient le mieux à vos utilisateurs et à votre cas d’utilisation, bouclant ainsi la boucle entre métriques techniques et résultats concrets.</p><h2>Recommandations finales pour l’utilisation des listes de jugement</h2><p>Travailler avec des listes de jugement ne consiste pas seulement à mesurer : c’est aussi construire un cadre vous permettant d’itérer en toute confiance. Pour y parvenir, voici quelques recommandations :</p><ol><li><p><strong>Démarrez petit, mais démarrez</strong>. Il n’est pas nécessaire d’avoir 10 000 requêtes avec 50 listes de jugement chacune. Vous devez seulement identifier les 5 à 10 requêtes les plus critiques pour votre cas d’utilisation, et définir les documents que vous attendez en haut des résultats. Cela vous donne déjà une base de travail. En général, on commence par les principales requêtes et celles qui ne renvoient aucun résultat. Vous pouvez aussi tester en partant d’une métrique simple comme la précision, puis monter en complexité.</p></li><li><p><strong>Validez avec les utilisateurs.</strong> Complétez les résultats chiffrés par des tests A/B en production. De cette façon, vous saurez si les modifications prometteuses dans les métriques ont aussi un véritable impact.</p></li><li><p><strong>Gardez la liste vivante.</strong> Votre cas d’utilisation évoluera, tout comme vos requêtes critiques. Mettez régulièrement à jour votre liste de jugement pour refléter les nouveaux besoins.</p></li><li><p><strong>Intégrez-la à vos workflows.</strong> Intégrez les listes de jugement dans vos pipelines de développement. Assurez-vous que chaque modification de configuration, de synonymes ou d’analyse de texte soit automatiquement validée à partir de votre liste de référence.</p></li><li><p><strong>Connectez les savoir-faire techniques à la stratégie.</strong> Ne vous limitez pas à des métriques techniques comme la précision ou le rappel. Utilisez les résultats d’évaluation pour éclairer vos décisions métier.</p></li></ol>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/judgment-lists-search-query-relevance-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/judgment-lists-search-query-relevance-elasticsearch</guid>
    <category><![CDATA[Pertinence]]></category>
    <category><![CDATA[À l'intérieur d'Elastic]]></category>
    <dc:creator><![CDATA[Jhon Guzmán]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcadfd2fb1cc95b4c/6a170df7acf0887798be9bd0/25478d0ffb228afd5d65d82312998ec1c299c565-700x490.png" length="0" type="image/png"/>
    <pubDate>Thu, 11 Dec 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[La recherche hybride sans prise de tête : simplifier la recherche hybride avec des extracteurs]]></title>
    <description><![CDATA[Découvrez comment simplifier la recherche hybride dans Elasticsearch avec un format de requête à champs multiples pour les extracteurs linéaires et RRF, et créez des requêtes sans aucune connaissance préalable de votre index Elasticsearch.]]></description>
    <content:encoded><![CDATA[<p>La <a href="https://www.elastic.co/what-is/hybrid-search">recherche hybride</a> est largement reconnue comme une approche de recherche puissante, combinant la précision et la vitesse de la <a href="https://www.elastic.co/search-labs/blog/lexical-and-semantic-search-with-elasticsearch#lexical-search---sparse-retrieval">recherche lexicale</a> avec les capacités de langage naturel de la <a href="https://www.elastic.co/what-is/semantic-search">recherche sémantique</a>. Cependant, son application pratique peut s'avérer délicate, nécessitant souvent une connaissance approfondie de votre index et la construction de requêtes verbeuses avec des configurations non triviales. Dans ce blog, nous allons voir comment le <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/retrievers#multi-field-query-format">format de requête multi-champs pour les extracteurs linéaires et RRF</a> rend la recherche hybride plus simple et plus accessible, en éliminant les maux de tête courants et en vous permettant de tirer parti de toute sa puissance avec plus de facilité. Nous verrons également comment le format d'interrogation à champs multiples vous permet d'effectuer des recherches hybrides sans aucune connaissance préalable de votre index.</p><h2>Le problème de l'étendue des scores</h2><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3521a6558cd477ca/6a17f174445de94d3c4d0225/c8b49153c47d2cdc233c0d2e440db04711d48ca5-1600x1600.jpg" alt="" /><p>Pour préparer le terrain, examinons l'une des principales raisons pour lesquelles la recherche hybride peut s'avérer difficile : la variation des fourchettes de scores. Notre vieil ami <a href="https://www.elastic.co/elasticon/conf/2016/sf/improved-text-scoring-with-bm25">BM25</a> produit des scores non bornés. En d'autres termes, BM25 peut générer des scores allant de près de 0 à (théoriquement) l'infini. En revanche, les requêtes portant sur les champs <code>dense_vector</code> produiront des scores limités entre 0 et 1. Pour aggraver ce problème, <code>semantic_text</code> obscurcit le type de champ utilisé pour indexer les embeddings, de sorte qu'à moins d'avoir une connaissance détaillée de la configuration de votre index et de votre point de terminaison d'inférence, il peut être difficile de savoir quelle sera la plage de scores de votre requête. Cela pose un problème lorsqu'on essaie d'intercaler des résultats de recherche lexicaux et sémantiques, car les résultats lexicaux peuvent prendre le pas sur les résultats sémantiques, même si ces derniers sont plus pertinents. La solution généralement acceptée pour ce problème est de normaliser les scores avant d'entrelacer les résultats. Elasticsearch dispose de deux outils pour cela, les extracteurs <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/retrievers/linear-retriever">linéaires</a> et <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/retrievers/rrf-retriever">RRF</a>.
</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt09ed6bf3d25066bd/6a17f1750b0bedbd70dd3686/264481268c8b6ac259e3c257b85431b513f16672-1077x586.png" alt="Comparaison des résultats de recherche avec linéaire/rrf et sans linéaire/rrf" /><p>Le récupérateur <strong>RRF</strong> applique l'<a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/reciprocal-rank-fusion">algorithme RRF</a>, en utilisant le rang du document comme mesure de la pertinence et en écartant le score. Étant donné que le score n'est pas pris en compte, les écarts de score ne posent pas de problème.</p><p>L'extracteur <strong>linéaire</strong> utilise une combinaison linéaire pour déterminer le score final d'un document. Il s'agit de prendre le score de chaque composante de la requête pour le document, de le normaliser et de l'additionner pour obtenir le score total. Mathématiquement, l'opération peut être exprimée comme suit :</p>Total Score = 𝚺(N(Sx))<p>Où <code>N</code> est la fonction de normalisation et SX est le score de la requête X. La fonction de normalisation est essentielle ici, car elle transforme le score de chaque requête pour utiliser le même intervalle. Pour en savoir plus sur le retriever linéaire <a href="https://www.elastic.co/search-labs/blog/linear-retriever-hybrid-search">, cliquez ici.</a></p><h2>La décomposition</h2><p>Les utilisateurs peuvent mettre en œuvre une recherche hybride efficace à l'aide de ces outils, mais cela nécessite une certaine connaissance de votre index. Prenons un exemple avec l'extracteur linéaire, où nous allons interroger un index avec deux champs :</p>PUT linear_retriever_example
{
  "mappings": {
    "properties": {
      "semantic_text_field": { &lt;1&gt;
        "type": "semantic_text",
        "inference_id": ".multilingual-e5-small-elasticsearch"
      },
      "text_field": { &lt;2&gt;
        "type": "text"
      }
    }
  }
}<p>1. <code>semantic_text_field</code> est un champ <code>semantic_text</code> qui utilise <a href="https://www.elastic.co/docs/explore-analyze/machine-learning/nlp/ml-nlp-e5">E5</a>, un modèle d'intégration de texte.</p><p>2. <code>text_field</code> est un champ standard <code>text</code></p>GET linear_retriever_example/_search
{
  "retriever": {
    "linear": {
      "retrievers": [
        {
          "retriever": {
            "standard": {
              "query": {
                "match": { &lt;1&gt;
                  "semantic_text_field": "foo"
                }
              }
            }
          },
          "normalizer": "minmax"
        },
        {
          "retriever": {
            "standard": {
              "query": {
                "match": {
                  "text_field": "foo"
                }
              }
            }
          },
          "normalizer": "minmax"
        }
      ]
    }
  }
}<p>1. Nous utilisons une requête <code>match</code> sur notre champ <code>semantic_text</code>, dont <a href="https://www.elastic.co/search-labs/blog/semantic-search-match-knn-sparse-vector#we-made-match-happen-in-semantic-search!">la prise en charge a été ajoutée dans Elasticsearch 8.18/9.0.</a></p><p>
Lors de la construction de la requête, nous devons garder à l'esprit que <code>semantic_text_field</code> utilise un modèle d'intégration de texte, de sorte que toute requête sur ce site générera un score entre 0 et 1. Nous devons également savoir que <code>text_field</code> est un champ standard de <code>text</code> et que les requêtes sur ce champ génèreront donc un score non borné. Pour créer un ensemble de résultats pertinents, nous devons utiliser un extracteur qui normalisera les résultats des requêtes avant de les combiner. Dans cet exemple, nous utilisons l'extracteur linéaire avec la normalisation <code>minmax</code>, qui normalise le score de chaque requête à une valeur comprise entre 0 et 1.</p><p>La construction de la requête dans cet exemple est assez simple car seuls deux champs sont concernés. Toutefois, la situation peut se compliquer très rapidement à mesure que l'on ajoute d'autres champs, de types différents. Cela démontre que la rédaction d'une requête de recherche hybride efficace nécessite souvent une connaissance plus approfondie de l'index interrogé, afin que les scores des composantes de la requête soient correctement normalisés avant d'être combinés. Cela constitue un obstacle à l'adoption plus large de la recherche hybride.</p><h3>Regroupement de requêtes</h3><p>Étendons l'exemple : Et si nous voulions interroger un champ <code>text</code> et deux champs <code>semantic_text</code>? Nous pourrions construire une requête comme celle-ci :</p>GET linear_retriever_example/_search
{
  "retriever": {
    "linear": {
      "retrievers": [
        {
          "retriever": {
            "standard": {
              "query": {
                "semantic": {
                  "field": "semantic_text_field_1",
                  "query": "foo"
                }
              }
            }
          },
          "normalizer": "minmax"
        },
        {
          "retriever": {
            "standard": {
              "query": {
                "semantic": {
                  "field": "semantic_text_field_2",
                  "query": "foo"
                }
              }
            }
          },
          "normalizer": "minmax"
        },
        {
          "retriever": {
            "standard": {
              "query": {
                "match": {
                  "text_field": "foo"
                }
              }
            }
          },
          "normalizer": "minmax"
        }
      ]
    }
  }
}<p>Cela semble être une bonne chose à première vue, mais il y a un problème potentiel. Désormais, les matchs sur le terrain <code>semantic_text</code> représentent ⅔ du score total :</p>Total Score = N(semantic_text_field_1 score) + N(semantic_text_field_2 score) + N(text_field score)<p>Ce n'est probablement pas ce que vous souhaitez, car cela crée un score déséquilibré. Les effets ne sont peut-être pas très visibles dans un exemple comme celui-ci, qui ne comporte que trois champs, mais ils deviennent problématiques lorsqu'un plus grand nombre de champs sont interrogés. Par exemple, la plupart des index contiennent beaucoup plus de champs lexicaux que de champs sémantiques (c.-à-d. <code>dense_vector</code>, <code>sparse_vector</code>, ou <code>semantic_text</code>). Que se passerait-il si nous interrogions un index comportant 9 champs lexicaux et 1 champ sémantique en utilisant le modèle ci-dessus ? Les correspondances lexicales représenteraient 90% du score, ce qui réduirait l'efficacité de la recherche sémantique.</p><p>Une solution courante consiste à regrouper les requêtes en catégories lexicales et sémantiques et à pondérer les deux de manière égale. Cela permet d'éviter que l'une ou l'autre catégorie ne domine le score total.</p><p>Mettons cela en pratique. À quoi ressemblerait cette approche de requêtes groupées pour cet exemple en utilisant l'outil de recherche linéaire ?</p>GET linear_retriever_example/_search
{
  "retriever": {
    "linear": {
      "retrievers": [
        {
          "retriever": {
            "linear": {
              "retrievers": [
                {
                  "retriever": {
                    "standard": {
                      "query": {
                        "semantic": {
                          "field": "semantic_text_field_1",
                          "query": "foo"
                        }
                      }
                    }
                  },
                  "normalizer": "minmax"
                },
                {
                  "retriever": {
                    "standard": {
                      "query": {
                        "semantic": {
                          "field": "semantic_text_field_2",
                          "query": "foo"
                        }
                      }
                    }
                  },
                  "normalizer": "minmax"
                }
              ]
            }
          },
          "normalizer": "minmax"
        },
        {
          "retriever": {
            "standard": {
              "query": {
                "match": {
                  "text_field": "foo"
                }
              }
            }
          },
          "normalizer": "minmax"
        }
      ]
    }
  }
}<p>Wow, ça devient verbeux ! Vous avez peut-être même dû faire défiler l'écran de haut en bas plusieurs fois pour examiner l'ensemble de la requête ! Ici, nous utilisons deux niveaux de normalisation pour créer les groupes de requêtes. Mathématiquement, elle peut être exprimée comme suit :</p>Total Score = N(N(semantic_text_field_1 score) + N(semantic_text_field_2 score)) + N(text_field score)<p>Ce deuxième niveau de normalisation garantit que les requêtes portant sur les champs <code>semantic_text</code> et <code>text</code> sont pondérées de manière égale. Notez que nous omettons la normalisation de second niveau pour <code>text_field</code> dans cet exemple puisqu'il n'y a qu'un seul champ lexical, ce qui vous évite <em>encore plus</em> de verbosité.</p><p>Cette structure d'interrogation est déjà lourde, et nous n'interrogeons que trois champs. Il devient de plus en plus difficile à gérer, même pour les praticiens chevronnés de la recherche, au fur et à mesure que l'on interroge davantage de champs.</p><h2>Le format d'interrogation à champs multiples</h2><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt5d9007d279f0da29/6a17f17714d90c39cf79b6f5/dd04e1686076a574b717c1460acfe4eb79299208-1600x1600.jpg" alt="" /><p>Nous avons ajouté le <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/retrievers#multi-field-query-format">format de requête multi-champs</a> pour les extracteurs linéaires et RRF dans Elasticsearch 8.19, 9.1 et <a href="https://www.elastic.co/cloud/serverless">serverless</a> pour simplifier tout cela. Vous pouvez maintenant effectuer la même requête que ci-dessus avec just :</p>GET linear_retriever_example/_search
{
  "retriever": {
    "linear": {
      "fields": [ "semantic_text_field_1", "semantic_text_field_2", "text_field" ],
      "query": "foo",
      "normalizer": "minmax"
    }
  }
}<p>Ce qui réduit la requête de 55 lignes à seulement 9 ! Elasticsearch utilise automatiquement les mappages d'index pour :</p><ul><li><p>Déterminer le type de chaque champ interrogé</p></li><li><p>Regrouper chaque champ dans une catégorie lexicale ou sémantique</p></li><li><p>Pondérer chaque catégorie de manière égale dans la note finale</p></li></ul><p>Cela permet à n'importe qui d'exécuter une requête de recherche hybride efficace sans avoir besoin de connaître les détails de l'index ou les points de terminaison d'inférence utilisés.</p><p>Lorsque vous utilisez la méthode RRF, vous pouvez omettre le site <code>normalizer</code>, car le rang est utilisé comme indicateur de la pertinence :</p>GET rrf_retriever_example/_search
{
  "retriever": {
    "rrf": {
      "fields": [ "semantic_text_field_1", "semantic_text_field_2", "text_field" ],
      "query": "foo"
    }
  }
}<h2>Renforcement par champ</h2><p>Lors de l'utilisation de l'extracteur linéaire, vous pouvez appliquer un boost par champ pour ajuster l'importance des correspondances dans certains champs. Par exemple, disons que vous interrogez quatre champs : deux champs <code>semantic_text</code> et deux champs <code>text</code>:</p>GET linear_retriever_example/_search
{
  "retriever": {
    "linear": {
      "fields": [ "semantic_text_field_1", "semantic_text_field_2", "text_field_1", "text_field_2" ],
      "query": "foo",
      "normalizer": "minmax"
    }
  }
}<p>Par défaut, chaque champ est pondéré de manière égale dans son groupe (lexical ou sémantique). La répartition des points est la suivante :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltdc6e197e5ff7b68d/6a17f179505ac32834ad8c46/ba31c76189e3a1e5b1638437ccf0528aafec2598-1600x549.png" alt="Comparaison des groupes d'interrogation et des scores sur le terrain" /><p>En d'autres termes, chaque champ représente 25% du score total.</p><p>Nous pouvons utiliser la syntaxe <code>field^boost</code> pour ajouter un boost par champ à n'importe quel champ. Appliquons un boost de 2 à <code>semantic_text_field_1</code> et <code>text_field_1</code>:</p>GET linear_retriever_example/_search
{
  "retriever": {
    "linear": {
      "fields": [ "semantic_text_field_1^2", "semantic_text_field_2", "text_field_1^2", "text_field_2" ]
      "query": "foo",
      "normalizer": "minmax"
    }
  }
}<p>La répartition des points est maintenant la suivante :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltccc9ed7d6e865a5e/6a17f17abe6086a31d004882/de20e555d52f914bf483a048d056f54f4fece757-1600x549.png" alt="Modification du poids des champs avec la recherche par réf. et la recherche hybride" /><p>Chaque groupe de requêtes est toujours pondéré de manière égale, mais la pondération des champs à l'intérieur des groupes a changé :</p><ul><li><p><code>semantic_text_field_1</code> est 66% du score du groupe de requêtes sémantiques, 33% du score total</p></li><li><p><code>text_field_1</code> est 66% du score du groupe de requêtes lexicales, 33% du score total</p></li></ul><p>ℹ️ Notez que la fourchette de score total ne changera pas lorsqu'une majoration par champ est appliquée. Il s'agit d'un effet secondaire voulu de la normalisation des scores, qui garantit que les scores des requêtes lexicales et sémantiques restent directement comparables entre eux.</p><p>ℹ️ Le boosting par champ peut également être utilisé avec le récupérateur RRF dans Elasticsearch 9.2+.</p><h3>Résolution sur les caractères génériques</h3><p>Vous pouvez utiliser le caractère générique <code>*</code> dans le paramètre <code>fields</code> pour faire correspondre plusieurs champs. Si l'on reprend l'exemple ci-dessus, cette requête est fonctionnellement équivalente à l'interrogation explicite des sites<code>emantic_text_field_1</code>, <code>semantic_text_field_2</code> et <code>text_field_1</code>:</p>GET linear_retriever_example/_search
{
  "retriever": {
    "linear": {
      "fields": [ "semantic_text_field_*", "*_field_1" ],
      "query": "foo",
      "normalizer": "minmax"
    }
  }
}<p>Il est intéressant de noter que le modèle <code>*_field_1</code> correspond à la fois à <code>text_field_1</code> et à <code>semantic_text_field_1</code>. La requête sera exécutée comme si chacun des champs avait été explicitement interrogé. Le fait que le site <code>semantic_text_field_1</code> corresponde aux deux modèles ne pose pas de problème ; tous les noms de champ correspondant sont dédupliqués avant l'exécution de la requête.</p><p>Vous pouvez utiliser les caractères génériques de différentes manières :</p><ul><li><p>Correspondance des préfixes (ex : <code>*_text_field</code>)</p></li><li><p>Correspondance en ligne (ex : <code>semantic_*_field</code>)</p></li><li><p>Correspondance des suffixes (ex : <code>semantic_text_field_*</code>)</p></li></ul><p>Vous pouvez également utiliser plusieurs caractères génériques pour appliquer une combinaison des éléments ci-dessus, par exemple <code>*_text_field_*</code>.</p><h3>Champs de requête par défaut</h3><p>Le format d'interrogation à champs multiples vous permet également d'interroger un index dont vous ignorez tout. Si vous omettez le paramètre <code>fields</code>, il interrogera tous les champs spécifiés par le <a href="https://www.elastic.co/docs/reference/elasticsearch/index-settings/index-modules">paramètre d'indexation index.query.default_field</a>:</p>GET linear_retriever_example/_search
{
  "retriever": {
    "linear": {
      "query": "foo",
      "normalizer": "minmax"
    }
  }
}<p>Par défaut, <code>index.query.default_field</code> est défini comme <code>*</code>. Ce caractère générique permet de résoudre tous les types de champs de l'index qui prennent en charge les requêtes de termes, ce qui est le cas de la plupart d'entre eux. Les exceptions sont les suivantes :</p><ul><li><p><code>dense_vector</code> champs</p></li><li><p><code>rank_vector</code> champs</p></li><li><p>Champs de géométrie : <code>geo_point</code>, <code>shape</code></p></li></ul><p>Cette fonctionnalité est particulièrement utile lorsque vous souhaitez effectuer une recherche hybride sur un index fourni par un tiers. Le format d'interrogation à champs multiples vous permet d'exécuter une requête appropriée de manière simple. Il suffit d'exclure le paramètre <code>fields</code> pour que tous les champs applicables soient interrogés.</p><h2>Conclusion</h2><p>Le problème de la plage de scores peut faire de la recherche hybride efficace un casse-tête à mettre en œuvre, en particulier lorsque l'on ne dispose que de peu d'informations sur l'index interrogé ou sur les points de terminaison d'inférence utilisés. Le format d'interrogation à champs multiples pour les extracteurs linéaires et RRF atténue cette difficulté en intégrant une approche de recherche hybride automatisée, basée sur le regroupement de requêtes, dans une API simple et facile d'accès. Des fonctionnalités supplémentaires, telles que le renforcement par champ, la résolution des caractères génériques et les champs de requête par défaut, permettent d'étendre les fonctionnalités à de nombreux cas d'utilisation.</p><h2>Essayez le format d'interrogation à champs multiples dès aujourd'hui</h2><p>Vous pouvez tester les extracteurs linéaires et RRF avec le format de requête multi-champs dans des projets Elasticsearch <a href="https://www.elastic.co/cloud/serverless">Serverless</a> entièrement gérés avec un <a href="https://www.elastic.co/docs/deploy-manage/deploy/elastic-cloud/create-serverless-project">essai gratuit</a>. Il est également disponible en version stack à partir de 8.19 &amp; 9.1.</p><p>Démarrez en quelques minutes sur votre environnement local à l'aide d'une simple commande :</p>curl -fsSL https://elastic.co/start-local | sh<p></p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/hybrid-search-multi-field-query-retrievers-elasticsearch</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/hybrid-search-multi-field-query-retrievers-elasticsearch</guid>
    <category><![CDATA[Recherche hybride]]></category>
    <category><![CDATA[Pertinence]]></category>
    <dc:creator><![CDATA[Mike Pellegrini]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt89e066372c549595/6a17f17c3e9e457c38ba1583/4494f98ae3958bbdbc6171df9677fc4d65ec5640-1536x1024.png" length="0" type="image/png"/>
    <pubDate>Thu, 27 Nov 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Vous savez, pour le contexte - Partie I : L'évolution de la recherche hybride et de l'ingénierie contextuelle]]></title>
    <description><![CDATA[Découvrez comment la recherche hybride et l'ingénierie contextuelle ont évolué à partir de bases lexicales pour permettre la prochaine génération de flux de travail d'IA agentique.]]></description>
    <content:encoded><![CDATA[<h2>Notre tout nouveau monde d'IA agentique</h2><p>Comme beaucoup d'entre nous, je suis à la fois heureux et étonné du rythme auquel les capacités de l'IA évoluent. Les grands modèles de langage (LLM) et la recherche vectorielle nous ont d'abord lancés dans la révolution sémantique, où nous ne cherchions plus à trouver des choses à l'aide de mots-clés. Ensuite, les LLM nous ont montré de nouvelles façons d'interagir avec nos données, en utilisant des interfaces de chat pour transformer les demandes en langage naturel en réponses qui distillent de vastes bases de connaissances en résumés facilement consommables. Nous avons maintenant (déjà !) ont les prémices d'une logique automatisée pilotée par le LLM sous la forme de flux de travail "d'IA agentique" qui peuvent comprendre sémantiquement une demande entrante, raisonner sur les étapes à suivre, puis choisir parmi les outils disponibles pour exécuter itérativement des actions afin d'atteindre ces objectifs.</p><p>La promesse de l'IA agentique nous oblige à évoluer et à ne plus utiliser principalement l'"ingénierie de l'invite" pour façonner nos interactions génératives avec l'IA, mais à nous concentrer sur la manière dont nous pouvons aider les outils agentiques à obtenir les informations supplémentaires les plus pertinentes et les plus efficaces que le LLM doit prendre en compte lorsqu'il génère ses réponses - l'"ingénierie du contexte" est la prochaine frontière. La recherche hybride est de loin le moyen le plus puissant et le plus souple de faire apparaître un contexte pertinent, et la plateforme Search AI d'Elastic ouvre une toute nouvelle voie pour exploiter les données au service de l'ingénierie contextuelle. Dans cet article, nous allons examiner comment les LLM ont changé le monde de la recherche d'informations sous deux angles, puis comment ils peuvent travailler ensemble pour obtenir de meilleurs résultats. Il y a beaucoup de chemin à parcourir...</p><h2>Partie I : Comment les LLM ont changé la recherche</h2><p>Commençons par la façon dont les LLM ont changé la façon dont nous accédons à l'information et dont nous la recherchons.</p><h3>Notre héritage lexical</h3><p>Nous vivons tous depuis longtemps dans le monde quelque peu limité de la recherche lexicale (plutôt bien, du mieux que nous pouvons). La recherche est le premier outil que nous utilisons lorsque nous faisons des recherches ou que nous commençons un nouveau projet. Jusqu'à récemment, il nous incombait de formuler nos requêtes de manière à ce qu'elles soient comprises par un moteur de recherche lexical. La recherche lexicale repose sur la mise en correspondance d'une certaine forme de termes d'interrogation avec des mots-clés trouvés dans un corpus de documents, que le contenu soit structuré ou non. Pour qu'une recherche lexicale aboutisse à un document, celui-ci doit correspondre à ce mot-clé (ou disposer d'un vocabulaire contrôlé tel qu'une liste de synonymes ou un dictionnaire pour établir le lien conceptuel).</p>POST my-index/_search
{
  "size": 10,
  "query": {
    "semantic": {
      "query": "machine learning applications",
      "field": "semantic-content-field"
    }
  }
}<p><em>Exemple de </em><em> requête</em><a href="https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-multi-match-query"><em>lexicale multi-correspondance</em></a></p><p>Au moins, les moteurs de recherche ont la possibilité de renvoyer les résultats avec un score de pertinence. Les moteurs de recherche offrent une multitude d'options syntaxiques pour cibler efficacement les données indexées et des algorithmes de pertinence intégrés qui évaluent les résultats en fonction de l'intention de la syntaxe de la requête de l'utilisateur. Les moteurs de recherche bénéficient de décennies de progrès dans les algorithmes de classement par pertinence, ce qui en fait une plate-forme efficace de recherche de données capable de fournir des résultats notés et triés en fonction de leur pertinence par rapport à la requête. Les bases de données et autres systèmes qui utilisent SQL comme principale méthode de recherche de données sont ici désavantagés : il n'y a pas de concept de pertinence dans une requête de base de données ; le mieux qu'ils puissent faire est de trier les résultats par ordre alphabétique ou numérique. La bonne nouvelle, c'est que vous obtiendrez tous les résultats (rappel) avec ces mots-clés, mais qu'ils ne seront pas nécessairement dans un ordre utile par rapport à la <em>raison pour laquelle</em> vous les avez demandés (précision). C'est un point important, comme nous le verrons bientôt...</p><h3>Entrez dans le dragon (sémantique)</h3><p>Le potentiel des représentations vectorielles de l'information en tant qu'alternative à la recherche par mot-clé fait l'objet de recherches depuis <a href="https://www.elastic.co/search-labs/blog/introduction-to-vector-search">longtemps</a>. Les vecteurs sont très prometteurs parce qu'ils nous permettent de sortir du mode de correspondance par mot-clé uniquement - parce qu'ils sont des représentations numériques des termes et des poids, les vecteurs permettent de rapprocher mathématiquement les concepts sur la base de la compréhension par un modèle linguistique de la manière dont les termes sont liés les uns aux autres dans le domaine d'apprentissage. Le retard pris par la recherche vectorielle générale s'explique par le fait que les modèles étaient essentiellement limités à des domaines spécifiques et qu'ils n'étaient tout simplement pas assez vastes pour comprendre suffisamment les nombreux concepts différents qu'un terme peut représenter dans des contextes différents.</p><p>Ce n'est que lorsque les grands modèles de langage (LLM) sont apparus il y a quelques années, avec leur capacité à s'entraîner sur des quantités de données beaucoup plus importantes (en utilisant des <a href="https://en.wikipedia.org/wiki/Transformer_(deep_learning_architecture)">transformateurs</a> et de l'<a href="https://en.wikipedia.org/wiki/Attention_(machine_learning)">attention</a>), que la recherche vectorielle est devenue pratique - la taille et la profondeur des LLM ont finalement permis aux vecteurs de stocker suffisamment de nuances pour qu'ils puissent réellement capturer le sens sémantique. Cette augmentation soudaine de la profondeur de compréhension a permis aux LLM de remplir un grand nombre de fonctions de traitement du langage naturel (NLP) qui étaient auparavant verrouillées, la plus importante étant peut-être la capacité à déduire le terme suivant le plus probable dans une séquence, compte tenu du contexte de ce qui se trouve dans la séquence jusqu'à présent. L'inférence est le processus qui donne à l'IA générative sa capacité quasi humaine à produire du texte. Le texte généré par l'IA s'appuie sur la compréhension qu'a le LLM de la manière dont les termes sont liés dans ses données d'apprentissage et utilise également la formulation de la demande pour désambiguïser les différents contextes dans lesquels les termes peuvent apparaître.</p><p>Aussi magique que soit l'IA générative, les LLM présentent <em>des</em> limites qui entraînent des erreurs de qualité et de précision, communément appelées hallucinations. Les hallucinations se produisent lorsque le LLM n'a pas accès aux informations (ou n'est pas guidé vers le bon contexte) pour fonder sa réponse sur la vérité et que, pour être utile, il génère une réponse confiante et plausible qui a été inventée. Cela s'explique en partie par le fait que les LLM apprennent l'usage de la langue dans de vastes domaines d'informations diverses, mais qu'ils doivent cesser leur formation à un moment donné, de sorte que leur compréhension est soumise à un facteur temporel, ce qui signifie que le modèle ne peut savoir que ce qui était exact jusqu'au moment où il a cessé de se former. Un autre facteur d'hallucinations est que le modèle ne connaît généralement pas les données privées (données non disponibles sur l'internet public), ce qui est particulièrement important lorsque ces données contiennent des termes et une nomenclature spécifiques.</p><h3>Bases de données vectorielles</h3><p>Les LLM vectorisent le contenu dans l'espace de leur modèle à l'aide d'une technique appelée "text embedding", qui consiste à <a href="https://www.elastic.co/search-labs/blog/hybrid-search-multiple-embeddings">intégrer</a> ou à cartographier la signification sémantique du contenu dans la vision du monde du modèle sur la base de la formation qu'il a reçue. Quelques étapes sont nécessaires pour préparer et traiter le contenu à intégrer, notamment le <a href="https://www.elastic.co/search-labs/blog/chunking-strategies-elasticsearch">découpage en morceaux</a> et la tokenisation (et la <a href="https://www.kaggle.com/code/danishmahdi/subword-tokenization-bpe-wordpiece-and-unigram">tokenisation des sous-mots</a>). Le résultat est généralement un ensemble de vecteurs denses représentant la compréhension par le modèle de la signification de ce morceau de contenu dans son espace vectoriel. Le découpage est un processus inexact qui vise à adapter le contenu aux limites des contraintes de traitement d'un modèle pour générer des encastrements, tout en essayant de regrouper le texte apparenté dans un morceau à l'aide de constructions sémantiques telles que les indicateurs de phrase et de paragraphe.</p><p>La nécessité d'un découpage en morceaux peut entraîner une certaine perte sémantique dans un document incorporé, car les morceaux individuels ne sont pas entièrement associés à d'autres morceaux du même document. L'opacité inhérente aux réseaux neuronaux peut aggraver cette perte - un LLM est véritablement une "boîte noire" dans laquelle les connexions entre les termes et les concepts établies au cours de la formation sont non déterministes et ne peuvent être interprétées par les humains. Cela pose des problèmes d'explicabilité, de reproductibilité, de partialité inconsciente et, potentiellement, de perte de confiance et d'exactitude. Néanmoins, la possibilité de relier sémantiquement des idées, de ne pas être lié à des mots-clés spécifiques lors de la recherche, est extrêmement puissante :</p>POST my-index/_search 
{
  "size": 10, 
  "query": {
    "semantic": {
      "query": "machine learning applications",
      "field": "semantic-content-field"
    }
  }
} <p><em>Un exemple </em><a href="https://www.elastic.co/docs/reference/query-languages/query-dsl/query-dsl-semantic-query"><em>de</em></a><em> requête sémantique</em></p><p>Les bases de données vectorielles ne sont pas des moteurs de recherche, mais des bases de données ! Lorsqu'une <a href="https://www.elastic.co/search-labs/blog/introduction-to-vector-search">recherche de similarité vectorielle</a> est effectuée, les termes de la requête sont encodés pour trouver un ensemble de coordonnées (d'intégration) dans l'espace vectoriel du modèle. Ces coordonnées sont ensuite utilisées comme œil-de-bœuf pour trouver les documents qui sont les "plus proches voisins" de l'œil-de-bœuf - ce qui signifie que le rang d'un document (ou sa place dans les résultats) est déterminé par la <em>distance de</em> similarité calculée entre les coordonnées de ce document et les coordonnées de la requête. Dans quel sens le classement doit-il primer, lequel des contextes possibles est le plus proche de l'intention de l'utilisateur ? L'image à laquelle je me réfère est une scène du film <a href="https://www.youtube.com/watch?v=x3h7xz558EY&amp;start=3&amp;end=86">Stargate</a>, où nous avons les six points de coordonnées qui se croisent pour nous indiquer la destination (l'œil-de-bœuf), mais nous ne pouvons pas nous y rendre sans connaître le "7e symbole" - les coordonnées du point de départ représentant l'intention subjective de l'utilisateur. Ainsi, au lieu que le classement relatif des vecteurs soit basé sur une sphère de similarité toujours plus étendue et indifférenciée, en tenant compte de l'intention subjective de la requête par le biais d'une syntaxe expressive et d'une notation de la pertinence, nous pouvons obtenir quelque chose qui ressemble à un <em>cylindre</em> de pertinence subjective graduée.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb49ae330d3de1fc1/6a17053ee8fbce089639fb46/1ddfaae0c1496d08d7d30419e6d2aeaeacfc0ea2-1600x544.png" alt="Un cylindre à pertinence subjective graduée." /><p>Les capacités d'inférence d'un LLM peuvent aider à identifier le contexte le plus probable <em>pour</em> la requête, mais le problème est que <em>sans aide, les</em> coordonnées de la requête entrante <em>ne</em> peuvent être déterminées que par la façon dont le modèle a été formé à l'origine.</p><p>D'une certaine manière, on pourrait dire que la similarité vectorielle va à l'extrême opposé d'une correspondance stricte par mot-clé - sa force réside dans sa capacité à surmonter les problèmes d'inadéquation des termes, mais <a href="https://medium.com/data-science/vector-embeddings-are-lossy-heres-what-to-do-about-it-4f9a8ee58bb7">presque jusqu'à la faute</a>: Les LLM tendent à unifier des concepts apparentés plutôt qu'à les différencier. La similarité vectorielle améliore notre capacité à faire correspondre le contenu sur le plan sémantique, mais ne garantit pas la précision car elle peut négliger des mots-clés exacts et des détails spécifiques qui ne sont pas suffisamment désambiguïsés par le modèle. La recherche de similarités vectorielles est puissante en soi, mais nous avons besoin de moyens pour corréler les résultats que nous extrayons d'une base de données vectorielle avec les résultats d'autres méthodes d'extraction.</p><h3>Techniques de repositionnement</h3><p>C'est le moment de mentionner une technique générale appelée "reranking", qui consiste à réévaluer ou à normaliser les ensembles de résultats en fonction d'un ordre de classement unifié. Le besoin de reclassement peut être dû au fait que les résultats provenant de sources multiples ou de méthodes de recherche ont des mécanismes de classement/évaluation différents (ou aucun, SQL !), ou le reclassement peut être utilisé pour aligner sémantiquement les résultats provenant de sources non sémantiques sur la requête de l'utilisateur. Le reclassement est une opération de deuxième étape, c'est-à-dire un ensemble de résultats qui ont été collectés par une méthode de <em>recherche initiale</em> (c'est-à-dire le SQL, recherche lexicale, recherche vectorielle) sont ensuite réordonnées avec une méthode de notation différente.</p><p>Plusieurs approches sont disponibles, notamment <a href="https://www.elastic.co/docs/solutions/search/ranking/learning-to-rank-ltr">Learning-To-Rank (LTR)</a> et <a href="https://www.elastic.co/docs/reference/elasticsearch/rest-apis/reciprocal-rank-fusion">Reciprocal Rank Fusion (RRF)</a> - LTR est utile pour capturer les caractéristiques des résultats de recherche (likes, évaluations, clics, etc.) et les utiliser pour noter et améliorer ou biaiser les résultats. RRF est parfait pour fusionner les résultats obtenus à partir de différentes modalités d'interrogation (par ex. les recherches dans les bases de données lexicales et vectorielles) en une seule liste de résultats. Elastic offre également la possibilité d'ajuster les scores à l'aide de méthodes de <a href="https://www.elastic.co/search-labs/blog/linear-retriever-hybrid-search">reclassement linéaire</a>.</p><p>L'une des techniques de reclassement les plus efficaces est cependant le <a href="https://www.elastic.co/docs/solutions/search/ranking/semantic-reranking">reclassement sémantique</a>, qui utilise la compréhension sémantique d'un LLM pour analyser les vecteurs d'intégration de la requête et des résultats, puis appliquer la notation de la pertinence/le reclassement pour déterminer l'ordre final. Le reranking sémantique nécessite une connexion à un modèle de reranking, bien sûr, et Elasticsearch fournit une <a href="https://www.elastic.co/docs/api/doc/elasticsearch/group/endpoint-inference">API d'inférence</a> qui vous permet de créer des points d'extrémité de <strong>rerank</strong> qui exploitent des modèles intégrés<a href="https://www.elastic.co/docs/explore-analyze/machine-learning/nlp/ml-nlp-rerank">(Elastic Rerank</a>), des modèles tiers <a href="https://www.elastic.co/docs/reference/elasticsearch/clients/eland/machine-learning">importés</a> ou des services hébergés en externe tels que <a href="https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put-cohere">Cohere</a> ou <a href="https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-inference-put-googlevertexai">Google Vertex AI.</a> Vous pouvez ensuite effectuer un reclassement grâce à la syntaxe d'abstraction de la requête du <a href="https://www.elastic.co/docs/solutions/search/retrievers-overview">récupérateur</a>:</p>POST my-index/_search 
{
  "size": 10,
  "retriever": {
    "text_similarity_reranker": {
      "retriever": {
        "rrf": {
          "retrievers": [
            {
              "standard": {
                "query": {
                  "multi_match": {
                    "query": "machine learning applications",
                    "fields": ["title", "content"]
                  }
                }
              }
            },
            {
              "knn": {
                "field": "semantic-content-field",
                "k": 10,
                "num_candidates": 100,
                "query_vector_builder": {
                  "text_embedding": {
                    "model_id": "my-text-embedding-model",
                    "model_text": "machine learning applications"
                  }
                }
              }
            }
          ],
          "rank_window_size": 50,
          "rank_constant": 20
        }
      }
    },
    "field": "content",
    "inference_id": "my-reranker",
    "inference_text": "machine learning applications",
    "rank_window_size": 20
  }
}<p><em>Exemple d'opération de remise en ordre d'un récupérateur en plusieurs étapes</em></p><p>Ça a l'air bien, non ? Nous pouvons effectuer un reclassement sur des résultats provenant de sources disparates et nous rapprocher d'une compréhension sémantique de tous les types de contenu... Le reclassement sémantique peut être coûteux tant sur le plan du calcul que du temps de traitement nécessaire, et pour cette raison, le reclassement sémantique ne peut être effectué que sur un nombre limité de résultats, ce qui signifie que la <em>manière dont</em> ces résultats initiaux sont récupérés est importante.</p><h3>La méthode de recherche contextuelle est importante</h3><p>L'intention subjective est un facteur important dans la détermination de l'exactitude d'un résultat, dans l'évaluation de sa pertinence. Sans la possibilité de prendre en compte l'intention de l'utilisateur lors de l'exécution de la requête (telle qu'elle est exprimée par une syntaxe flexible ou par un reclassement de deuxième niveau), nous ne pouvons que sélectionner les contextes existants déjà encodés dans l'espace de modélisation. La façon dont nous abordons généralement ce manque de contexte est par le biais de techniques telles que <a href="https://en.wikipedia.org/wiki/Retrieval-augmented_generation">Retrieval Augment Generation (RAG).</a> La méthode RAG consiste à déplacer les coordonnées de la requête en incluant des termes connexes supplémentaires issus d'une pré-requête de données contextuelles pertinentes. Le moteur qui fournit ce contexte supplémentaire et <em>sa</em> méthode initiale de recherche sont donc d'autant plus importants pour la précision du contexte !</p><p>Passons en revue les différentes méthodes de recherche contextuelle et la manière dont elles peuvent aider ou nuire à une opération RAG :</p><ul><li><p><strong>La recherche hybride sans moteur de recherche manque encore de pertinence subjective.</strong> Si la plateforme qui fournit le RAG est principalement basée sur SQL (ce qui inclut la plupart des plateformes de "lac de données"), elle ne dispose pas d'un système de notation de la pertinence au stade de la recherche initiale. De nombreuses plateformes de lac de données proposent leur propre version de la recherche hybride (et non de la recherche), combinant généralement des techniques de reranking telles que le reranking sémantique et le RRF sur leur recherche basée sur SQL et les résultats de la base de données vectorielles. Un simple tri est manifestement insuffisant pour un classement subjectif, mais même lorsqu'il est utilisé comme base pour une opération de reclassement sémantique à la deuxième étape, SQL comme la recherche à la première étape devient un problème lorsque le reclassement sémantique n'est effectué que sur les "k premiers" résultats - sans un moyen de noter les résultats à la recherche, quelle garantie avons-nous que les <em>meilleurs</em> résultats se trouvent effectivement dans les premiers résultats ?</p></li><li><p><strong>La similarité vectorielle n'est pas suffisante pour le RAG</strong>. Il s'agit en fait d'un ensemble de problèmes combinés - la perte de l'intégration, les méthodes naïves de regroupement, le mode de calcul de la similarité et la composante manquante cruciale de l'intention subjective. L'un des principaux objectifs de RAG est de fonder les interactions génératives de l'IA sur la vérité objective, à la fois pour éviter les hallucinations et pour informer le LLM des informations privées dont il n'a pas eu connaissance au cours de la formation. Nous pouvons utiliser le contexte supplémentaire fourni par le RAG pour contraindre et orienter les MFR à prendre en compte les liens et les détails que nous savons être les plus importants pour répondre à la question posée. Pour ce faire, nous devons utiliser des approches sémantiques et <em>lexicales</em>.</p></li><li><p><strong>RAG (grep/regex) basé sur des fichiers.</strong> Certains <a href="https://www.nicolasbustamante.com/p/the-rag-obituary-killed-by-agents">secteurs</a> de l'univers de l'IA agentique préconisent l'utilisation de fenêtres contextuelles considérablement agrandies qui accèdent aux fichiers locaux via grep et regex pour RAG plutôt que des plates-formes de recherche externes. L'idée est qu'en disposant d'une fenêtre contextuelle beaucoup plus large, les LLM seront en mesure d'établir des connexions conceptuelles au sein de leur propre espace de réflexion plutôt que de s'appuyer sur des éléments fragmentés et de multiples méthodes/plateformes de recherche pour collecter des informations pertinentes. S'il est vrai en théorie que le fait de disposer d'un document entier donne une image plus complète que des segments de document, cela ne peut fonctionner que dans des domaines de données restreints (ou, par exemple, lors de la fourniture de fichiers pour le <a href="https://en.wikipedia.org/wiki/Vibe_coding">vibecodage</a>), et même dans ce cas, la méthode de recherche initiale est un balayage de tous les documents avec une correspondance par mot-clé uniquement.</p></li></ul><p><strong>La recherche, c'est plus que l'extraction</strong></p><p>Les moteurs de recherche sont conçus pour rendre les requêtes aussi rapides et flexibles que possible. En interne, ils utilisent des structures de données spécialisées pour stocker et récupérer différents types de données de manière adaptée à ces types de données. Elasticsearch permet d'optimiser le stockage et l'interrogation de pratiquement tous les types de données, y compris la recherche lexicale non structurée/texte intégral (correspondance, phrase, proximité, correspondance multiple), la correspondance et le filtrage rapides par mot-clé (correspondance exacte), les plages numériques, les dates, les adresses IP, et est très flexible dans la manière dont il stocke les structures de documents (par ex. les documents imbriqués ou aplatis). Elasticsearch est également une base de données vectorielle native capable de stocker et d'interroger des types de vecteurs épars et denses, et nous continuons à explorer des moyens innovants (par exemple, <a href="https://www.elastic.co/search-labs/blog/better-binary-quantization-lucene-elasticsearch">Better Binary Quantization (BBQ)</a> &amp; <a href="https://www.elastic.co/search-labs/blog/diskbbq-elasticsearch-introduction">DiskBBQ</a>) pour maintenir la fidélité de la recherche tout en améliorant la vitesse, l'évolutivité et les coûts associés au contenu vectorisé. La plateforme Elasticsearch offre également une résilience des données et une haute disponibilité intégrées, ainsi que des fonctionnalités de gestion du cycle de vie des données, telles que les <a href="https://www.elastic.co/docs/deploy-manage/tools/snapshot-and-restore/searchable-snapshots">instantanés consult</a> ables, qui vous permettent de conserver les données rarement consultées ou les données conservées à long terme sur un stockage objet rentable, tout en conservant une capacité de recherche totale.</p><h3>La recherche hybride, c'est le meilleur des mondes</h3><p><a href="https://www.elastic.co/what-is/hybrid-search">Recherche hybride</a> (et pas seulement recherche hybride !) combine les forces de la recherche lexicale traditionnelle avec la compréhension sémantique des LLM et la recherche par similarité vectorielle. Cette synergie permet de cibler des résultats très pertinents au stade de la <em>recherche</em> grâce à l'une des options syntaxiques souples proposées par un moteur de recherche : options syntaxiques axées sur l'intention et évaluation de la pertinence, recherche de données multimodales, filtrage, agrégations et biais. Avec une syntaxe de recherche telle que <a href="https://www.elastic.co/docs/reference/query-languages/esql">ES|QL</a> et des <a href="https://www.elastic.co/docs/solutions/search/retrievers-overview">extracteurs</a> à plusieurs niveaux, nous pouvons combiner de manière flexible la recherche traditionnelle avec la recherche sémantique, les filtres et plusieurs techniques de reclassement en une seule requête.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt6ee9512910856ee3/6a17053fcdacbf2ea97d291e/f25180cb430414b99ae553d3b8eb161dbccea4d4-1920x1080.png" alt="Comment fonctionne la recherche hybride ?" /><p>L'un des principaux avantages de la recherche hybride est que vos requêtes peuvent utiliser une syntaxe spécialisée pour plusieurs types de données simultanément. Ces différentes syntaxes d'interrogation peuvent être utilisées non seulement pour <em>trouver des</em> résultats, mais aussi comme filtres ou agrégations <em>sur les</em> résultats. Par exemple, l'<a href="https://www.elastic.co/docs/explore-analyze/geospatial-analysis">analyse géospatiale</a> est l'un des types d'interrogation les plus courants qui est fréquemment combiné à d'autres syntaxes. Vous pouvez par exemple demander des résultats dont les coordonnées géographiques se situent à une distance donnée d'un point, ou demander des agrégations de vos résultats par région, ou encore des agrégations pour suivre et alerter sur les mouvements à l'intérieur ou à l'extérieur d'une zone. Avec la recherche hybride, vous avez la possibilité de combiner des syntaxes pour cibler les résultats de la manière la plus précise possible, afin de retrouver le contenu le plus proche de votre contexte.</p><h2>Intermède</h2><p>Cette première partie raconte comment la recherche vectorielle a changé la façon dont nous pouvons récupérer des données et prépare le terrain pour les changements que les LLM ont apportés aux mécanismes d'interrogation que nous utilisons pour interagir avec les données. Nous allons faire comme si nous avions dû diviser ce texte en plusieurs parties pour que les LLM puissent le comprendre sans perdre le contexte... ;-) Nous en apprendrons plus sur les <em>raisons de cette importance</em> dans la <a href="https://www.elastic.co/search-labs/blog/context-engineering-llm-evolution-agentic-ai">Partie II : L'IA agentique et le besoin d'ingénierie contextuelle</a>, et dans la Partie III, nous reviendrons à notre discussion sur la recherche hybride.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/context-engineering-hybrid-search-evolution-agentic-ai</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/context-engineering-hybrid-search-evolution-agentic-ai</guid>
    <category><![CDATA[Recherche hybride]]></category>
    <category><![CDATA[Pertinence]]></category>
    <dc:creator><![CDATA[Woody Walton]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc49e39872984c8eb/6a1705410e2e49e42c419fd5/7e59a0671aa9ea32d68188a693936a66ebf48625-1000x628.png" length="0" type="image/png"/>
    <pubDate>Wed, 12 Nov 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[La recherche hybride revisitée : introduction de la recherche linéaire dans Elasticsearch !]]></title>
    <description><![CDATA[Découvrez comment le récupérateur linéaire améliore la recherche hybride en exploitant les scores pondérés et la normalisation MinMax pour des classements plus précis et plus cohérents, et apprenez à l'utiliser.]]></description>
    <content:encoded><![CDATA[<p>Dans notre <a href="https://www.elastic.co/fr/search-labs/blog/elasticsearch-retrievers-ga-8.16.0">précédent article</a> de blog, nous avons présenté le cadre des récupérateurs remanié de A à Z, qui permet de créer des pipelines de classement complexes. Nous avons également étudié la manière dont le récupérateur Reciprocal Rank Fusion (RRF) permet une recherche hybride en fusionnant les résultats de différentes requêtes. Bien que la méthode RRF soit facile à mettre en œuvre, elle présente une limitation notable : elle se concentre uniquement sur les rangs relatifs, sans tenir compte des scores réels. Cela rend le réglage fin et l'optimisation difficiles.</p><h2>Rencontrez le retriever linéaire !</h2><p>Dans ce billet, nous vous présentons le <a href="https://www.elastic.co/fr/docs/solutions/search/retrievers-overview#retrievers-overview-types"><code>linear</code></a> <a href="https://www.elastic.co/fr/docs/solutions/search/retrievers-overview#retrievers-overview-types">retriever</a>, notre dernier ajout pour soutenir la recherche hybride ! Contrairement à <code>rrf</code>, le récupérateur <code>linear</code> calcule une somme pondérée de toutes les requêtes correspondant à un document. Cette approche préserve l'importance relative de chaque document dans un ensemble de résultats tout en permettant un contrôle précis de l'influence de chaque requête sur le score final. Il s'agit donc d'un moyen plus intuitif et plus souple d'affiner la recherche hybride.</p><p>Définition d'un récupérateur linéaire où le score final sera calculé comme suit :</p><p>C'est aussi simple que cela :</p>GET linear_retriever_blog/_search
{
   "retriever": {
       "linear": {
           "retrievers": [
               {
                   "retriever": {
                       "knn": {
                          ...
                        }
                    },
                   "weight": 5
               },
                  {
                   "retriever": {
                       "standard": {
                          ...
                        }
                    },
                   "weight": 1.5
               },


           ]
        }
     }
}<p>Vous avez remarqué à quel point c'est simple et intuitif ? (et très similaire à <code>rrf</code>!) Cette configuration vous permet de contrôler précisément la contribution de chaque type de requête au classement final, contrairement à <code>rrf</code>, qui s'appuie uniquement sur les classements relatifs.</p><p>Une mise en garde subsiste : les scores <code>knn</code> peuvent être strictement limités, en fonction de la métrique de similarité utilisée. Par exemple, avec la similarité en cosinus ou le produit de points de vecteurs normalisés en unités, les scores se situeront toujours dans l'intervalle <code>[0, 1]</code>. En revanche, les scores sur <code>bm25</code> sont moins prévisibles et n'ont pas de limites clairement définies.</p><h2>Mise à l'échelle des scores : kNN vs BM25</h2><p>L'une des difficultés de la recherche hybride réside dans le fait que les différents outils de recherche produisent des résultats sur des échelles différentes. Prenons par exemple le scénario suivant :</p><p>La requête A obtient un score :</p><p></p><p>doc1</p><p>doc2</p><p>doc3</p><p>doc4</p><p>knn</p><p>0.347</p><p>0.35</p><p>0.348</p><p>0.346</p><p>bm25</p><p>100</p><p>1.5</p><p>1</p><p>0.5</p><p>Les résultats de la requête B :</p><p></p><p>doc1</p><p>doc2</p><p>doc3</p><p>doc4</p><p>knn</p><p>0.347</p><p>0.35</p><p>0.348</p><p>0.346</p><p>bm25</p><p>0.63</p><p>0.01</p><p>0.3</p><p>0.4</p><p>Vous pouvez voir la disparité ci-dessus : les scores de <code>kNN</code> se situent entre 0 et 1, tandis que les scores de <code>bm25</code> peuvent varier considérablement. Cette différence rend difficile l'établissement de poids statiques optimaux pour la combinaison des résultats.</p><h2>La normalisation à la rescousse : le normalisateur MinMax</h2><p>Pour y remédier, nous avons introduit un normalisateur <code>minmax</code> facultatif qui adapte les scores, indépendamment pour chaque requête, à la plage <code>[0, 1]</code> en utilisant la formule suivante :</p><p>Cela permet de préserver l'importance relative de chaque document dans l'ensemble des résultats d'une requête, ce qui facilite la combinaison des scores obtenus par différents extracteurs. Avec la normalisation, les scores deviennent :</p><p>La requête A obtient un score :</p><p></p><p>doc1</p><p>doc2</p><p>doc3</p><p>doc4</p><p>knn</p><p>0.347</p><p>0.35</p><p>0.348</p><p>0.346</p><p>bm25</p><p>1.00</p><p>0.01</p><p>0.005</p><p>0.000</p><p>Les résultats de la requête B :</p><p></p><p>doc1</p><p>doc2</p><p>doc3</p><p>doc4</p><p>knn</p><p>0.347</p><p>0.35</p><p>0.348</p><p>0.346</p><p>bm25</p><p>1.00</p><p>0.000</p><p>0.465</p><p>0.645</p><p>Tous les scores se situent désormais dans la fourchette <code>[0, 1]</code> et l'optimisation de la somme pondérée est beaucoup plus simple car nous capturons désormais l'importance (relative à la requête) d'un résultat au lieu de son score absolu et nous maintenons la cohérence entre les requêtes.</p><h2>Exemple de récupérateur linéaire </h2><p>Prenons maintenant un exemple pour illustrer ce qui précède et la façon dont le récupérateur <code>linear</code> comble certaines lacunes de <code>rrf</code>. RRF se base uniquement sur les rangs relatifs et ne prend pas en compte les différences de score réelles. Par exemple, compte tenu de ces scores :</p><p></p><p>doc1</p><p>doc2</p><p>doc3</p><p>doc4</p><p>knn</p><p>0.347</p><p>0.35</p><p>0.348</p><p>0.346</p><p>bm25</p><p>100</p><p>1.5</p><p>1</p><p>0.5</p><p>score du rrf</p><p>0.03226</p><p>0.03252</p><p>0.03200</p><p>0.03125</p><p>rrf classerait les documents comme suit :</p><p>Cependant, doc1 a un score <code>bm25</code> nettement plus élevé que les autres, ce que <code>rrf</code> ne parvient pas à capturer car il ne tient compte que des rangs relatifs. L'outil <code>linear</code> retriever, combiné à la normalisation, prend correctement en compte les scores et leurs différences, ce qui permet d'obtenir un classement plus significatif :</p><p></p><p>doc1</p><p>doc2</p><p>doc3</p><p>doc4</p><p>knn</p><p>0.347</p><p>0.35</p><p>0.348</p><p>0.346</p><p>bm25</p><p>1</p><p>0.01</p><p>0.005</p><p>0</p><p>Comme nous pouvons le voir ci-dessus, l'excellent classement de doc1 et <code>score</code> pour <code>bm25</code> est correctement pris en compte et reflété dans les notes finales. En outre, tous les scores se situent désormais dans la fourchette <code>[0, 1]</code>, ce qui nous permet de les comparer et de les combiner de manière beaucoup plus intuitive (et même de mettre en place des processus d'optimisation hors ligne).</p><h2>La mise en place de l'ensemble</h2><p>Pour tirer pleinement parti de l'outil de recherche <code>linear</code> et de la normalisation, la demande de recherche devrait ressembler à ce qui suit :</p>GET linear_retriever_blog/_search
{
   "retriever": {
       "linear": {
           "retrievers": [
               {
                   "retriever": {
                       "knn": {
                          ...
                        }
                    },
                   "weight": 5
               },
                  {
                   "retriever": {
                       "standard": {
                          ...
                        }
                    },
                   "weight": 1.5,
                   "normalizer": "minmax"
               },


           ]
       }
   }
}<p>Cette approche combine le meilleur des deux mondes : elle conserve la flexibilité et la notation intuitive du <code>linear</code> retriever, tout en garantissant une mise à l'échelle cohérente des scores grâce à la normalisation MinMax.</p><p>Comme tous nos retrievers, le retriever <code>linear</code> peut être intégré à n'importe quel niveau d'un arbre hiérarchique de retrievers, avec une prise en charge de l'explicabilité, de la mise en évidence des correspondances, du regroupement des champs, etc.</p><h2>Quand choisir le retriever linéaire et pourquoi cela fait une différence</h2><p>Le <code>linear</code> retriever :</p><ul><li><p>Préserve l'importance relative en s'appuyant sur les scores réels, et pas seulement sur les rangs.</p></li><li><p>Permet un réglage fin avec des contributions pondérées de différentes requêtes.</p></li><li><p>Améliore la cohérence grâce à la normalisation, ce qui rend la recherche hybride plus robuste et plus prévisible.</p></li></ul><h2>Conclusion</h2><p>Le récupérateur <code>linear</code> est déjà disponible sur Elasticsearch Serverless, et les versions 8.18 et 9.0 ! D'autres exemples et paramètres de configuration sont également disponibles dans notre documentation. Essayez-le et voyez comment il peut améliorer votre expérience de la recherche hybride - nous attendons vos commentaires. Bonne recherche !</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/linear-retriever-hybrid-search</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/linear-retriever-hybrid-search</guid>
    <category><![CDATA[Pertinence]]></category>
    <category><![CDATA[Recherche hybride]]></category>
    <dc:creator><![CDATA[Panagiotis Bailis]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte58a751cbcc1153d/6a17e3c76317305c4f585a10/7a07e27e3095463ff93b4cb7f8a0cf3b8e44eab0-1777x1000.png" length="0" type="image/png"/>
    <pubDate>Wed, 28 May 2025 00:00:00 GMT</pubDate>
  </item>
  <item>
    <title><![CDATA[Création de listes de jugements avec Quepid]]></title>
    <description><![CDATA[Apprenez à créer des listes de jugement dans Quepid en utilisant un processus collaboratif d'évaluation humaine et à utiliser les références pour ajuster votre pertinence.]]></description>
    <content:encoded><![CDATA[<p>La création de <a href="https://www.elastic.co/search-labs/blog/judgment-lists">listes de jugement</a> est une étape cruciale dans l'optimisation de la qualité des résultats de recherche, mais elle peut s'avérer une tâche compliquée et difficile. Une liste d'évaluation est un ensemble de requêtes de recherche associées à des notes de pertinence pour les résultats correspondants, également connu sous le nom de collection de tests. Les mesures calculées à l'aide de cette liste servent de référence pour mesurer les performances d'un moteur de recherche. Pour simplifier le processus de création des listes de jugement, l'équipe d'<a href="https://opensourceconnections.com/">OpenSource Connections</a> a développé <a href="https://quepidapp.com/">Quepid</a>. Le jugement peut être explicite ou basé sur un retour d'information implicite de la part des utilisateurs. Ce blog vous guidera dans la mise en place d'un environnement collaboratif dans Quepid afin de permettre aux évaluateurs humains d'effectuer des jugements explicites, ce qui est la base de toute liste de jugements.</p><p>Quepid soutient les équipes de recherche dans le processus d'évaluation de la qualité de la recherche :</p><ul><li><p>Construire des ensembles de requêtes</p></li><li><p>Créer des listes de jugement</p></li><li><p>Calculer les indicateurs de qualité de la recherche</p></li><li><p>Comparer différents algorithmes de recherche/rankers sur la base de paramètres de qualité de recherche calculés</p></li></ul><p>Pour notre blog, supposons que nous gérons un magasin de location de films et que notre objectif est d'améliorer la qualité de nos résultats de recherche.</p><h2>Produits requis</h2><p>Ce blog utilise les données et les correspondances du <a href="https://github.com/o19s/es-tmdb">référentiel es-tmdb</a>. Les données proviennent de <a href="https://www.themoviedb.org/">The Movie Database</a>. Pour continuer, créez un index appelé tmdb avec les mappings et indexez les données. Peu importe que vous mettiez en place une instance locale ou que vous utilisiez un déploiement Elastic Cloud pour cela - l'un ou l'autre fonctionne parfaitement. Pour ce blog, nous supposons un déploiement d'Elastic Cloud. Vous pouvez trouver des informations sur la manière d'indexer les données dans le <a href="https://github.com/o19s/es-tmdb/blob/master/README.md">README du dépôt es-tmdb</a>.</p><p>Effectuez une simple recherche de correspondance dans le champ du titre pour <code>rocky</code> afin de confirmer que vous disposez des données nécessaires à la recherche :</p>GET tmdb/_search
{
 "query": {
   "match": {
     "title": "rocky"
   }
 }
}<p>Vous devriez voir 8 résultats.</p>{
 "took": 2,
 "timed_out": false,
 "_shards": {
   "total": 1,
   "successful": 1,
   "skipped": 0,
   "failed": 0
 },
 "hits": {
   "total": {
     "value": 8,
     "relation": "eq"
   }
…
}<h2>Se connecter à Quepid</h2><p><a href="https://github.com/o19s/quepid">Quepid</a> est un outil qui permet aux utilisateurs de mesurer la qualité des résultats de recherche et de mener des expériences hors ligne pour l'améliorer.</p><p>Vous pouvez utiliser Quepid de deux manières : soit vous utilisez la version gratuite et publiquement disponible à l'adresse <a href="https://app.quepid.com">https://app</a>.quepid.com, ou installez Quepid sur une machine à laquelle vous avez accès. Cet article suppose que vous utilisez la version hébergée gratuite. Si vous souhaitez mettre en place une instance de Quepid dans votre environnement, suivez le <a href="https://github.com/o19s/quepid/wiki/Installation-Guide">Guide d'installation</a>.</p><p>Quelle que soit la configuration choisie, vous devrez créer un compte si vous n'en avez pas déjà un.</p><h2>Comment configurer un cas Quepid</h2><p>Quepid est organisé autour des cas "." Un cas stocke les requêtes avec les paramètres de réglage de la pertinence et la façon d'établir une connexion avec votre moteur de recherche.</p><ul><li><p>Pour les nouveaux utilisateurs, sélectionnez <strong>Créer votre premier cas de pertinence.</strong></p></li><li><p>Les utilisateurs qui reviennent peuvent sélectionner <strong>Cas de pertinence</strong> dans le menu de haut niveau et cliquer sur <strong>+ Créer un cas.</strong></p></li></ul><p>Donnez un nom descriptif à votre cas, par exemple "Movie Search Baseline,", car nous voulons commencer à mesurer et à améliorer notre recherche de base.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte2913d344c42cd24/6a17e6477b54f906b48b38bd/8f9e480d9aae0d706cfc5371e41f19c706dd452a-594x251.png" alt="Mise en place d'un dossier Quepid" /><p>Confirmez le nom en sélectionnant <strong>Continuer.</strong></p><p>Ensuite, nous établissons une connexion entre Quepid et le moteur de recherche. Quepid peut se connecter à une variété de moteurs de recherche, y compris Elasticsearch.</p><p>La configuration diffère en fonction de la configuration d'Elasticsearch et de Quepid. Pour connecter Quepid à un déploiement Elastic Cloud, nous devons activer et configurer CORS pour notre déploiement Elastic Cloud et avoir une clé API prête. Les instructions détaillées se trouvent dans le guide pratique correspondant dans la <a href="https://quepid-docs.dev.o19s.com/2/quepid/49/how-to-connect-quepid-to-elastic-cloud">documentation de</a> Quepid.</p><p>Saisissez les informations relatives à votre point de terminaison Elasticsearch (<code>https://YOUR_ES_HOST:PORT/tmdb/_search</code>) et toute autre information nécessaire à la connexion (la clé API dans le cas d'un déploiement Elastic Cloud dans les options de configuration <strong>avancées</strong> ), testez la connexion en cliquant sur <strong>ping it</strong> et sélectionnez <strong>Continue</strong> pour passer à l'étape suivante.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcc068309bdc094ae/6a17e6480b0bed14cddd356a/267339dfaecae2740eb2ee2739bdc971608bdb5f-588x1169.png" alt="Configurer un point de terminaison Elasticsearch avec Quepid." /><p>Nous définissons maintenant les champs que nous voulons voir apparaître dans le dossier. Sélectionner tout ce qui aide nos évaluateurs humains à évaluer ultérieurement la pertinence d'un document pour une requête donnée.</p><p>Définissez <code>title</code> comme <em>champ de titre</em>, laissez <code>_id</code> comme <em>champ d'identification</em> et ajoutez <code>overview, tagline, cast, vote_average, thumb:poster_path</code> comme <em>champs d'affichage supplémentaires</em>. La dernière entrée affiche de petites vignettes pour les films de nos résultats afin de nous guider visuellement, ainsi que les évaluateurs humains.</p><p>Confirmez les paramètres d'affichage en sélectionnant le bouton <strong>Continuer.</strong></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc910bdf5aa7680b3/6a17e64ae8fbce710b3a1906/02c58aae8c2ebb6d31f538b27462b4c65428fdc3-594x493.png" alt="Définir les champs à afficher dans le cas des évaluateurs humains de Quepid." /><p>La dernière étape consiste à ajouter des requêtes de recherche au dossier. Ajoutez les trois requêtes <em>star wars</em>, <em>harrison ford</em>, et <em>meilleur film d'action une</em> par une dans le champ de saisie et <strong>continuez</strong>.</p><p>Idéalement, un cas contient des requêtes qui représentent des requêtes réelles d'utilisateurs et illustrent différents types de requêtes. Pour l'instant, nous pouvons imaginer que <em>Star Wars</em> est une requête représentant toutes les demandes de titres de films, que <em>Harrison Ford</em> est une requête représentant toutes les demandes de noms d'acteurs, et que <em>le meilleur film d'action</em> est une requête représentant toutes les demandes de films d'un genre spécifique. C'est ce que l'on appelle généralement un ensemble de requêtes.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt46122bb45e1063e4/6a17e64b505ac36510ad8af8/baccfe96766319aa7255e9bff08913ac87d1517f-595x326.png" alt="Ajouter des requêtes de recherche à un cas Quepid" /><p>Dans un scénario de production, nous échantillonnerions les requêtes à partir des données de suivi des événements en appliquant des techniques statistiques telles que l'<a href="https://opensourceconnections.com/blog/2022/10/13/how-to-succeed-with-explicit-relevance-evaluation-using-probability-proportional-to-size-sampling/">échantillonnage proportionnel à la taille</a> et importerions ces requêtes échantillonnées dans Quepid pour inclure les requêtes de la tête (requêtes fréquentes) et de la queue (requêtes peu fréquentes) par rapport à leur fréquence, ce qui signifie que nous privilégions les requêtes les plus fréquentes sans exclure les requêtes rares.</p><p>Enfin, sélectionnez <strong>Terminer</strong> et vous serez redirigé vers l'interface du cas où vous verrez les trois requêtes définies.</p><h2>Requêtes et besoins d'information</h2><p>Pour parvenir à l'objectif global d'une liste de jugement, les évaluateurs humains devront juger un résultat de recherche (généralement un document) pour une requête donnée. C'est ce qu'on appelle une paire requête/document.</p><p>Parfois, il semble facile de savoir ce que l'utilisateur voulait en regardant la requête. L'objectif de la requête <code>harrison ford</code> est de trouver des films mettant en scène l'acteur Harrison Ford. Qu'en est-il de la requête <code>action</code>? Je sais que je serais tenté de dire que l'intention de l'utilisateur est de trouver des films appartenant au genre action. Mais lesquels ? Les plus récents, les plus populaires, les meilleurs d'après les évaluations des utilisateurs ? Ou bien l'utilisateur souhaite-t-il trouver tous les films intitulés "Action" ? <a href="https://www.themoviedb.org/search/movie?query=Action">Il y a au moins 12 ( !) films appelés "Action" dans The Movie Database</a> et leurs noms diffèrent principalement par le nombre de points d'exclamation dans le titre.</p><p>Deux évaluateurs humains peuvent interpréter différemment une requête dont l'intention n'est pas claire. Le besoin d'information : Un <a href="https://en.wikipedia.org/wiki/Information_needs">besoin</a> d'information est un désir conscient ou inconscient d'obtenir des informations. La définition d'un besoin d'information aide les évaluateurs humains à juger les documents pour une requête, et joue donc un rôle important dans le processus d'élaboration des listes de jugement. Les utilisateurs experts ou les experts en la matière sont de bons candidats pour spécifier les besoins d'information. Une bonne pratique consiste à définir les besoins d'information du point de vue de l'utilisateur, car c'est à ses besoins que les résultats de la recherche doivent répondre.</p><p>Besoins en informations pour les requêtes de notre cas "Recherche de films de référence" :</p><ol><li><p><strong>la guerre des étoiles</strong>: L'utilisateur souhaite trouver des films ou des émissions de la franchise Star Wars. Les documentaires sur la Guerre des étoiles sont potentiellement pertinents.</p></li><li><p><strong>harrison ford</strong>: L'utilisateur souhaite trouver des films mettant en scène l'acteur Harrison Ford. Les films dans lesquels Harrison Ford joue un rôle différent, comme celui de narrateur, sont potentiellement pertinents.</p></li><li><p><strong>meilleur film d'action</strong>: L'utilisateur souhaite trouver des films d'action, de préférence ceux dont la moyenne des votes des utilisateurs est élevée.</p></li></ol><h2>Comment définir les besoins en information dans Quepid</h2><p>Pour définir un besoin d'information dans Quepid, accédez à l'interface du cas :</p><p>1. Ouvrez une requête (par exemple<em>star wars</em>) et sélectionnez <em>Toggle Notes.</em></p><p>2. Inscrivez le besoin d'information dans le premier champ et toute note supplémentaire dans le deuxième champ :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte57395f64f6e5fab/6a17e64d6864a40fd6b68771/e01d3d5242a350d8797faa665eb3170039f5dfa2-1483x559.png" alt="Définir les besoins d'information et de requêtes dans Quepid." /><p>3. Cliquez sur <strong>Enregistrer</strong>.</p><p>Pour une poignée de requêtes, ce processus est satisfaisant. Cependant, lorsque vous passez de trois à 100 requêtes (les cas Quepid sont souvent compris entre 50 et 100 requêtes), vous pouvez définir les besoins d'information en dehors de Quepid (par exemple, dans une feuille de calcul), puis les télécharger via <strong>Import</strong> et sélectionner <strong>Besoins d'information.</strong></p><h2>Créez une équipe dans Quepid et partagez votre cas</h2><p>Les jugements collaboratifs améliorent la qualité des évaluations de la pertinence. Mettre en place une équipe :</p><p>1. Naviguez jusqu'à <strong>Équipes</strong> dans le menu de haut niveau.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt45c51d1a0e05a80d/6a17e64fe8fbcede793a190f/797706e8d130b474a95d30b6fa22ecaf36f98c03-613x58.png" alt="Créer une équipe dans Quepid." /><p>2. Cliquez sur <strong>+ Ajouter nouveau</strong>, saisissez un nom d'équipe (par exemple, "Search Relevance Raters"), puis cliquez sur <strong>Créer.</strong></p><p>3. Ajoutez des membres en saisissant leur adresse électronique et en cliquant sur <strong>Ajouter un utilisateur</strong>.</p><p>4. Dans l'interface du dossier, sélectionnez <strong>Partager le dossier.</strong></p><p>5. Choisissez l'équipe appropriée et confirmez.</p><h2>Créer un livre de jugements dans Quepid</h2><p>Un livre dans Quepid permet à plusieurs évaluateurs d'évaluer systématiquement les paires requête/document. Pour en créer un :</p><p>1. Dans l'interface du dossier, allez dans <strong>Jugements</strong> et cliquez sur <strong>+ Créer un livre.</strong></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3543c00e0b834b3f/6a17e650e9ea87f57fa9c598/6a077f26225961150b7414463d7db04f090b68d6-896x365.png" alt="Création d'un book de jugements dans Quepid." /><p>2. Configurez le livre avec un nom descriptif, assignez-le à votre équipe, sélectionnez une méthode de notation (par exemple, DCG@10) et définissez la stratégie de sélection (un ou plusieurs évaluateurs). Utilisez les paramètres suivants pour le livre :</p><ul><li><p><strong>Nom</strong>: "Recherche de films échelle 0-3"</p></li><li><p><strong>Équipes avec lesquelles partager ce livre</strong>: Cochez la case de l'équipe que vous avez créée.</p></li><li><p><strong>Marqueur</strong>: DCG@10</p></li></ul><p>3. Cliquez sur <strong>Créer un livre.</strong></p><p>Le nom est descriptif et contient des informations sur l'objet de la recherche ("Films") ainsi que l'échelle des jugements ("0-3"). Le scoreur DCG@10 sélectionné définit la manière dont la métrique de recherche sera calculée. "DCG" est l'abréviation de <a href="https://en.wikipedia.org/wiki/Discounted_cumulative_gain">Discounted Cumulative Gain (gain cumulatif actualisé</a> ) et "@10" est le nombre de résultats à partir du sommet pris en considération lors du calcul de la mesure.</p><p>Dans ce cas, nous utilisons un indicateur qui mesure le gain d'information et le combine avec la pondération positionnelle. D'autres mesures de recherche peuvent être plus adaptées à votre cas d'utilisation et le <a href="https://opensourceconnections.com/blog/2020/02/28/choosing-your-search-relevance-metric">choix de la bonne mesure est un défi en soi.</a></p><h2>Remplir le book avec des paires requête/document</h2><p>Afin d'ajouter des paires requête/document pour l'évaluation de la pertinence, suivez les étapes suivantes :</p><p>1. Dans l'interface du cas, naviguez vers "Judgements."</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0e98583138535cc3/6a17e6520b0bed4f51dd3571/d717c5b06ae6cb42ed2b9e771486a12f738a9890-1041x218.png" alt="Remplir le book avec des paires requête/document dans Quepid." /><p>2. Sélectionnez le livre que vous avez créé.</p><p>3. Cliquez sur "Populate Book" et confirmez en sélectionnant "Refresh Query/Doc Pairs for Book."</p><p>Cette action génère des paires basées sur les meilleurs résultats de recherche pour chaque requête, prêtes à être évaluées par votre équipe.</p><h2>Laissez votre équipe d’évaluateurs humains juger </h2><p>Jusqu'à présent, les étapes franchies étaient plutôt techniques et administratives. Maintenant que cette préparation nécessaire est faite, nous pouvons laisser notre équipe de juges faire son travail. En substance, le travail du juge consiste à évaluer la pertinence d'un document particulier pour une requête donnée. Le résultat de ce processus est la liste de jugement qui contient tous les labels de pertinence pour les paires de documents de la requête jugés. Ensuite, ce processus et son interface sont expliqués plus en détail.</p><h3>Aperçu de l'interface Human Rating</h3><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt553afb07d8080421/6a17e654505ac30514ad8afc/be3016091b49655dab3354d84e6dc638f3468390-1283x664.png" alt="Comment les évaluateurs humains de Quepid interagissent avec les informations contenues dans les documents et les requêtes." /><p>L'interface Human Rating de Quepid est conçue pour des évaluations efficaces :</p><ul><li><p><strong>Requête :</strong> Affiche le terme de la recherche.</p></li><li><p><strong>Besoin d'information :</strong> Indique l'intention de l'utilisateur.</p></li><li><p><strong>Lignes directrices pour la notation :</strong> Fournit des instructions pour des évaluations cohérentes.</p></li><li><p><strong>Métadonnées du document :</strong> Présente des détails pertinents sur le document.</p></li><li><p><strong>Boutons d'évaluation :</strong> Permet aux évaluateurs d'attribuer des jugements à l'aide des raccourcis clavier correspondants.</p></li></ul><h3>Utilisation de l'interface Human Rating</h3><p>En tant qu'évaluateur humain, j'accède à l'interface via l'aperçu du livre :</p><p>1. Accédez à l'interface du dossier et cliquez sur <strong>Jugements</strong>.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0e98583138535cc3/6a17e6520b0bed4f51dd3571/d717c5b06ae6cb42ed2b9e771486a12f738a9890-1041x218.png" alt="Utilisation de l'interface Quepid Human Rating " /><p>2. Cliquez sur <strong>Plus de jugements sont nécessaires !</strong></p><p>Le système présentera une paire requête/document qui n'a pas encore été évaluée et qui nécessite des jugements supplémentaires. Elle est déterminée par la stratégie de sélection du Livre :</p><ul><li><p>Un <em>seul évaluateur</em>: Un seul jugement par paire requête/document.</p></li><li><p><em>Plusieurs évaluateurs</em>: Jusqu'à trois évaluations par paire requête/document.</p></li></ul><h3>Évaluation des paires requête/document</h3><p>Voyons quelques exemples. Lorsque vous suivrez ce guide, vous serez probablement confronté à différents films. Cependant, les principes de notation restent les mêmes.</p><p>Notre premier exemple est le film "Heroes" pour la requête <em>harrison ford</em>:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blta248e787b5e0a670/6a17e656ec0f89612d5a65ee/c1e14b0d8b04dd579471932dbe4ff72ae5692a02-981x571.png" alt="Comment remplir un book dans Quepid avec des paires requête/document." /><p>Nous examinons d'abord la requête, puis le besoin d'information et jugeons ensuite le film sur la base des métadonnées fournies.</p><p>Ce film est un résultat pertinent pour notre requête, puisque Harridson Ford en fait partie. Nous pouvons considérer subjectivement que les films plus récents sont plus pertinents, mais cela ne fait pas partie de notre besoin d'information. Nous attribuons donc à ce document la note "parfait", qui correspond à un 3 dans notre échelle de notation.</p><p>Notre prochain exemple est le film "Ford contre Ferrari" pour la requête <em>harrison ford</em>:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf5d86aac918a1e96/6a17e657414c64833e945152/052af7894506d7a765af156ba8e26ceec3559973-981x789.png" alt="Un exemple du film &quot;Ford v Ferrari&quot; pour la requête Harrison Ford dans Quepid." /><p>Selon la même pratique, nous évaluons cette requête/document en examinant la requête, le besoin d'information et la correspondance entre les métadonnées du document et le besoin d'information.</p><p>C'est un mauvais résultat. Ce résultat est probablement dû au fait que l'un des termes de notre requête, "ford", figure dans le titre. Mais Harrison Ford ne joue aucun rôle dans ce film, ni dans aucun autre. Nous attribuons donc à ce document la note "médiocre", ce qui correspond à un 0 dans notre échelle de notation.</p><p>Notre troisième exemple est le film "Action Jackson" pour la requête <em>meilleur film d'action :</em></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2cee335ddd1e6a92/6a17e6596df731d1f40a0ed7/247ab862fbc7435537709f8c96619cb331133d09-985x606.png" alt="Un exemple du film &quot;Action Jackson&quot; pour la requête de meilleur film d'action :" /><p>Cela ressemble à un film d'action, donc le besoin d'information est au moins partiellement satisfait. Cependant, la moyenne des votes est de 5,4 sur 10. Ce qui fait que ce film n'est probablement pas le meilleur film d'action de notre collection. Cela m'amènerait, en tant que juge, à attribuer à ce document la note "Passable", qui correspond à la note 1 dans notre échelle de notation.</p><p>Ces exemples illustrent le processus d'évaluation des paires requête/document avec Quepid en particulier, à un niveau élevé et aussi en général.</p><h2>Bonnes pratiques pour les évaluateurs humains</h2><p>Les exemples présentés peuvent donner l'impression qu'il est facile de parvenir à des jugements explicites. Mais la mise en place d'un programme d'évaluation humaine fiable n'est pas une mince affaire. C'est un processus plein de défis qui peut facilement compromettre la qualité de vos données :</p><ul><li><p>Les évaluateurs humains peuvent être fatigués par des tâches répétitives.</p></li><li><p>Les préférences personnelles peuvent fausser les jugements.</p></li><li><p>Les niveaux d'expertise varient d'un juge à l'autre.</p></li><li><p>Les évaluateurs jonglent souvent avec de multiples responsabilités.</p></li><li><p>La pertinence perçue d'un document peut ne pas correspondre à sa pertinence réelle par rapport à une requête.</p></li></ul><p>Ces facteurs peuvent entraîner des jugements incohérents et de faible qualité. Mais ne vous inquiétez pas - il existe des bonnes pratiques éprouvées qui peuvent vous aider à minimiser ces problèmes et à mettre en place un processus d'évaluation plus solide et plus fiable :</p><ul><li><p><strong>Évaluation cohérente :</strong> Examiner la requête, le besoin d'information et les métadonnées du document dans l'ordre.</p></li><li><p><strong>Se référer aux lignes directrices :</strong> Utiliser les lignes directrices pour la notation afin de maintenir la cohérence. Les lignes directrices en matière de notation peuvent contenir des exemples illustrant le processus de jugement et indiquant quand appliquer telle ou telle note. La vérification des évaluateurs humains après le premier lot de jugements s'est avérée être une bonne pratique pour connaître les cas limites difficiles et les domaines dans lesquels une aide supplémentaire est nécessaire.</p></li><li><p><strong>Utilisez les options :</strong> En cas d'incertitude, utilisez "I Will Judge Later" ou "I Can't Tell," en fournissant des explications si nécessaire.</p></li><li><p><strong>Faire des pauses :</strong> Des pauses régulières permettent de maintenir la qualité du jugement. Quepid facilite les pauses régulières en lançant des confettis chaque fois qu'un évaluateur humain termine un lot de jugements.</p></li></ul><p>En suivant ces étapes, vous établissez une approche structurée et collaborative pour créer des listes d'arrêts dans Quepid, améliorant ainsi l'efficacité de vos efforts d'optimisation de la pertinence des recherches.</p><h2>Étapes suivantes</h2><p>Que faire maintenant ? Les listes de jugement ne sont qu'une étape fondamentale vers l'amélioration de la qualité des résultats de recherche. Voici les prochaines étapes :</p><h3>Calculer les indicateurs et commencer à expérimenter</h3><p>Une fois que les listes de jugements sont disponibles, l'exploitation des jugements et le calcul des <a href="https://opensourceconnections.com/blog/2020/02/28/choosing-your-search-relevance-metric/">mesures de la qualité de la recherche</a> constituent une progression naturelle. Quepid calcule automatiquement la mesure configurée pour l'affaire en cours lorsque les jugements sont disponibles. Les mesures sont implémentées en tant que "Scorers" et vous pouvez fournir les vôtres lorsque les mesures supportées n'incluent pas vos préférées !</p><p>Accédez à l'interface du cas, naviguez jusqu'à <strong>Sélectionner un évaluateur</strong>, choisissez <em>DCG@10</em> et confirmez en cliquant sur <strong>Sélectionner un évaluateur</strong>. Quepid va maintenant calculer le DCG@10 par requête ainsi que la moyenne des requêtes globales afin de quantifier la qualité des résultats de recherche pour votre cas.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0d059c959b842139/6a17e65be8fbceb29b3a1913/0ff3b9918342071744d681a43d542102e927abd3-1163x551.png" alt="Comment quantifier la qualité des résultats de recherche dans Quepid. " /><p>Maintenant que la qualité de vos résultats de recherche est quantifiée, vous pouvez lancer les premières expériences. L'expérimentation commence par la formulation d'hypothèses. En examinant les trois requêtes de la capture d'écran après avoir effectué un classement, il est évident que les trois requêtes ont des performances très différentes en termes de qualité de recherche : <em>la guerre des étoiles</em> est assez performante, <em>harrison ford</em> semble correct mais le plus grand potentiel réside dans le <em>meilleur film d'action.</em></p><p>En développant cette requête, nous voyons ses résultats et pouvons nous plonger dans les détails les plus infimes et explorer les raisons pour lesquelles les documents correspondent et ce qui influence leurs scores :</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt35227761f4524a1e/6a17e65cb1e11325c579f25a/c45c6cae085a492198c0f8b7060a1a7204e3724e-1131x691.png" alt="Expérimentation de différentes requêtes pour observer leurs performances selon différents indicateurs de recherche dans Quepid." /><p>En cliquant sur "Explain Query" et en entrant dans l'onglet "Parsing", nous voyons que la requête est une DisjunctionMaxxQuery qui recherche trois champs : <em>cast</em>, <em>overview</em> et <em>title</em>:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0966653b9ab3cc9c/6a17e65efaa913171f93c84c/4a1e1bb2a9cd28e9c48e0ba16357d17ed9d3a5cf-894x557.png" alt="Expliquer l'analyse des requêtes" /><p>En général, en tant qu'ingénieurs de recherche, nous connaissons certaines spécificités de notre plateforme de recherche. Dans ce cas, nous pouvons savoir que nous avons un champ de <em>genre</em>. Ajoutons-le à la requête et voyons si la qualité de la recherche est améliorée.</p><p>Nous utilisons l'<strong>Environnement de recherche</strong> qui s'ouvre lorsque l'on sélectionne <strong>Accorder la pertinence</strong> dans l'interface du cas. Allez-y et explorez cette possibilité en ajoutant le champ des <em>genres</em> dans lequel vous effectuez votre recherche :</p>{
  "query": {
    "multi_match": {
      "query": "#$query##",
      "type": "best_fields",
      "fields": [
        "title^10",
        "overview",
        "cast",
        "genres"
      ]
    }
  }
}<p>Cliquez sur Réexécuter mes recherches ! Et consultez les résultats. Ont-ils changé ? Malheureusement, ce n'est pas le cas. Nous avons maintenant beaucoup d'options à explorer, essentiellement toutes les options de requête offertes par Elasticsearch :</p><ul><li><p>Nous pourrions augmenter le poids du champ sur le champ des genres.</p></li><li><p>Nous pourrions ajouter une fonction qui augmente les documents en fonction de leur moyenne de votes.</p></li><li><p>Nous pourrions créer une requête plus complexe qui n'augmenterait les documents en fonction de leur moyenne de vote que s'il existe une forte correspondance des genres.</p></li><li><p>…</p></li></ul><p>L'avantage d'avoir toutes ces options et de les explorer dans Quepid est que nous avons un moyen de quantifier les effets non seulement sur la requête que nous essayons d'améliorer, mais aussi sur toutes les requêtes que nous avons dans notre cas. Cela nous évite d'améliorer une requête peu performante en sacrifiant la qualité des résultats de recherche pour les autres. Nous pouvons itérer rapidement et à peu de frais et valider la valeur de notre hypothèse sans aucun risque, ce qui fait de l'expérimentation hors ligne une capacité fondamentale pour toutes les équipes de recherche.</p><h3>Mesurer la fiabilité inter-évaluateurs</h3><p>Même avec des descriptions de tâches, des besoins d'information et une interface d'évaluation humaine comme celle fournie par Quepid, les évaluateurs humains peuvent ne pas être d'accord.</p><p>Le désaccord en soi n'est pas une mauvaise chose, bien au contraire : mesurer le désaccord peut mettre en lumière des questions que vous pourriez vouloir aborder. La pertinence peut être subjective, les requêtes peuvent être ambiguës et les données peuvent être incomplètes ou incorrectes. Le <a href="https://en.wikipedia.org/wiki/Fleiss%27_kappa">Kappa de Fleiss</a> est une mesure statistique de l'accord entre les évaluateurs et il existe un cahier d'exemples dans Quepid que vous pouvez utiliser. Pour le trouver, sélectionnez <strong>Notebooks</strong> dans la navigation de haut niveau et sélectionnez le carnet <strong>Fleiss Kappa.ipynb</strong> dans le dossier <strong>examples.</strong></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt92d52b30f1fb19c1/6a17e660abe0f2224bdfe9bb/f0669ae96371368ef4d84bb28669560ef09d755c-624x61.png" alt="Comment trouver la mesure statistique Kappa de Fleiss pour l'accord entre les évaluateurs dans Quepid." /><h2>Conclusion</h2><p>Quepid vous permet de relever les défis les plus complexes en matière de pertinence des recherches et continue d'évoluer : <a href="https://github.com/o19s/quepid/blob/main/CHANGELOG.md#800----2024-02-14">à partir de la version 8, Quepid prend en charge les jugements générés par l'IA</a>, ce qui est particulièrement utile pour les équipes qui souhaitent faire évoluer leur processus de génération de jugements.</p><p>Les flux de travail de Quepid vous permettent de créer efficacement des listes d'arrêts évolutives, ce qui se traduit par des résultats de recherche qui répondent réellement aux besoins des utilisateurs. Une fois les listes de jugement établies, vous disposez d'une base solide pour mesurer la pertinence des recherches, procéder à des améliorations itératives et améliorer l'expérience des utilisateurs.</p><p>N'oubliez pas que l'optimisation de la pertinence est un processus continu. Les listes de jugement vous permettent d'évaluer systématiquement vos progrès, mais elles sont plus efficaces lorsqu'elles sont associées à l'expérimentation, à l'analyse des mesures et aux améliorations itératives.</p><h2>Lecture complémentaire</h2><ul><li><p>Docs Quepid :</p><ul><li><p><a href="https://quepid-docs.dev.o19s.com/2/quepid/32/relevancy-is-a-team-sport">La pertinence est un sport d'équipe</a></p></li><li><p><a href="https://quepid-docs.dev.o19s.com/2/quepid/18/quepid-for-human-raters">Quepid pour les évaluateurs humains</a></p></li><li><p><a href="https://quepid-docs.dev.o19s.com/2/quepid/49/how-to-connect-quepid-to-elastic-cloud">Comment connecter Quepid à Elastic Cloud ?</a></p></li></ul></li><li><p><a href="https://github.com/o19s/quepid">Dépôt Github de Quepid</a></p></li><li><p><a href="https://opensourceconnections.com/blog/2020/07/07/meet-pete-the-e-commerce-search-product-manager/">Meet Pete, une série de blogs sur l'amélioration de la recherche dans le domaine du commerce électronique</a></p></li><li><p><a href="https://opensourceconnections.com/slack">Relevance Slack</a>: rejoignez le canal #quepid</p></li></ul><p><strong>Associez-vous à </strong><a href="https://opensourceconnections.com/"><strong>Open Source Connections</strong></a> pour transformer vos capacités de recherche et d'IA et donner à votre équipe les moyens de les faire évoluer en permanence. Nous avons fait nos preuves dans le monde entier et nos clients ont constamment amélioré la qualité de leurs recherches, les capacités de leurs équipes et les performances de leurs entreprises. <a href="https://opensourceconnections.com/contact/">Contactez-nous dès aujourd'hui</a> pour en savoir plus.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/quepid-judgement-lists</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/quepid-judgement-lists</guid>
    <category><![CDATA[Pertinence]]></category>
    <dc:creator><![CDATA[Daniel Wrigley]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte6779c72c7a42a5a/6a17e6623e9e45acf0ba146b/307c1774bd31f92bb4aa7b69e1a6796240465100-1600x914.png" length="0" type="image/png"/>
    <pubDate>Mon, 26 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[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[Scaling des modèles d'interaction tardive dans Elasticsearch - 2e partie]]></title>
    <description><![CDATA[Cet article explore des techniques pour préparer les vecteurs d'interaction tardive aux charges de travail de production à grande échelle, notamment la réduction de l’espace disque et l’amélioration de l’efficacité des calculs.]]></description>
    <content:encoded><![CDATA[<p>Dans notre <a href="https://www.elastic.co/search-labs/blog/elastiacsearch-colpali-document-search">article précédent sur ColPali</a>, nous avons exploré comment créer des applications de recherche visuelle avec Elasticsearch. Nous nous sommes principalement concentrés sur la valeur que des modèles tels que ColPali apportent à nos applications, mais ils présentent des inconvénients en termes de performances par rapport à la recherche vectorielle avec des bi-encodeurs tels que E5.</p><p>S’appuyant sur les exemples de <a href="https://www.elastic.co/search-labs/blog/elastiacsearch-colpali-document-search">la première partie</a>, ce blog explore comment utiliser différentes techniques et la puissante boîte à outils de recherche vectorielle d’Elasticsearch afin de préparer les vecteurs d’interaction tardive pour des charges de production à grande échelle.</p><p>Les exemples complets de code sont disponibles sur <a href="https://github.com/elastic/elasticsearch-labs/tree/main/supporting-blog-content/colpali">GitHub.</a></p><h2>Défis des modèles d’interaction tardive</h2><p>ColPali crée plus de 1000 vecteurs par page pour les documents dans notre index.</p><p>Travailler avec des vecteurs d'interaction tardive présente alors deux défis :</p><ol><li><p>Espace disque : l’enregistrement de tous ces vecteurs sur disque entraînera une consommation de stockage considérable, ce qui s’avérera coûteux à grande échelle..</p></li><li><p>Calcul : Lors du classement de nos documents avec la comparaison <code>maxSimDotProduct()</code> , nous devons comparer tous ces vecteurs pour chacun de nos documents avec les N vecteurs de notre requête.</p></li></ol><p>Examinons quelques techniques pour remédier à ces problèmes.</p><h2>Techniques pour optimiser les modèles d'interactions tardives</h2><h3>Vecteurs de bits</h3><p>Afin de réduire l'espace disque, nous pouvons compresser les images en vecteurs binaires. Nous pouvons utiliser une simple fonction Python pour transformer nos multi-vecteurs en vecteurs de bits :</p>def to_bit_vectors(embeddings: list) -&gt; list:
    return [
        np.packbits(np.where(np.array(embedding) &gt; 0, 1, 0))
        .astype(np.int8)
        .tobytes()
        .hex()
        for embedding in embeddings
    ]<p>Le concept de noyau de la fonction est simple : les valeurs supérieures à 0 deviennent 1, et les valeurs inférieures à 0. Cela aboutit à un tableau de 0 et de 1, que nous transformons ensuite en une chaîne hexadécimale représentant notre vecteur de bits.</p><p>Pour le mapping de notre index, nous avons défini le paramètre <code>element_type</code> sur <code>bit</code>:</p>mappings = {
    "mappings": {
        "properties": {
            "col_pali_vectors": {
                "type": "rank_vectors",
                "element_type": "bit"
            }
        }
    }
}

es.indices.create(index=INDEX_NAME, body=mappings)<p>Après avoir écrit tous nos nouveaux vecteurs de bits dans notre index, nous pouvons classer nos vecteurs de bits en utilisant le code suivant :</p>query = "What do companies use for recruiting?"
query_vector = to_bit_vectors(create_col_pali_query_vectors(query))
es_query = {
    "_source": False,
    "query": {
        "script_score": {
            "query": {
                "match_all": {}
            },
            "script": {
                "source": "maxSimInvHamming(params.query_vector, 'col_pali_vectors')",
                "params": {
                    "query_vector": query_vector
                }
            }
        }
    },
    "size": 5
}<img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcaf0c8f999d68701/6a17f46696142a6f46eb1c56/51b989446e4099745971e1eac27d147a78d13e0a-1600x480.png" alt="" /><p>En échange d'un peu de précision, cela nous permet d'utiliser la distance de hamming (<code>maxSimInvHamming(...)</code>), qui est capable de tirer parti d'optimisations telles que les masques de bits, SIMD, etc. Pour en savoir plus sur les <a href="https://www.elastic.co/search-labs/blog/bit-vectors-in-elasticsearch">vecteurs binaires et la distance de hamming, consultez notre blog</a>.</p><p>Sinon, nous ne pouvons pas convertir notre vecteur de requête en vecteurs de bits et rechercher à l'aide du vecteur d'interaction tardive en pleine fidélité :</p>query = "What do companies use for recruiting?"
query_vector = create_col_pali_query_vectors(query)
es_query = {
    "_source": False,
    "query": {
        "script_score": {
            "query": {
                "match_all": {}
            },
            "script": {
                "source": "maxSimDotProduct(params.query_vector, 'col_pali_vectors')",
                "params": {
                    "query_vector": query_vector
                }
            }
        }
    },
    "size": 5
}<img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2fa6c89fb451b6e0/6a17f468af47b65da9cde0d9/89f3c795c6dc44b2f7d46801320288316b47e1b2-1600x488.png" alt="Résultats de l'utilisation de vecteurs de bits pour optimiser les modèles d'interaction tardive" /><p>Cela comparera nos vecteurs en utilisant une fonction de similarité asymétrique.</p><p></p><p>Considérons une distance de Hamming standard entre deux vecteurs de bits.. Supposons que nous ayons un vecteur de document <em>D :</em></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltd4b6ece1ec4dedac/6a17f4694b055d248143234e/366a70a23e37d403788327b7aefc873fd4482f5e-1235x86.png" alt="" /><p>Et un vecteur de requête <em>Q :</em></p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt7721df9c8f0d84f1/6a17f46b3e03d77cf54f2dcb/978ec31e0afbc0eaebf548a015b628c0cad84625-1247x84.png" alt="" /><p></p><p>La quantification binaire simple transformera les vecteurs <em>D</em> en <code>10101101</code> et <em>Q</em> en <code>11111011</code>. Pour trouver la distance de Hamming, il faut des calculs directs en bits — c’est extrêmement rapide. Dans ce cas, la distance de hamming est <code>01010110</code>, qui a un nombre de bits de 4. La notation devient donc l'inverse de cette distance de hamming. Rappelez-vous : plus les vecteurs sont similaires, plus la distance de Hamming est petite. L'inverser permet aux vecteurs les plus similaires d'être mieux notés. Plus précisément ici, le score serait 1/4 = <code>0.25</code>.</p><p>Cependant, remarquez comment nous perdons l'ampleur de chaque dimension. Un <code>1</code> est un <code>1</code>. Ainsi, pour <em>Q</em>, la différence entre <code>0.01</code> et <code>0.79</code> disparaît. Puisque nous quantifions simplement selon <code>&gt;0</code>, nous pouvons faire une petite astuce où le vecteur Q n'est pas quantifié. Cela ne permet pas des calculs bit à bit extrêmement rapides, mais cela maintient le coût de stockage bas car D est toujours quantifié.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blted50315518e2d599/6a17f46c414c6463709452d3/508e8498ba969534d2a0131d431c75735fc27cb9-1399x611.png" alt="" /><p>En résumé, cette méthode conserve les informations fournies dans <em>Q</em>, ce qui permet d’améliorer la qualité de l’estimation de la distance tout en limitant la consommation de stockage.</p><p>L'utilisation de vecteurs de bits nous permet d'économiser de manière significative de l'espace disque et de la charge de calcul au moment de la requête. Mais nous pouvons faire davantage.</p><h3>Vecteurs moyens</h3><p>Pour scaler notre recherche sur des centaines de milliers de documents, même les avantages de performance que nous apportent les vecteurs de bits ne seront pas suffisants. Afin de scaler à ces types de charges de travail, nous voudrons exploiter la structure d'index HNSW d'Elasticsearch pour la recherche vectorielle.</p><p>ColPali génère environ un millier de vecteurs par document, ce qui est trop pour les ajouter à notre graphe HNSW. Nous devons donc réduire le nombre de vecteurs. Pour cela, nous pouvons créer une représentation unique de la signification du document en prenant la moyenne de tous les vecteurs de documents produits par ColPali lors de l’intégration de notre image.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc053425fbfcf8de8/6a17f46f148009faf1b488aa/7c3b4dffb70bd95f67deb35f8c01e73c5286c2ab-1476x1102.png" alt="Vecteur moyen sur tous les vecteurs d’interaction tardive" /><p>Pour l’instant, cela n’est pas possible au sein d’Elastic. Nous devrons donc prétraiter les vecteurs avant de les ingérer dans Elasticsearch. </p><p>Nous pouvons le faire avec Logstash ou des pipelines d'ingestion, mais ici nous utiliserons une simple fonction Python :</p>def to_avg_vector(vectors):
    vectors_array = np.array(vectors)
    
    avg_vector = np.mean(vectors_array, axis=0)
    
    norm = np.linalg.norm(avg_vector)
    if norm &gt; 0:
        normalized_avg_vector = avg_vector / norm
    else:
        normalized_avg_vector = avg_vector

    return normalized_avg_vector.tolist()<p>Nous normalisons également le vecteur afin de pouvoir utiliser la similarité par produit scalaire.</p><p>Après avoir transformé tous nos vecteurs ColPali en vecteurs moyens, nous pouvons les indexer dans notre champ dense_vector :</p>mappings = {
    "mappings": {
        "properties": {
            "avg_vector": {
                "type": "dense_vector",
                "dims": 128,
                "index": True,
                "similarity": "dot_product"
            },
            "col_pali_vectors": {
                "type": "rank_vectors",
                "element_type": "bit"
            }
        }
    }
}

es.indices.create(index=INDEX_NAME, body=mappings)<p>Il faut considérer que cela accroîtra l’utilisation globale du disque, car nous sauvegardons des données supplémentaires parallèlement à nos vecteurs d'interaction tardive. En outre, nous utiliserons de la RAM supplémentaire pour contenir le graphe HNSW, ce qui nous permettra de scaler la recherche à des milliards de vecteurs. Pour réduire l’utilisation de la RAM, nous pouvons utiliser notre <a href="https://www.elastic.co/search-labs/blog/optimized-scalar-quantization-elasticsearch">fonctionnalité BBQ</a> populaire. À notre tour, nous obtenons des résultats de recherche rapides sur d'énormes ensembles de données qui ne seraient autrement pas possibles.</p><p>À présent, nous recherchons simplement à l'aide de la requête knn pour trouver nos documents les plus pertinents.</p>query = "What do companies use for recruiting?"
query_vector = to_avg_vector(create_col_pali_query_vectors(query))
es_query = {
    "_source": False,
    "knn": {
        "field": "avg_vector",
        "query_vector": query_vector,
        "k": 10,
        "num_candidates": 100
    },
    "size": 5
}<img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltf4ac6b7fd444f935/6a17f471a29299d76ad02dc0/a500f9907020f032c3b1c7a48ed8c759dc2a1dd4-1600x498.png" alt="" /><p>Le meilleur résultat précédent a malheureusement été relégué au troisième rang.</p><p>Pour résoudre ce problème, nous pouvons effectuer une récupération en plusieurs étapes. Dans notre première étape, nous utilisons la requête knn pour rechercher les meilleurs candidats pour notre requête parmi des millions de documents. Dans la deuxième étape, nous ne classons que les k premiers (ici : 10) avec la plus grande fidélité des vecteurs d'interaction tardive de ColPali. </p>query = "What do companies use for recruiting?"
col_pali_vector = create_col_pali_query_vectors(query)
avg_vector = to_avg_vector(col_pali_vector)
es_query = {
  "_source": False,
  "retriever": {
    "rescorer": {
      "retriever": {
        "knn": {
          "field": "avg_vector",
          "query_vector": avg_vector,
          "k": 10,
          "num_candidates": 100
        }
      },
      "rescore": {
        "window_size": 10,
        "query": {
          "rescore_query": {
            "script_score": {
              "query": {
                "match_all": {}
              },
              "script": {
                "source": "maxSimDotProduct(params.query_vector, 'col_pali_vectors')",
                "params": {
                  "query_vector": col_pali_vector
                }
              }
            }
          }
        }
      }
    }
  },
  "size": 5
}<img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt265edd5f37be40b7/6a17f4733e9e45583dba15e6/797f490860af87fcf29f34668a5c4511419c6fd0-1600x501.png" alt="Résultats de l'utilisation des vecteurs moyens pour l'optimisation des modèles d'interaction tardive" /><p>Ici, nous utilisons l'outil <a href="https://www.elastic.co/guide/en/elasticsearch/reference/8.18/retriever.html#rescorer-retriever">rescore retriever</a> introduit en 8.18 pour reclasser nos résultats. Après un nouveau calcul des scores, nous constatons que notre meilleur match se retrouve à nouveau en première position. </p><p>Remarque : Dans une application de production, nous pouvons utiliser un k bien supérieur à 10 car la fonction Max Sim est toujours relativement performante.</p><h3>Regroupement de jetons</h3><p>Le pooling de tokens réduit la longueur de séquence des plongements multi-vectoriels en regroupant les informations redondantes, comme les zones de fond blanc. Cette technique réduit le nombre de plongements tout en préservant la majeure partie du signal de la page.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3d643e6ac908f640/6a17f4754b055d3783432352/09eae0b768f4b450e555d7e53e57561bd52de2c0-1412x1056.png" alt="Pooling de tokens pour optimiser les modèles d'interaction tardive" /><p>Le pooling de jetons fonctionne en regroupant des embeddings de jetons similaires au sein d'un document en clusters à l'aide d'un algorithme de clustering. Ensuite, la moyenne des vecteurs dans chaque groupe est calculée pour créer une représentation unique et agrégée. Ce vecteur agrégé remplace les tokens originaux dans le groupe, réduisant ainsi le nombre total de vecteurs sans perte significative du signal du document.</p><p>Le document ColPali propose une valeur initiale de facteur de pool de 3 pour la plupart des ensembles de données, ce qui assure la maintenance de 97,8 % des performances originales tout en réduisant le nombre total de vecteurs de 66,7 %. </p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2d78a15c6944a1ea/6a17f477414c64a2929452d9/343cc9eaf54af8c7a125d4115838f3c7d5659de0-1600x1007.png" alt="Facteur pool pour optimiser les modèles d'interactions tardives" /><p>Mais attention : l’ensemble de données « Shift », qui contient des documents très denses et riches en texte avec peu d’espace blanc, voit ses performances se dégrader rapidement à mesure que les facteurs de regroupement augmentent.</p><p>Pour créer les vecteurs regroupés, nous pouvons utiliser la bibliothèque colpali_engine :</p>from colpali_engine.compression.token_pooling import HierarchicalTokenPooler

pooler = HierarchicalTokenPooler(pool_factor=3) # test on your data for a good pool_factor

def pool_vectors(embedding: list) -&gt; list:
    tensor = torch.tensor(embedding).unsqueeze(0)
    pooled = pooler.pool_embeddings(tensor)
    return pooled.squeeze(0).tolist()<p>Nous avons maintenant un vecteur dont les dimensions ont été réduites d’environ 66,7 %. Nous l'indexons comme d'habitude et nous pouvons rechercher dessus avec notre fonction <code>maxSimDotProduct()</code>.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc460c14031814ede/6a17f4794202292bf629f72d/2412c5db7d79a590b96d42fe01f140c42f010612-1600x481.png" alt="Résultats des modèles à interaction tardive" /><p>Nous pouvons obtenir de bons résultats de recherche au détriment d’une légère précision dans les résultats.</p><p>Conseil : avec un pool_factor plus élevé (100-200), vous pouvez également obtenir un juste milieu entre la solution vectorielle moyenne et celle dont nous avons discuté ici. Avec environ 5 à 10 vecteurs par document, il devient possible de les indexer dans un champ imbriqué pour tirer parti de l'index HNSW.</p><h2>Encodeur Coss vs. encodeur à interaction tardive vs. bi-encodeur</h2><p>Compte tenu de ces éléments, quelle est la place des modèles d'interaction tardive (comme ColPali ou ColBERT) vis-à-vis des autres méthodes de récupération de données par IA ?</p><p>Bien que la fonction de simulation maximale soit moins chère que les encodeurs croisés, elle nécessite néanmoins beaucoup plus de comparaisons et de calculs que la recherche vectorielle avec des bi-encodeurs, où nous comparons simplement deux vecteurs pour chaque paire requête-document. </p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltbfd97f3bba3e5b17/6a17f47be31791b0052d5943/75e1fc9e601aa7a6e88f137565c1919166c7a71c-1480x458.png" alt="Cross-encodeur vs. modèles à interaction tardive vs. bi-encodeur" /><p>Pour cette raison, nous recommandons d'utiliser les modèles d'interaction tardive uniquement pour le reclassement des k premiers résultats de recherche. Nous le reflétons également dans le nom du type de champ : rank_vectors.</p><p>Mais qu'en est-il de l'encodeur croisé ? Les modèles d'interaction tardive sont-ils meilleurs parce qu'ils sont moins chers à exécuter au moment de la requête ? Comme c'est souvent le cas, la réponse est : cela dépend. Les encodeurs croisés produisent généralement des résultats de meilleure qualité, mais ils nécessitent beaucoup de calcul car les paires de documents de requête doivent effectuer un passage complet à travers le modèle transformateur. Ils bénéficient également du fait qu'ils ne nécessitent aucune indexation de vecteurs et peuvent fonctionner de manière apatride. Résultats obtenus :</p><ul><li><p>Moins d'espace disque utilisé</p></li><li><p>Un système plus simple</p></li><li><p>Qualité supérieure des résultats de recherche</p></li><li><p>Latence plus élevée, et donc impossible à repositionner aussi profondément</p></li></ul><p>D'autre part, les modèles d'interaction tardive peuvent décharger une partie de ce calcul sur l'index, ce qui rend la requête moins coûteuse. Le prix à payer est la nécessité d’indexer les vecteurs, ce qui complexifie nos pipelines d’ingestion et nécessite davantage d’espace disque pour sauvegarder ces données.</p><p>Dans le cas particulier de ColPali, l'analyse des informations contenues dans les images est très coûteuse car elles contiennent beaucoup de données. Dans ce cas, le compromis penche en faveur de l'utilisation d'un modèle d'interaction tardive tel que ColPali, car évaluer ces informations au moment de la requête serait trop gourmand en ressources/lent. </p><p>Pour un modèle d’interaction tardif comme ColBERT, qui fonctionne sur des données textuelles comme la plupart des encodeurs croisés (par exemple, elastic-rerank-v1), la décision pourrait plutôt pencher vers l’utilisation du codeur croisé pour bénéficier des économies et de la simplicité du disque.</p><p>Nous vous encourageons à peser le pour et le contre en fonction de votre cas d'utilisation et à expérimenter les différents outils qu'Elasticsearch met à votre disposition pour créer les meilleures applications de recherche.</p><h2>Conclusion</h2><p>Dans ce blog, nous avons exploré diverses techniques pour optimiser les modèles d'interaction tardive comme ColPali pour la recherche vectorielle à grande échelle dans Elasticsearch. Bien que les modèles d'interaction tardive offrent un bon équilibre entre l'efficacité de la récupération et la qualité du classement, ils présentent également des défis liés au stockage et au calcul.</p><p>Pour relever ces défis, nous avons examiné :</p><ul><li><p>Des <strong>vecteurs de bits</strong> pour réduire de manière significative l'espace disque tout en tirant parti de calculs de similarité efficaces, tels que la distance de Hamming ou la similarité maximale asymétrique.</p></li><li><p>Des <strong>vecteurs moyens</strong> pour compresser plusieurs intégrations en une seule représentation dense, permettant ainsi une récupération efficace grâce à l'indexation HNSW.</p></li><li><p>Le <strong>pooling de jetons</strong> permet de fusionner intelligemment les embeddings redondants tout en assurant la maintenance de l’intégrité sémantique, réduisant ainsi la surcharge de calcul au moment de la requête.</p></li></ul><p>Elasticsearch offre une boîte à outils puissante pour personnaliser et optimiser les applications de recherche selon vos besoins. Que vous privilégiez la vitesse de récupération, la qualité de classement ou l'efficacité de stockage, ces outils et techniques vous permettent d'équilibrer les performances et la qualité selon vos besoins pour vos applications du monde réel.</p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/late-interaction-model-colpali-scale</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/late-interaction-model-colpali-scale</guid>
    <category><![CDATA[Pertinence]]></category>
    <category><![CDATA[Base vectorielle]]></category>
    <dc:creator><![CDATA[Peter Straßer,Benjamin Trent]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt97a536033e6b0a56/6a17f47dfbc5f88c86491c0d/c780b78a07573f2df1cfef8b29a7109f839b0ab3-1200x628.png" length="0" type="image/png"/>
    <pubDate>Thu, 20 Mar 2025 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>