Analyseurs pour le traitement de texte dans Recherche Azure AI

Un analyseur est un composant du moteur de recherche en texte intégral chargé de traiter les chaînes durant l’indexation et l’exécution des requêtes. Le traitement du texte (également appelé analyse lexicale) est à l’origine de transformations. Il modifie une chaîne via des actions telles que celles-ci :

  • Supprimer les mots (mots vides) et la ponctuation non essentiels
  • Segmenter des expressions et des mots avec tirets en différents composants
  • Mettre les mots en majuscules en minuscules
  • Réduire les mots dans des formes racines primitives pour une efficacité de stockage et de sorte que des correspondances puissent être trouvées, quels que soient les temps

L’analyse s’applique à des champs Edm.String marqués comme étant « interrogeables », ce qui indique une recherche en texte intégral.

Pour les champs ayant cette configuration, l’analyse a lieu pendant l’indexation lors de la création de jetons, puis à nouveau lors de l’exécution de requêtes lorsque ces dernières sont analysées et que le moteur recherche les jetons correspondants. Une correspondance est plus probable lorsque le même analyseur est utilisé à la fois pour l’indexation et pour les requêtes, mais vous pouvez définir l’analyseur de manière indépendante pour chaque charge de travail, en fonction de vos besoins.

Les types de requêtes qui ne sont pas une recherche en texte intégral, comme les filtres ou la recherche approximative, ne passent pas par la phase d’analyse du côté de la requête. Au lieu de cela, l’analyseur envoie ces chaînes directement au moteur de recherche, à l’aide du modèle que vous fournissez comme base pour la correspondance. Ces formulaires de requête nécessitent généralement des jetons de chaîne entière pour effectuer un travail de correspondance de modèle. Pour vous assurer que les jetons de terme entiers sont conservés pendant l’indexation, vous aurez peut-être besoin d’analyseurs personnalisés. Pour plus d’informations sur le moment et la raison de l’analyse des termes de la requête, consultez Recherche en texte intégral dans la Recherche Azure AI.

Pour plus d’informations sur l’analyse lexicale, regardez le clip vidéo suivant, qui donne une brève explication.

Analyseur par défaut

Dans Recherche Azure AI, un analyseur est automatiquement appelé sur tous les champs de chaînes marqués comme pouvant faire l’objet d’une recherche.

Par défaut, la Recherche Azure AI utilise l’analyseur Apache Lucene Standard (lucene standard), qui décompose le texte en éléments en suivant les règles de la « Segmentation du texte Unicode ». L’analyseur standard convertit tous les caractères en minuscules. Les documents indexés et les termes de recherche sont analysés pendant l'indexation et le traitement des requêtes.

Vous pouvez substituer l’analyseur par défaut champ par champ. Les autres analyseurs sont les suivants :

Types d’analyseurs

La liste suivante décrit les analyseurs disponibles dans Recherche Azure AI.

Category Description
Analyseur Lucene standard Par défaut. Aucune spécification ou configuration n’est nécessaire. Cet analyseur à usage général est efficace pour de nombreux scénarios et langues.
Analyseurs intégrés Consommés tels quels et référencés par nom. Il existe deux types : linguistique et agnostique.

Les analyseurs spécialisés (non dépendants de la langue) sont employés quand les entrées de texte nécessitent un traitement spécialisé ou minimal. Exemples d’analyseurs dans cette catégorie : Asciifolding, Keyword, Pattern, Simple, Stop, Whitespace.

Utilisez les analyseurs linguistiques quand vous avez besoin d’une prise en charge linguistique avancée pour différentes langues. La Recherche Azure AI prend en charge 35 analyseurs linguistiques Lucene et 50 analyseurs de traitement en langage naturel Microsoft.
Analyseurs personnalisés Ils renvoient à une configuration définie par l’utilisateur constituée d’une combinaison d’éléments existants, dont un générateur de jetons (obligatoire) et des filtres facultatifs (caractères ou jetons).

Certains analyseurs intégrés, comme Pattern ou Stop, prennent en charge un ensemble limité d’options de configuration. Pour définir ces options, créez un analyseur personnalisé constitué de l’analyseur intégré et d’une des autres options documentées dans Analyseurs intégrés. Comme pour toute configuration personnalisée, nommez votre nouvelle configuration (par exemple, MonAnalyseurSéquencesOctets) pour la distinguer de l’analyseur Lucene Pattern.

Spécification d’analyseurs

La définition d’un analyseur est facultative. En règle générale, essayez d’abord d’utiliser l’analyseur Lucene standard par défaut pour voir comment il fonctionne. Si les requêtes ne renvoient pas les résultats attendus, le passage à un autre analyseur est souvent la bonne solution.

  1. Si vous utilisez un analyseur personnalisé, ajoutez-le à l’index de recherche sous la section « Analyseur ». Pour plus d’informations, consultez Créer un index et Ajouter des analyseurs personnalisés.

  2. Lors de la définition d’un champ, définissez sa propriété « analyzer » sur l’un des éléments suivants : un analyseur intégré tel que Keyword, un analyseur linguistique tel que en.microsoft ou un analyseur personnalisé (défini dans le même schéma d’index).

      "fields": [
     {
       "name": "Description",
       "type": "Edm.String",
       "retrievable": true,
       "searchable": true,
       "analyzer": "en.microsoft",
       "indexAnalyzer": null,
       "searchAnalyzer": null
     },
    
  3. Si vous utilisez un analyseur linguistique, vous devez utiliser la propriété « analyzer » pour le spécifier. Les propriétés « searchAnalyzer » et « indexAnalyzer » n’appliquent pas les analyseurs linguistiques.

  4. Vous pouvez également définir « indexAnalyzer » et « searchAnalyzer » afin de changer d’analyseur pour chaque charge de travail. Ces propriétés fonctionnent ensemble en tant que substitut de la propriété « analyzer », qui doit être null. Vous pouvez utiliser différents analyseurs pour l’indexation et les requêtes si l’une de ces activités nécessite une transformation spécifique et l’autre non.

      "fields": [
     {
       "name": "ProductGroup",
       "type": "Edm.String",
       "retrievable": true,
       "searchable": true,
       "analyzer": null,
       "indexAnalyzer": "keyword",
       "searchAnalyzer": "standard"
     },
    

Quand ajouter des analyseurs

La phase de développement actif est le meilleur moment pour ajouter et affecter des analyseurs, là où la suppression et la recréation d’index sont des activités courantes.

Étant donné que les analyseurs sont utilisés pour créer des jetons pour les termes, vous devez affecter un analyseur lors de la création du champ. En fait, l’attribution d’une propriété « analyzer » ou « indexAnalyzer » à un champ déjà créé physiquement n’est pas autorisée, même si vous pouvez modifier la propriété searchAnalyzer à tout moment sans aucun impact sur l’index.

Pour modifier l’analyseur d’un champ existant, vous devez ignorer et recréer entièrement l’index (vous ne pouvez pas recréer des champs individuels). Pour les index en production, vous devez retarder une regénération en créant un champ avec la nouvelle affectation d’analyseur et commencer à l’utiliser à la place de l’ancien. Utilisez Mettre à jour l’index pour incorporer le nouveau champ et mergeOrUpload pour le remplir. Par la suite, pendant l’opération de maintenance planifiée de l’index, vous pouvez le nettoyer de façon à supprimer les champs obsolètes.

Pour ajouter un nouveau champ à un index existant, appelez Mettre à jour l’index et mergeOrUpload pour le remplir.

Pour ajouter un analyseur personnalisé à un index existant, transférez l’indicateur « allowIndexDowntime » dans Mettre à jour l’index si vous souhaitez éviter cette erreur :

"Index update not allowed because it would cause downtime. In order to add new analyzers, tokenizers, token filters, or character filters to an existing index, set the 'allowIndexDowntime' query parameter to 'true' in the index update request. Note that this operation will put your index offline for at least a few seconds, causing your indexing and query requests to fail. Performance and write availability of the index can be impaired for several minutes after the index is updated, or longer for very large indexes."

Suggestions pour utiliser des analyseurs

Cette section offre des conseils pour utiliser les analyseurs.

Un même analyseur pour les opérations de lecture-écriture, sauf besoins spécifiques

La Recherche Azure AI vous permet de spécifier différents analyseurs pour l’indexation et la recherche via les propriétés de champ « indexAnalyzer » et « searchAnalyzer ». Par défaut, l’analyseur défini avec la propriété analyzer est utilisé pour l’indexation et la recherche. Si l’analyseur n’est pas spécifié, l’analyseur Lucene standard est utilisé par défaut.

En règle générale, il est préférable d’utiliser le même analyseur pour l’indexation et l’interrogation, sauf si des besoins spécifiques vous obligent à faire autrement. Veillez à effectuer des tests approfondis. Quand il existe une divergence de traitement de texte pendant la recherche et l’indexation, le risque est que les termes de la requête et les termes indexés ne correspondent pas si la configuration de l’analyseur de recherche et celle de l’analyseur d’indexation ne sont pas conformes.

Effectuer des tests pendant le développement actif

La substitution de l’analyseur standard nécessite une regénération de l’index. Si possible, choisissez les analyseurs à utiliser pendant le développement actif, avant de déployer l’index dans un environnement de production.

Examiner les termes sous forme de jetons

Si une recherche ne renvoie pas les résultats attendus, cela est très probablement dû aux différences de jetons entre les termes entrés dans la requête et les termes sous forme de jetons présents dans l’index. Si les jetons ne sont pas identiques, les correspondances ne sont pas détectées. Pour examiner les résultats du générateur de jetons, nous vous recommandons d’utiliser l’API d’analyse comme outil d’investigation. La réponse se compose de jetons qui sont générés par un analyseur spécifique.

Exemples REST

Les exemples ci-dessous montrent des définitions d’analyseur pour quelques scénarios clés.

Exemple d’analyseur personnalisé

Cet exemple montre une définition d’analyseur avec des options personnalisées. Les options personnalisées pour les filtres de caractères, les générateurs de jetons et les filtres de jetons sont spécifiées séparément comme des constructions nommées, puis elles sont référencées dans la définition de l’analyseur. Les éléments prédéfinis sont utilisés tels quels et sont référencés par leur nom.

Si nous suivons cet exemple :

  • Les analyseurs sont une propriété de la classe d’un champ pouvant faire l’objet d’une recherche.

  • Un analyseur personnalisé fait partie d’une définition d’index. Il peut faire l’objet d’une légère personnalisation (par exemple, la personnalisation d’une option d’un filtre) ou d’une personnalisation à plusieurs endroits.

  • Dans ce cas, l’analyseur personnalisé est « my_analyzer », qui utilise alors le générateur de jetons standard personnalisé « my_standard_tokenizer », et deux filtres de jetons : le filtre « lowercase » et le filtre asciifolding personnalisé « my_asciifolding ».

  • Il définit également les deux filtres de caractères personnalisés « map_dash » et « remove_whitespace ». Le premier remplace tous les tirets par des traits de soulignement et le second supprime tous les espaces. Les espaces doivent être encodés en UTF-8 dans les règles de mappage. Les filtres de caractères sont appliqués avant la segmentation du texte en unités lexicales et affectent les jetons qui en résultent (les tirets et les espaces provoquent l'arrêt du générateur de jetons, mais pas les traits de soulignement).

  {
     "name":"myindex",
     "fields":[
        {
           "name":"id",
           "type":"Edm.String",
           "key":true,
           "searchable":false
        },
        {
           "name":"text",
           "type":"Edm.String",
           "searchable":true,
           "analyzer":"my_analyzer"
        }
     ],
     "analyzers":[
        {
           "name":"my_analyzer",
           "@odata.type":"#Microsoft.Azure.Search.CustomAnalyzer",
           "charFilters":[
              "map_dash",
              "remove_whitespace"
           ],
           "tokenizer":"my_standard_tokenizer",
           "tokenFilters":[
              "my_asciifolding",
              "lowercase"
           ]
        }
     ],
     "charFilters":[
        {
           "name":"map_dash",
           "@odata.type":"#Microsoft.Azure.Search.MappingCharFilter",
           "mappings":["-=>_"]
        },
        {
           "name":"remove_whitespace",
           "@odata.type":"#Microsoft.Azure.Search.MappingCharFilter",
           "mappings":["\\u0020=>"]
        }
     ],
     "tokenizers":[
        {
           "name":"my_standard_tokenizer",
           "@odata.type":"#Microsoft.Azure.Search.StandardTokenizerV2",
           "maxTokenLength":20
        }
     ],
     "tokenFilters":[
        {
           "name":"my_asciifolding",
           "@odata.type":"#Microsoft.Azure.Search.AsciiFoldingTokenFilter",
           "preserveOriginal":true
        }
     ]
  }

Exemple d’affectation d’analyseur par champ

L’analyseur standard est celui qui est utilisé par défaut. Supposons que vous souhaitiez remplacer l’analyseur par défaut par un autre analyseur prédéfini, tel que l’analyseur de pattern. Si vous ne définissez pas d’options personnalisées, vous devez uniquement le spécifier par son nom dans la définition du champ.

L’élément « analyzer » remplace l’analyseur standard champ après champ. Aucun remplacement global n’est possible. Dans cet exemple, text1 utilise l’analyseur de pattern, et text2, qui ne spécifie pas d’analyseur, utilise celui par défaut.

  {
     "name":"myindex",
     "fields":[
        {
           "name":"id",
           "type":"Edm.String",
           "key":true,
           "searchable":false
        },
        {
           "name":"text1",
           "type":"Edm.String",
           "searchable":true,
           "analyzer":"pattern"
        },
        {
           "name":"text2",
           "type":"Edm.String",
           "searchable":true
        }
     ]
  }

Combinaison d’analyseurs pour les opérations d’indexation et de recherche

Les API comprennent des attributs d’index qui permettent de spécifier des analyseurs différents pour l’indexation et la recherche. Les attributs searchAnalyzer et indexAnalyzer doivent être spécifiés sous forme de paire, en remplacement de l’attribut analyzer.

  {
     "name":"myindex",
     "fields":[
        {
           "name":"id",
           "type":"Edm.String",
           "key":true,
           "searchable":false
        },
        {
           "name":"text",
           "type":"Edm.String",
           "searchable":true,
           "indexAnalyzer":"whitespace",
           "searchAnalyzer":"simple"
        },
     ],
  }

Exemple d’analyseur linguistique

Les champs qui contiennent des chaînes dans différentes langues peuvent utiliser un analyseur linguistique, tandis que les autres champs conservent l’analyseur par défaut (ou utilisent un autre analyseur prédéfini ou personnalisé). Si vous utilisez un analyseur linguistique, vous devez l’utiliser à la fois pour les opérations d’indexation et de recherche. Les champs qui utilisent un analyseur linguistique ne peuvent pas avoir des analyseurs différents pour l’indexation et la recherche.

  {
     "name":"myindex",
     "fields":[
        {
           "name":"id",
           "type":"Edm.String",
           "key":true,
           "searchable":false
        },
        {
           "name":"text",
           "type":"Edm.String",
           "searchable":true,
           "indexAnalyzer":"whitespace",
           "searchAnalyzer":"simple"
        },
        {
           "name":"text_fr",
           "type":"Edm.String",
           "searchable":true,
           "analyzer":"fr.lucene"
        }
     ],
  }

Exemples C#

Si vous utilisez les exemples de code du SDK .NET, vous pouvez ajouter ces exemples pour utiliser ou configurez des analyseurs.

Attribuer un analyseur de langage

Tout analyseur qui est utilisé tel quel, sans configuration, est spécifié sur une définition de champ. La création d’une entrée dans la section [analyzers] de l’index n’est pas obligatoire.

Les analyseurs linguistiques sont utilisés en l’état. Pour vous en servir, appelez LexicalAnalyzer en spécifiant le type LexicalAnalyzerName et en indiquant un analyseur de texte pris en charge dans la Recherche Azure AI.

Les analyseurs personnalisés sont spécifiés de la même façon dans la définition du champ. Pour que cela fonctionne, vous devez néanmoins préciser l’analyseur dans la définition de l’index (cf. section suivante).

    public partial class Hotel
    {
       . . . 
        [SearchableField(AnalyzerName = LexicalAnalyzerName.Values.EnLucene)]
        public string Description { get; set; }

        [SearchableField(AnalyzerName = LexicalAnalyzerName.Values.FrLucene)]
        [JsonPropertyName("Description_fr")]
        public string DescriptionFr { get; set; }

        [SearchableField(AnalyzerName = "url-analyze")]
        public string Url { get; set; }
      . . .
    }

Définir un analyseur personnalisé

Lorsqu’une personnalisation ou une configuration est requise, ajoutez une construction de l’analyseur à un index. Une fois que vous la définissez, vous pouvez l’ajouter à la définition de champ comme illustré dans l’exemple précédent.

Créez un objet CustomAnalyzer. Un analyseur personnalisé est une combinaison définie par l’utilisateur d’un jeton connu, de zéro, un ou plusieurs filtres de jeton et de zéro, un ou plusieurs noms de filtres de caractères :

Dans l’exemple suivant est créé un analyseur personnalisé nommé « url-analyze » qui utilise le générateur de jetons uax_url_email et le filtre de jeton Lowercase.

private static void CreateIndex(string indexName, SearchIndexClient adminClient)
{
   FieldBuilder fieldBuilder = new FieldBuilder();
   var searchFields = fieldBuilder.Build(typeof(Hotel));

   var analyzer = new CustomAnalyzer("url-analyze", "uax_url_email")
   {
         TokenFilters = { TokenFilterName.Lowercase }
   };

   var definition = new SearchIndex(indexName, searchFields);

   definition.Analyzers.Add(analyzer);

   adminClient.CreateOrUpdateIndex(definition);
}

Étapes suivantes

Vous trouverez une description détaillée de l’exécution des requêtes dans Recherche en texte intégral dans Recherche Azure AI. L’article utilise des exemples pour expliquer les comportements qui, au premier abord, peuvent sembler contre-intuitifs.

Pour en savoir plus sur les analyseurs, consultez les articles suivants :