Partager via


Démarrage rapide : Recherche en texte intégral

Dans ce guide de démarrage rapide, vous utilisez la bibliothèque cliente Azure.Search.Documents pour créer, charger et interroger un index de recherche avec des exemples de données pour la recherche en texte intégral. La recherche en texte intégral utilise Apache Lucene pour l’indexation et les requêtes et l’algorithme de classement BM25 pour les résultats de scoring.

Ce guide de démarrage rapide utilise les données d’hôtel fictives du référentiel azure-search-sample-data pour remplir l’index.

Conseil

Vous pouvez télécharger le code source pour commencer par un projet terminé ou suivre ces étapes pour créer votre propre code.

Prérequis

Prérequis pour Microsoft Entra ID

Pour l’authentification sans clé recommandée avec l’ID Microsoft Entra, vous devez :

  • Installez Azure CLI.

  • Affectez les rôles Search Service Contributor et Search Index Data Contributor à votre compte d'utilisateur. Vous pouvez attribuer des rôles dans le Portail Azure sous Contrôle d’accès (IAM)>Ajouter une attribution de rôle. Pour plus d’informations, consultez Se connecter à la Recherche Azure AI à l’aide des rôles.

Obtenir des informations sur le service

Vous devez récupérer les informations suivantes pour authentifier votre application auprès de votre ressource Recherche Azure AI :

Nom de la variable Valeur
SEARCH_API_ENDPOINT Cette valeur se trouve dans le portail Azure. Sélectionnez votre service de recherche, puis dans le menu de gauche, sélectionnez Vue d’ensemble. La valeur d’URL sous Essentials est le point de terminaison dont vous avez besoin. Voici un exemple de point de terminaison : https://mydemo.search.windows.net.

En savoir plus sur l’authentification sans clé et la définition de variables d’environnement.

Configurer

  1. Créez un dossier full-text-quickstart pour contenir l’application et ouvrez Visual Studio Code dans ce dossier avec la commande suivante :

    mkdir full-text-quickstart && cd full-text-quickstart
    
  2. Créez une application console avec la commande suivante :

    dotnet new console
    
  3. Installez la bibliothèque de client Recherche Azure AI (Azure.Search.Documents) pour .NET avec :

    dotnet add package Azure.Search.Documents
    
  4. Pour l’authentification sans clé recommandée avec Microsoft Entra ID, installez le package Azure.Identity avec :

    dotnet add package Azure.Identity
    
  5. Pour l’authentification sans clé recommandée avec Microsoft Entra ID, connectez-vous à Azure avec la commande suivante :

    az login
    

Créer, charger et interroger un index de recherche

Dans la section de configuration précédente, vous avez créé une application console et installé la bibliothèque de client Recherche Azure AI.

Dans cette section, vous ajoutez du code pour créer un index de recherche, chargez-le avec des documents et exécutez des requêtes. Vous exécutez le programme pour afficher les résultats dans la console. Pour obtenir une explication détaillée du code, consultez la section Explication du code .

L’exemple de code de ce guide de démarrage rapide utilise Microsoft Entra pour l’authentification sans clé recommandée. Si vous préférez utiliser une clé API, vous pouvez remplacer l’objet DefaultAzureCredential par un objet AzureKeyCredential.

Uri serviceEndpoint = new Uri($"https://<Put your search service NAME here>.search.windows.net/");
DefaultAzureCredential credential = new();
  1. Dans Program.cs, collez le code suivant. Modifiez les variables serviceName et apiKey avec votre nom de votre service de recherche et votre clé API d’administration.

    using System;
    using Azure;
    using Azure.Identity;
    using Azure.Search.Documents;
    using Azure.Search.Documents.Indexes;
    using Azure.Search.Documents.Indexes.Models;
    using Azure.Search.Documents.Models;
    
    namespace AzureSearch.Quickstart
    
    {
        class Program
        {
            static void Main(string[] args)
            {    
                // Your search service endpoint
                Uri serviceEndpoint = new Uri($"https://<Put your search service NAME here>.search.windows.net/");
    
                // Use the recommended keyless credential instead of the AzureKeyCredential credential.
                DefaultAzureCredential credential = new();
                //AzureKeyCredential credential = new AzureKeyCredential("Your search service admin key");
    
                // Create a SearchIndexClient to send create/delete index commands
                SearchIndexClient searchIndexClient = new SearchIndexClient(serviceEndpoint, credential);
    
                // Create a SearchClient to load and query documents
                string indexName = "hotels-quickstart";
                SearchClient searchClient = new SearchClient(serviceEndpoint, indexName, credential);
    
                // Delete index if it exists
                Console.WriteLine("{0}", "Deleting index...\n");
                DeleteIndexIfExists(indexName, searchIndexClient);
    
                // Create index
                Console.WriteLine("{0}", "Creating index...\n");
                CreateIndex(indexName, searchIndexClient);
    
                SearchClient ingesterClient = searchIndexClient.GetSearchClient(indexName);
    
                // Load documents
                Console.WriteLine("{0}", "Uploading documents...\n");
                UploadDocuments(ingesterClient);
    
                // Wait 2 secondsfor indexing to complete before starting queries (for demo and console-app purposes only)
                Console.WriteLine("Waiting for indexing...\n");
                System.Threading.Thread.Sleep(2000);
    
                // Call the RunQueries method to invoke a series of queries
                Console.WriteLine("Starting queries...\n");
                RunQueries(searchClient);
    
                // End the program
                Console.WriteLine("{0}", "Complete. Press any key to end this program...\n");
                Console.ReadKey();
            }
    
            // Delete the hotels-quickstart index to reuse its name
            private static void DeleteIndexIfExists(string indexName, SearchIndexClient searchIndexClient)
            {
                searchIndexClient.GetIndexNames();
                {
                    searchIndexClient.DeleteIndex(indexName);
                }
            }
            // Create hotels-quickstart index
            private static void CreateIndex(string indexName, SearchIndexClient searchIndexClient)
            {
                FieldBuilder fieldBuilder = new FieldBuilder();
                var searchFields = fieldBuilder.Build(typeof(Hotel));
    
                var definition = new SearchIndex(indexName, searchFields);
    
                var suggester = new SearchSuggester("sg", new[] { "HotelName", "Category", "Address/City", "Address/StateProvince" });
                definition.Suggesters.Add(suggester);
    
                searchIndexClient.CreateOrUpdateIndex(definition);
            }
    
            // Upload documents in a single Upload request.
            private static void UploadDocuments(SearchClient searchClient)
            {
                IndexDocumentsBatch<Hotel> batch = IndexDocumentsBatch.Create(
                    IndexDocumentsAction.Upload(
                        new Hotel()
                        {
                            HotelId = "1",
                            HotelName = "Stay-Kay City Hotel",
                            Description = "This classic hotel is fully-refurbished and ideally located on the main commercial artery of the city in the heart of New York. A few minutes away is Times Square and the historic centre of the city, as well as other places of interest that make New York one of America's most attractive and cosmopolitan cities.",
                            Category = "Boutique",
                            Tags = new[] { "view", "air conditioning", "concierge" },
                            ParkingIncluded = false,
                            LastRenovationDate = new DateTimeOffset(2022, 1, 18, 0, 0, 0, TimeSpan.Zero),
                            Rating = 3.6,
                            Address = new Address()
                            {
                                StreetAddress = "677 5th Ave",
                                City = "New York",
                                StateProvince = "NY",
                                PostalCode = "10022",
                                Country = "USA"
                            }
                        }),
                    IndexDocumentsAction.Upload(
                        new Hotel()
                        {
                            HotelId = "2",
                            HotelName = "Old Century Hotel",
                            Description = "The hotel is situated in a nineteenth century plaza, which has been expanded and renovated to the highest architectural standards to create a modern, functional and first-class hotel in which art and unique historical elements coexist with the most modern comforts. The hotel also regularly hosts events like wine tastings, beer dinners, and live music.",
                            Category = "Boutique",
                            Tags = new[] { "pool", "free wifi", "concierge" },
                            ParkingIncluded = false,
                            LastRenovationDate = new DateTimeOffset(2019, 2, 18, 0, 0, 0, TimeSpan.Zero),
                            Rating = 3.60,
                            Address = new Address()
                            {
                                StreetAddress = "140 University Town Center Dr",
                                City = "Sarasota",
                                StateProvince = "FL",
                                PostalCode = "34243",
                                Country = "USA"
                            }
                        }),
                    IndexDocumentsAction.Upload(
                        new Hotel()
                        {
                            HotelId = "3",
                            HotelName = "Gastronomic Landscape Hotel",
                            Description = "The Gastronomic Hotel stands out for its culinary excellence under the management of William Dough, who advises on and oversees all of the Hotel’s restaurant services.",
                            Category = "Suite",
                            Tags = new[] { "restaurant", "bar", "continental breakfast" },
                            ParkingIncluded = true,
                            LastRenovationDate = new DateTimeOffset(2015, 9, 20, 0, 0, 0, TimeSpan.Zero),
                            Rating = 4.80,
                            Address = new Address()
                            {
                                StreetAddress = "3393 Peachtree Rd",
                                City = "Atlanta",
                                StateProvince = "GA",
                                PostalCode = "30326",
                                Country = "USA"
                            }
                        }),
                    IndexDocumentsAction.Upload(
                        new Hotel()
                        {
                            HotelId = "4",
                            HotelName = "Sublime Palace Hotel",
                            Description = "Sublime Palace Hotel is located in the heart of the historic center of Sublime in an extremely vibrant and lively area within short walking distance to the sites and landmarks of the city and is surrounded by the extraordinary beauty of churches, buildings, shops and monuments. Sublime Cliff is part of a lovingly restored 19th century resort, updated for every modern convenience.",
                            Category = "Boutique",
                            Tags = new[] { "concierge", "view", "air conditioning" },
                            ParkingIncluded = true,
                            LastRenovationDate = new DateTimeOffset(2020, 2, 06, 0, 0, 0, TimeSpan.Zero),
                            Rating = 4.60,
                            Address = new Address()
                            {
                                StreetAddress = "7400 San Pedro Ave",
                                City = "San Antonio",
                                StateProvince = "TX",
                                PostalCode = "78216",
                                Country = "USA"
                            }
                        })
                    );
    
                try
                {
                    IndexDocumentsResult result = searchClient.IndexDocuments(batch);
                }
                catch (Exception)
                {
                    // If for some reason any documents are dropped during indexing, you can compensate by delaying and
                    // retrying. This simple demo just logs the failed document keys and continues.
                    Console.WriteLine("Failed to index some of the documents: {0}");
                }
            }
    
            // Run queries, use WriteDocuments to print output
            private static void RunQueries(SearchClient searchClient)
            {
                SearchOptions options;
                SearchResults<Hotel> response;
    
                // Query 1
                Console.WriteLine("Query #1: Search on empty term '*' to return all documents, showing a subset of fields...\n");
    
                options = new SearchOptions()
                {
                    IncludeTotalCount = true,
                    Filter = "",
                    OrderBy = { "" }
                };
    
                options.Select.Add("HotelId");
                options.Select.Add("HotelName");
                options.Select.Add("Rating");
    
                response = searchClient.Search<Hotel>("*", options);
                WriteDocuments(response);
    
                // Query 2
                Console.WriteLine("Query #2: Search on 'hotels', filter on 'Rating gt 4', sort by Rating in descending order...\n");
    
                options = new SearchOptions()
                {
                    Filter = "Rating gt 4",
                    OrderBy = { "Rating desc" }
                };
    
                options.Select.Add("HotelId");
                options.Select.Add("HotelName");
                options.Select.Add("Rating");
    
                response = searchClient.Search<Hotel>("hotels", options);
                WriteDocuments(response);
    
                // Query 3
                Console.WriteLine("Query #3: Limit search to specific fields (pool in Tags field)...\n");
    
                options = new SearchOptions()
                {
                    SearchFields = { "Tags" }
                };
    
                options.Select.Add("HotelId");
                options.Select.Add("HotelName");
                options.Select.Add("Tags");
    
                response = searchClient.Search<Hotel>("pool", options);
                WriteDocuments(response);
    
                // Query 4 - Use Facets to return a faceted navigation structure for a given query
                // Filters are typically used with facets to narrow results on OnClick events
                Console.WriteLine("Query #4: Facet on 'Category'...\n");
    
                options = new SearchOptions()
                {
                    Filter = ""
                };
    
                options.Facets.Add("Category");
    
                options.Select.Add("HotelId");
                options.Select.Add("HotelName");
                options.Select.Add("Category");
    
                response = searchClient.Search<Hotel>("*", options);
                WriteDocuments(response);
    
                // Query 5
                Console.WriteLine("Query #5: Look up a specific document...\n");
    
                Response<Hotel> lookupResponse;
                lookupResponse = searchClient.GetDocument<Hotel>("3");
    
                Console.WriteLine(lookupResponse.Value.HotelId);
    
    
                // Query 6
                Console.WriteLine("Query #6: Call Autocomplete on HotelName...\n");
    
                var autoresponse = searchClient.Autocomplete("sa", "sg");
                WriteDocuments(autoresponse);
    
            }
    
            // Write search results to console
            private static void WriteDocuments(SearchResults<Hotel> searchResults)
            {
                foreach (SearchResult<Hotel> result in searchResults.GetResults())
                {
                    Console.WriteLine(result.Document);
                }
    
                Console.WriteLine();
            }
    
            private static void WriteDocuments(AutocompleteResults autoResults)
            {
                foreach (AutocompleteItem result in autoResults.Results)
                {
                    Console.WriteLine(result.Text);
                }
    
                Console.WriteLine();
            }
        }
    }
    
  2. Dans le même dossier, créez un fichier nommé Hotel.cs et collez le code suivant. Ce code définit la structure d’un document d’hôtel.

    using System;
    using System.Text.Json.Serialization;
    using Azure.Search.Documents.Indexes;
    using Azure.Search.Documents.Indexes.Models;
    
    namespace AzureSearch.Quickstart
    {
        public partial class Hotel
        {
            [SimpleField(IsKey = true, IsFilterable = true)]
            public string HotelId { get; set; }
    
            [SearchableField(IsSortable = true)]
            public string HotelName { get; set; }
    
            [SearchableField(AnalyzerName = LexicalAnalyzerName.Values.EnLucene)]
            public string Description { get; set; }
    
            [SearchableField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
            public string Category { get; set; }
    
            [SearchableField(IsFilterable = true, IsFacetable = true)]
            public string[] Tags { get; set; }
    
            [SimpleField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
            public bool? ParkingIncluded { get; set; }
    
            [SimpleField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
            public DateTimeOffset? LastRenovationDate { get; set; }
    
            [SimpleField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
            public double? Rating { get; set; }
    
            [SearchableField]
            public Address Address { get; set; }
        }
    }
    
  3. Créez un fichier nommé Hotel.cs et collez le code suivant pour définir la structure d’un document hôtel. Les attributs du champ déterminent la façon dont il est utilisé dans une application. Par exemple, l’attribut IsFilterable doit être assigné à chaque champ qui prend en charge une expression de filtre.

    using System;
    using System.Text.Json.Serialization;
    using Azure.Search.Documents.Indexes;
    using Azure.Search.Documents.Indexes.Models;
    
    namespace AzureSearch.Quickstart
    {
        public partial class Hotel
        {
            [SimpleField(IsKey = true, IsFilterable = true)]
            public string HotelId { get; set; }
    
            [SearchableField(IsSortable = true)]
            public string HotelName { get; set; }
    
            [SearchableField(AnalyzerName = LexicalAnalyzerName.Values.EnLucene)]
            public string Description { get; set; }
    
            [SearchableField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
            public string Category { get; set; }
    
            [SearchableField(IsFilterable = true, IsFacetable = true)]
            public string[] Tags { get; set; }
    
            [SimpleField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
            public bool? ParkingIncluded { get; set; }
    
            [SimpleField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
            public DateTimeOffset? LastRenovationDate { get; set; }
    
            [SimpleField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
            public double? Rating { get; set; }
    
            [SearchableField]
            public Address Address { get; set; }
        }
    }
    
  4. Créez un fichier nommé Address.cs et collez le code suivant pour définir la structure d’un document d’adresse.

    using Azure.Search.Documents.Indexes;
    
    namespace AzureSearch.Quickstart
    {
        public partial class Address
        {
            [SearchableField(IsFilterable = true)]
            public string StreetAddress { get; set; }
    
            [SearchableField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
            public string City { get; set; }
    
            [SearchableField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
            public string StateProvince { get; set; }
    
            [SearchableField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
            public string PostalCode { get; set; }
    
            [SearchableField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
            public string Country { get; set; }
        }
    }
    
  5. Créez un fichier nommé Hotel.Methods.cs et collez le code suivant pour définir un remplacement ToString() pour la classe Hotel.

    using System;
    using System.Text;
    
    namespace AzureSearch.Quickstart
    {
        public partial class Hotel
        {
            public override string ToString()
            {
                var builder = new StringBuilder();
    
                if (!String.IsNullOrEmpty(HotelId))
                {
                    builder.AppendFormat("HotelId: {0}\n", HotelId);
                }
    
                if (!String.IsNullOrEmpty(HotelName))
                {
                    builder.AppendFormat("Name: {0}\n", HotelName);
                }
    
                if (!String.IsNullOrEmpty(Description))
                {
                    builder.AppendFormat("Description: {0}\n", Description);
                }
    
                if (!String.IsNullOrEmpty(Category))
                {
                    builder.AppendFormat("Category: {0}\n", Category);
                }
    
                if (Tags != null && Tags.Length > 0)
                {
                    builder.AppendFormat("Tags: [ {0} ]\n", String.Join(", ", Tags));
                }
    
                if (ParkingIncluded.HasValue)
                {
                    builder.AppendFormat("Parking included: {0}\n", ParkingIncluded.Value ? "yes" : "no");
                }
    
                if (LastRenovationDate.HasValue)
                {
                    builder.AppendFormat("Last renovated on: {0}\n", LastRenovationDate);
                }
    
                if (Rating.HasValue)
                {
                    builder.AppendFormat("Rating: {0}\n", Rating);
                }
    
                if (Address != null && !Address.IsEmpty)
                {
                    builder.AppendFormat("Address: \n{0}\n", Address.ToString());
                }
    
                return builder.ToString();
            }
        }
    }
    
  6. Créez un fichier nommé Address.Methods.cs et collez le code suivant pour définir un remplacement ToString() pour la classe Address.

    using System;
    using System.Text;
    using System.Text.Json.Serialization;
    
    namespace AzureSearch.Quickstart
    {
        public partial class Address
        {
            public override string ToString()
            {
                var builder = new StringBuilder();
    
                if (!IsEmpty)
                {
                    builder.AppendFormat("{0}\n{1}, {2} {3}\n{4}", StreetAddress, City, StateProvince, PostalCode, Country);
                }
    
                return builder.ToString();
            }
    
            [JsonIgnore]
            public bool IsEmpty => String.IsNullOrEmpty(StreetAddress) &&
                                   String.IsNullOrEmpty(City) &&
                                   String.IsNullOrEmpty(StateProvince) &&
                                   String.IsNullOrEmpty(PostalCode) &&
                                   String.IsNullOrEmpty(Country);
        }
    }
    
  7. Compilez et exécutez l’application avec la commande suivante :

    dotnet run
    

La sortie comprend des messages de la méthode Console.WriteLine, avec en plus des informations et des résultats de requête.

Explication du code

Dans les sections précédentes, vous avez créé une nouvelle application console et installé la bibliothèque de client Recherche Azure AI. Vous avez ajouté du code pour créer un index de recherche, le charger avec des documents et exécuter des requêtes. Vous avez exécuté le programme pour afficher les résultats dans la console.

Dans cette section, nous expliquons le code que vous avez ajouté à l’application console.

Créer un client de recherche

Dans Program.cs, vous avez créé deux clients :

Les deux clients ont besoin du point de terminaison de service de recherche et des informations d’identification décrits précédemment dans la section Obtenir des informations de service .

L’exemple de code de ce guide de démarrage rapide utilise Microsoft Entra pour l’authentification sans clé recommandée. Si vous préférez utiliser une clé API, vous pouvez remplacer l’objet DefaultAzureCredential par un objet AzureKeyCredential.

Uri serviceEndpoint = new Uri($"https://<Put your search service NAME here>.search.windows.net/");
DefaultAzureCredential credential = new();
static void Main(string[] args)
{
    // Your search service endpoint
    Uri serviceEndpoint = new Uri($"https://<Put your search service NAME here>.search.windows.net/");

    // Use the recommended keyless credential instead of the AzureKeyCredential credential.
    DefaultAzureCredential credential = new();
    //AzureKeyCredential credential = new AzureKeyCredential("Your search service admin key");

    // Create a SearchIndexClient to send create/delete index commands
    SearchIndexClient searchIndexClient = new SearchIndexClient(serviceEndpoint, credential);

    // Create a SearchClient to load and query documents
    string indexName = "hotels-quickstart";
    SearchClient searchClient = new SearchClient(serviceEndpoint, indexName, credential);
    
    // REDACTED FOR BREVITY . . . 
}

Création d'un index

Ce guide de démarrage rapide crée un index Hotels que vous allez charger avec des données sur des hôtels et sur lequel vous allez effectuer des requêtes. Dans cette étape, définissez les champs de l’index. Chaque définition de champ comprend un nom, un type de données et des attributs qui déterminent la façon dont le champ est utilisé.

Dans cet exemple, des méthodes synchrones de la bibliothèque Azure.Search.Documents sont utilisées par souci de simplicité et de lisibilité. En revanche, dans des scénarios de production, vous devez utiliser des méthodes asynchrones pour maintenir la scalabilité et la réactivité de votre application. Par exemple, vous pouvez utiliser CreateIndexAsync au lieu de CreateIndex.

Définir les structures

Vous avez créé deux classes d’assistance, Hotel.cs et Address.cs, pour définir la structure d’un document d’hôtel et son adresse. La classe Hotel comprend des champs pour un ID d’hôtel, nom, description, catégorie, étiquettes, parking, date de rénovation, évaluation et adresse. La classe Address inclut des champs pour l’adresse postale, la ville, l’état/la province, le code postal et le pays/région.

Dans la bibliothèque de client Azure.Search.Documents, vous pouvez utiliser SearchableField et SimpleField pour simplifier les définitions des champs. Les deux sont des dérivés d’un SearchField et peuvent potentiellement simplifier votre code :

  • SimpleField peut être n’importe quel type de données, ne peut jamais faire l’objet d’une recherche (il est ignoré pour les requêtes de recherche de texte intégral) et peut être récupéré (il n’est pas masqué). Les autres attributs sont désactivés par défaut, mais peuvent être activés. Vous pouvez utiliser un SimpleField pour les ID de document ou les champs utilisés seulement dans des filtres, des facettes ou des profils de scoring. Dans ce cas, veillez à appliquer tous les attributs nécessaires pour le scénario, comme IsKey = true pour un ID de document. Pour plus d’informations, consultez SimpleFieldAttribute.cs dans le code source.

  • SearchableField doit être une chaîne, et peut toujours faire l’objet d’une recherche et d’une récupération. Les autres attributs sont désactivés par défaut, mais peuvent être activés. Comme ce type de champ peut faire l’objet d’une recherche, il prend en charge les synonymes et l’ensemble complet des propriétés de l’analyseur. Pour plus d’informations, consultez SearchableFieldAttribute.cs dans le code source.

Que vous utilisiez l’API SearchField de base ou un des modèles d’assistance, vous devez activer explicitement les attributs de filtre, de facette et de tri. Par exemple, IsFilterable, IsSortable et IsFacetable doivent être explicitement attribués, comme illustré dans l’exemple précédent.

Créer l’index de recherche

Dans Program.cs, créez un objet SearchIndex, puis appelez la méthode CreateIndex pour exprimer l’index dans votre service de recherche. L’index comprend également un SearchSuggester pour activer l’autocomplétion sur les champs spécifiés.

// Create hotels-quickstart index
private static void CreateIndex(string indexName, SearchIndexClient searchIndexClient)
{
    FieldBuilder fieldBuilder = new FieldBuilder();
    var searchFields = fieldBuilder.Build(typeof(Hotel));

    var definition = new SearchIndex(indexName, searchFields);

    var suggester = new SearchSuggester("sg", new[] { "HotelName", "Category", "Address/City", "Address/StateProvince" });
    definition.Suggesters.Add(suggester);

    searchIndexClient.CreateOrUpdateIndex(definition);
}

Chargement de documents

Recherche Azure AI effectue des recherches parmi les contenus stockés dans le service. Au cours de cette étape, vous allez charger des documents JSON conformes à l’index de l’hôtel que vous avez créé.

Dans la recherche Azure AI, les documents de recherche sont des structures de données qui sont à la fois des entrées pour l’indexation et des sorties de requêtes. Selon une source de données externe, les entrées de documents peuvent être des lignes dans une base de données, des objets blob dans le Stockage Blob ou des documents JSON sur le disque. Dans cet exemple, nous prenons un raccourci et incorporons des documents JSON pour quatre hôtels dans le code lui-même.

Lors du chargement de documents, vous devez utiliser un objet IndexDocumentsBatch. Un objet IndexDocumentsBatch contient une collection d’Actions, chacune contenant un document et une propriété qui indiquent à la recherche Azure AI l’action à effectuer (upload, merge, delete et mergeOrUpload).

Dans Program.cs, créez un tableau des documents et des actions d’index, puis passez le tableau à IndexDocumentsBatch. Les documents suivants sont conformes à l’index hotels-quickstart, tel que défini par la classe hotel.

// Upload documents in a single Upload request.
private static void UploadDocuments(SearchClient searchClient)
{
    IndexDocumentsBatch<Hotel> batch = IndexDocumentsBatch.Create(
        IndexDocumentsAction.Upload(
            new Hotel()
            {
                HotelId = "1",
                HotelName = "Stay-Kay City Hotel",
                Description = "This classic hotel is fully-refurbished and ideally located on the main commercial artery of the city in the heart of New York. A few minutes away is Times Square and the historic centre of the city, as well as other places of interest that make New York one of America's most attractive and cosmopolitan cities.",
                Category = "Boutique",
                Tags = new[] { "view", "air conditioning", "concierge" },
                ParkingIncluded = false,
                LastRenovationDate = new DateTimeOffset(2022, 1, 18, 0, 0, 0, TimeSpan.Zero),
                Rating = 3.6,
                Address = new Address()
                {
                    StreetAddress = "677 5th Ave",
                    City = "New York",
                    StateProvince = "NY",
                    PostalCode = "10022",
                    Country = "USA"
                }
            }),
        // REDACTED FOR BREVITY
}

Une fois que vous avez initialisé l’objet IndexDocumentsBatch, vous pouvez l’envoyer à l’index en appelant IndexDocuments sur votre objet SearchClient.

Vous allez charger des documents en utilisant SearchClient dans Main(), mais l’opération nécessite également des droits d’administrateur sur le service, généralement associé à SearchIndexClient. Une façon de configurer cette opération consiste à obtenir SearchClient via SearchIndexClient (searchIndexClient dans cet exemple).

SearchClient ingesterClient = searchIndexClient.GetSearchClient(indexName);

// Load documents
Console.WriteLine("{0}", "Uploading documents...\n");
UploadDocuments(ingesterClient);

Étant donné qu’il s’agit d’une application console qui exécute toutes les commandes de manière séquentielle, nous allons ajouter un délai d’attente de 2 secondes entre l’indexation et les requêtes.

// Wait 2 seconds for indexing to complete before starting queries (for demo and console-app purposes only)
Console.WriteLine("Waiting for indexing...\n");
System.Threading.Thread.Sleep(2000);

Le retard de 2 secondes compense l’indexation, qui est asynchrone, afin que tous les documents puissent être indexés avant l’exécution des requêtes. Le codage dans un retard n’est nécessaire que dans les démonstrations, les tests et les exemples d’applications.

Rechercher dans un index

Vous pouvez obtenir les résultats de la requête dès que le premier document est indexé, mais les tests réels de votre index doivent attendre que tous les documents soient indexés.

Cette section ajoute deux éléments de fonctionnalité : logique de requête et résultats. Pour les requêtes, utilisez la méthode Search. Cette méthode prend le texte de recherche (la chaîne de requête) ainsi que d’autres options.

La classe SearchResults représente les résultats.

Dans Program.cs, la méthode WriteDocuments imprime les résultats de recherche dans la console.

// Write search results to console
private static void WriteDocuments(SearchResults<Hotel> searchResults)
{
    foreach (SearchResult<Hotel> result in searchResults.GetResults())
    {
        Console.WriteLine(result.Document);
    }

    Console.WriteLine();
}

private static void WriteDocuments(AutocompleteResults autoResults)
{
    foreach (AutocompleteItem result in autoResults.Results)
    {
        Console.WriteLine(result.Text);
    }

    Console.WriteLine();
}

Exemple de requête 1

La méthode RunQueries exécute des requêtes et retourne des résultats. Les résultats sont des objets Hotel. Cet exemple montre la signature de la méthode et la première requête. Cette requête montre le paramètre Select qui vous permet de composer le résultat à l’aide de champs sélectionnés dans le document.

// Run queries, use WriteDocuments to print output
private static void RunQueries(SearchClient searchClient)
{
    SearchOptions options;
    SearchResults<Hotel> response;
    
    // Query 1
    Console.WriteLine("Query #1: Search on empty term '*' to return all documents, showing a subset of fields...\n");

    options = new SearchOptions()
    {
        IncludeTotalCount = true,
        Filter = "",
        OrderBy = { "" }
    };

    options.Select.Add("HotelId");
    options.Select.Add("HotelName");
    options.Select.Add("Address/City");

    response = searchClient.Search<Hotel>("*", options);
    WriteDocuments(response);
    // REDACTED FOR BREVITY
}

Exemple de requête 2

Dans la deuxième requête, recherchez un terme, ajoutez un filtre qui sélectionne les documents dont l’évaluation (Rating) est supérieure à 4, puis triez par Rating dans l’ordre décroissant. Un filtre est une expression booléenne évaluée sur des champs IsFilterable dans un index. Les requêtes de filtre incluent ou excluent des valeurs. Par conséquent, aucun score de pertinence n’est associé à une requête de filtre.

// Query 2
Console.WriteLine("Query #2: Search on 'hotels', filter on 'Rating gt 4', sort by Rating in descending order...\n");

options = new SearchOptions()
{
    Filter = "Rating gt 4",
    OrderBy = { "Rating desc" }
};

options.Select.Add("HotelId");
options.Select.Add("HotelName");
options.Select.Add("Rating");

response = searchClient.Search<Hotel>("hotels", options);
WriteDocuments(response);

Exemple de requête 3

La troisième requête illustre l’utilisation de searchFields, qui sert à limiter l’étendue d’une opération de recherche en texte intégral à des champs spécifiques.

// Query 3
Console.WriteLine("Query #3: Limit search to specific fields (pool in Tags field)...\n");

options = new SearchOptions()
{
    SearchFields = { "Tags" }
};

options.Select.Add("HotelId");
options.Select.Add("HotelName");
options.Select.Add("Tags");

response = searchClient.Search<Hotel>("pool", options);
WriteDocuments(response);

Exemple de requête 4

La quatrième requête illustre les facets, que vous pouvez utiliser pour créer une structure de navigation par facettes.

// Query 4
Console.WriteLine("Query #4: Facet on 'Category'...\n");

options = new SearchOptions()
{
    Filter = ""
};

options.Facets.Add("Category");

options.Select.Add("HotelId");
options.Select.Add("HotelName");
options.Select.Add("Category");

response = searchClient.Search<Hotel>("*", options);
WriteDocuments(response);

Exemple de requête 5

La cinquième requête retourne un document spécifique. Une recherche de document est une réponse classique à l’événement OnClick dans un jeu de résultats.

// Query 5
Console.WriteLine("Query #5: Look up a specific document...\n");

Response<Hotel> lookupResponse;
lookupResponse = searchClient.GetDocument<Hotel>("3");

Console.WriteLine(lookupResponse.Value.HotelId);

Exemple de requête 6

La dernière requête affiche la syntaxe pour l’autocomplétion ; elle simule une entrée utilisateur partielle, sa, qui est résolue en deux correspondances possibles dans les sourceFields associés au suggesteur que vous avez défini dans l’index.

// Query 6
Console.WriteLine("Query #6: Call Autocomplete on HotelName that starts with 'sa'...\n");

var autoresponse = searchClient.Autocomplete("sa", "sg");
WriteDocuments(autoresponse);

Résumé des requêtes

Les requêtes précédentes illustrent plusieurs manières d’établir des correspondances entre des termes dans une requête : recherche en texte intégral, filtres et autocomplétion.

La recherche en texte intégral et les filtres sont exécutés à l’aide de la méthode SearchClient.Search. Une requête de recherche peut être transmise dans la chaîne searchText, tandis qu’une expression de filtre peut être transmise dans la propriété Filter de la classe SearchOptions. Pour filtrer sans effectuer de recherche, transmettez simplement "*" pour le paramètre searchText de la méthode Search. Pour effectuer une recherche sans filtrage, ne définissez pas la propriété Filter et ne transmettez aucune instance SearchOptions.

Dans ce guide de démarrage rapide, vous utilisez la bibliothèque cliente Azure.Search.Documents pour créer, charger et interroger un index de recherche avec des exemples de données pour la recherche en texte intégral. La recherche en texte intégral utilise Apache Lucene pour l’indexation et les requêtes et l’algorithme de classement BM25 pour les résultats de scoring.

Ce guide de démarrage rapide utilise les données d’hôtel fictives du référentiel azure-search-sample-data pour remplir l’index.

Conseil

Vous pouvez télécharger le code source pour commencer par un projet terminé ou suivre ces étapes pour créer votre propre code.

Prérequis

Prérequis pour Microsoft Entra ID

Pour l’authentification sans clé recommandée avec l’ID Microsoft Entra, vous devez :

  • Installez Azure CLI.

  • Affectez les rôles Search Service Contributor et Search Index Data Contributor à votre compte d'utilisateur. Vous pouvez attribuer des rôles dans le Portail Azure sous Contrôle d’accès (IAM)>Ajouter une attribution de rôle. Pour plus d’informations, consultez Se connecter à la Recherche Azure AI à l’aide des rôles.

Obtenir des informations sur le service

Vous devez récupérer les informations suivantes pour authentifier votre application auprès de votre ressource Recherche Azure AI :

Nom de la variable Valeur
SEARCH_API_ENDPOINT Cette valeur se trouve dans le portail Azure. Sélectionnez votre service de recherche, puis dans le menu de gauche, sélectionnez Vue d’ensemble. La valeur d’URL sous Essentials est le point de terminaison dont vous avez besoin. Voici un exemple de point de terminaison : https://mydemo.search.windows.net.

En savoir plus sur l’authentification sans clé et la définition de variables d’environnement.

Configurer

L’échantillon de ce guide de démarrage rapide fonctionne avec le runtime Java. Installez un kit de développement Java tel que Azul Zulu OpenJDK. La build Microsoft d’OpenJDK ou le JDK de votre choix doivent également fonctionner.

  1. Installez Apache Maven. Exécutez ensuite mvn -v pour confirmer la réussite de l’installation.

  2. Créez un fichier pom.xml à la racine de votre projet, puis copiez-y le code suivant :

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>azure.search.sample</groupId>
        <artifactId>azuresearchquickstart</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <build>
            <sourceDirectory>src</sourceDirectory>
            <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.7.0</version>
                <configuration>
                <source>1.8</source>
                <target>1.8</target>
                </configuration>
            </plugin>
            </plugins>
        </build>
        <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.11</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>com.azure</groupId>
                <artifactId>azure-search-documents</artifactId>
                <version>11.7.3</version>
            </dependency>
            <dependency>
                <groupId>com.azure</groupId>
                <artifactId>azure-core</artifactId>
                <version>1.53.0</version>
            </dependency>
            <dependency>
                <groupId>com.azure</groupId>
                <artifactId>azure-identity</artifactId>
                <version>1.15.1</version>
            </dependency>
        </dependencies>
    </project>
    
  3. Installez les dépendances, notamment la bibliothèque de client Recherche Azure AI (Azure.Search.Documents) pour Java et la bibliothèque de client Azure Identity pour Java avec :

    mvn clean dependency:copy-dependencies
    
  4. Pour l’authentification sans clé recommandée avec Microsoft Entra ID, connectez-vous à Azure avec la commande suivante :

    az login
    

Créer, charger et interroger un index de recherche

Dans la section de configuration précédente, vous avez installé la bibliothèque de client Recherche Azure AI et d’autres dépendances.

Dans cette section, vous ajoutez du code pour créer un index de recherche, chargez-le avec des documents et exécutez des requêtes. Vous exécutez le programme pour afficher les résultats dans la console. Pour obtenir une explication détaillée du code, consultez la section Explication du code .

L’exemple de code de ce guide de démarrage rapide utilise Microsoft Entra pour l’authentification sans clé recommandée. Si vous préférez utiliser une clé API, vous pouvez remplacer l’objet DefaultAzureCredential par un objet AzureKeyCredential.

String searchServiceEndpoint = "https://<Put your search service NAME here>.search.windows.net/";
DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();
  1. Créez un fichier nommé App.java et collez le code suivant dans App.java :

    import java.util.Arrays;
    import java.util.ArrayList;
    import java.time.OffsetDateTime;
    import java.time.ZoneOffset;
    import java.time.LocalDateTime;
    import java.time.LocalDate;
    import java.time.LocalTime;
    import com.azure.core.util.Configuration;
    import com.azure.core.util.Context;
    import com.azure.identity.DefaultAzureCredential;
    import com.azure.identity.DefaultAzureCredentialBuilder;
    import com.azure.search.documents.SearchClient;
    import com.azure.search.documents.SearchClientBuilder;
    import com.azure.search.documents.indexes.SearchIndexClient;
    import com.azure.search.documents.indexes.SearchIndexClientBuilder;
    import com.azure.search.documents.indexes.models.IndexDocumentsBatch;
    import com.azure.search.documents.models.SearchOptions;
    import com.azure.search.documents.indexes.models.SearchIndex;
    import com.azure.search.documents.indexes.models.SearchSuggester;
    import com.azure.search.documents.util.AutocompletePagedIterable;
    import com.azure.search.documents.util.SearchPagedIterable;
    
    public class App {
    
        public static void main(String[] args) {
            // Your search service endpoint
            "https://<Put your search service NAME here>.search.windows.net/";
    
            // Use the recommended keyless credential instead of the AzureKeyCredential credential.
            DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();
            //AzureKeyCredential credential = new AzureKeyCredential("<Your search service admin key>");
    
            // Create a SearchIndexClient to send create/delete index commands
            SearchIndexClient searchIndexClient = new SearchIndexClientBuilder()
                .endpoint(searchServiceEndpoint)
                .credential(credential)
                .buildClient();
    
            // Create a SearchClient to load and query documents
            String indexName = "hotels-quickstart-java";
            SearchClient searchClient = new SearchClientBuilder()
                .endpoint(searchServiceEndpoint)
                .credential(credential)
                .indexName(indexName)
                .buildClient();
    
            // Create Search Index for Hotel model
            searchIndexClient.createOrUpdateIndex(
                new SearchIndex(indexName, SearchIndexClient.buildSearchFields(Hotel.class, null))
                .setSuggesters(new SearchSuggester("sg", Arrays.asList("HotelName"))));
    
            // Upload sample hotel documents to the Search Index
            uploadDocuments(searchClient);
    
            // Wait 2 seconds for indexing to complete before starting queries (for demo and console-app purposes only)
            System.out.println("Waiting for indexing...\n");
            try
            {
                Thread.sleep(2000);
            }
            catch (InterruptedException e)
            {
            }
    
            // Call the RunQueries method to invoke a series of queries
            System.out.println("Starting queries...\n");
            RunQueries(searchClient);
    
            // End the program
            System.out.println("Complete.\n");
        }
    
        // Upload documents in a single Upload request.
        private static void uploadDocuments(SearchClient searchClient)
        {
            var hotelList = new ArrayList<Hotel>();
    
            var hotel = new Hotel();
            hotel.hotelId = "1";
            hotel.hotelName = "Stay-Kay City Hotel";
            hotel.description = "This classic hotel is fully-refurbished and ideally located on the main commercial artery of the city in the heart of New York. A few minutes away is Times Square and the historic centre of the city, as well as other places of interest that make New York one of America's most attractive and cosmopolitan cities.";
            hotel.category = "Boutique";
            hotel.tags = new String[] { "view", "air conditioning", "concierge" };
            hotel.parkingIncluded = false;
            hotel.lastRenovationDate = OffsetDateTime.of(LocalDateTime.of(LocalDate.of(2022, 1, 18), LocalTime.of(0, 0)), ZoneOffset.UTC);
            hotel.rating = 3.6;
            hotel.address = new Address();
            hotel.address.streetAddress = "677 5th Ave";
            hotel.address.city = "New York";
            hotel.address.stateProvince = "NY";
            hotel.address.postalCode = "10022";
            hotel.address.country = "USA";
            hotelList.add(hotel);
    
            hotel = new Hotel();
            hotel.hotelId = "2";
            hotel.hotelName = "Old Century Hotel";
            hotel.description = "The hotel is situated in a nineteenth century plaza, which has been expanded and renovated to the highest architectural standards to create a modern, functional and first-class hotel in which art and unique historical elements coexist with the most modern comforts. The hotel also regularly hosts events like wine tastings, beer dinners, and live music.",
            hotel.category = "Boutique";
            hotel.tags = new String[] { "pool", "free wifi", "concierge" };
            hotel.parkingIncluded = false;
            hotel.lastRenovationDate = OffsetDateTime.of(LocalDateTime.of(LocalDate.of(2019, 2, 18), LocalTime.of(0, 0)), ZoneOffset.UTC);
            hotel.rating = 3.60;
            hotel.address = new Address();
            hotel.address.streetAddress = "140 University Town Center Dr";
            hotel.address.city = "Sarasota";
            hotel.address.stateProvince = "FL";
            hotel.address.postalCode = "34243";
            hotel.address.country = "USA";
            hotelList.add(hotel);
    
            hotel = new Hotel();
            hotel.hotelId = "3";
            hotel.hotelName = "Gastronomic Landscape Hotel";
            hotel.description = "The Gastronomic Hotel stands out for its culinary excellence under the management of William Dough, who advises on and oversees all of the Hotel’s restaurant services.";
            hotel.category = "Suite";
            hotel.tags = new String[] { "restaurant", "bar", "continental breakfast" };
            hotel.parkingIncluded = true;
            hotel.lastRenovationDate = OffsetDateTime.of(LocalDateTime.of(LocalDate.of(2015, 9, 20), LocalTime.of(0, 0)), ZoneOffset.UTC);
            hotel.rating = 4.80;
            hotel.address = new Address();
            hotel.address.streetAddress = "3393 Peachtree Rd";
            hotel.address.city = "Atlanta";
            hotel.address.stateProvince = "GA";
            hotel.address.postalCode = "30326";
            hotel.address.country = "USA";
            hotelList.add(hotel);
    
            hotel = new Hotel();
            hotel.hotelId = "4";
            hotel.hotelName = "Sublime Palace Hotel";
            hotel.description = "Sublime Palace Hotel is located in the heart of the historic center of Sublime in an extremely vibrant and lively area within short walking distance to the sites and landmarks of the city and is surrounded by the extraordinary beauty of churches, buildings, shops and monuments. Sublime Cliff is part of a lovingly restored 19th century resort, updated for every modern convenience.";
            hotel.category = "Boutique";
            hotel.tags = new String[] { "concierge", "view", "air conditioning" };
            hotel.parkingIncluded = true;
            hotel.lastRenovationDate = OffsetDateTime.of(LocalDateTime.of(LocalDate.of(2020, 2, 06), LocalTime.of(0, 0)), ZoneOffset.UTC);
            hotel.rating = 4.60;
            hotel.address = new Address();
            hotel.address.streetAddress = "7400 San Pedro Ave";
            hotel.address.city = "San Antonio";
            hotel.address.stateProvince = "TX";
            hotel.address.postalCode = "78216";
            hotel.address.country = "USA";
            hotelList.add(hotel);
    
            var batch = new IndexDocumentsBatch<Hotel>();
            batch.addMergeOrUploadActions(hotelList);
            try
            {
                searchClient.indexDocuments(batch);
            }
            catch (Exception e)
            {
                e.printStackTrace();
                // If for some reason any documents are dropped during indexing, you can compensate by delaying and
                // retrying. This simple demo just logs failure and continues
                System.err.println("Failed to index some of the documents");
            }
        }
    
        // Write search results to console
        private static void WriteSearchResults(SearchPagedIterable searchResults)
        {
            searchResults.iterator().forEachRemaining(result ->
            {
                Hotel hotel = result.getDocument(Hotel.class);
                System.out.println(hotel);
            });
    
            System.out.println();
        }
    
        // Write autocomplete results to console
        private static void WriteAutocompleteResults(AutocompletePagedIterable autocompleteResults)
        {
            autocompleteResults.iterator().forEachRemaining(result ->
            {
                String text = result.getText();
                System.out.println(text);
            });
    
            System.out.println();
        }
    
        // Run queries, use WriteDocuments to print output
        private static void RunQueries(SearchClient searchClient)
        {
            // Query 1
            System.out.println("Query #1: Search on empty term '*' to return all documents, showing a subset of fields...\n");
    
            SearchOptions options = new SearchOptions();
            options.setIncludeTotalCount(true);
            options.setFilter("");
            options.setOrderBy("");
            options.setSelect("HotelId", "HotelName", "Address/City");
    
            WriteSearchResults(searchClient.search("*", options, Context.NONE));
    
            // Query 2
            System.out.println("Query #2: Search on 'hotels', filter on 'Rating gt 4', sort by Rating in descending order...\n");
    
            options = new SearchOptions();
            options.setFilter("Rating gt 4");
            options.setOrderBy("Rating desc");
            options.setSelect("HotelId", "HotelName", "Rating");
    
            WriteSearchResults(searchClient.search("hotels", options, Context.NONE));
    
            // Query 3
            System.out.println("Query #3: Limit search to specific fields (pool in Tags field)...\n");
    
            options = new SearchOptions();
            options.setSearchFields("Tags");
    
            options.setSelect("HotelId", "HotelName", "Tags");
    
            WriteSearchResults(searchClient.search("pool", options, Context.NONE));
    
            // Query 4
            System.out.println("Query #4: Facet on 'Category'...\n");
    
            options = new SearchOptions();
            options.setFilter("");
            options.setFacets("Category");
            options.setSelect("HotelId", "HotelName", "Category");
    
            WriteSearchResults(searchClient.search("*", options, Context.NONE));
    
            // Query 5
            System.out.println("Query #5: Look up a specific document...\n");
    
            Hotel lookupResponse = searchClient.getDocument("3", Hotel.class);
            System.out.println(lookupResponse.hotelId);
            System.out.println();
    
             // Query 6
            System.out.println("Query #6: Call Autocomplete on HotelName that starts with 's'...\n");
    
            WriteAutocompleteResults(searchClient.autocomplete("s", "sg"));
        }
    }
    
  2. Créez un fichier nommé Hotel.java et collez le code suivant dans Hotel.java :

    import com.azure.search.documents.indexes.SearchableField;
    import com.azure.search.documents.indexes.SimpleField;
    import com.fasterxml.jackson.annotation.JsonInclude;
    import com.fasterxml.jackson.annotation.JsonProperty;
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.annotation.JsonInclude.Include;
    
    import java.time.OffsetDateTime;
    
    /**
     * Model class representing a hotel.
     */
    @JsonInclude(Include.NON_NULL)
    public class Hotel {
        /**
         * Hotel ID
         */
        @JsonProperty("HotelId")
        @SimpleField(isKey = true)
        public String hotelId;
    
        /**
         * Hotel name
         */
        @JsonProperty("HotelName")
        @SearchableField(isSortable = true)
        public String hotelName;
    
        /**
         * Description
         */
        @JsonProperty("Description")
        @SearchableField(analyzerName = "en.microsoft")
        public String description;
    
        /**
         * Category
         */
        @JsonProperty("Category")
        @SearchableField(isFilterable = true, isSortable = true, isFacetable = true)
        public String category;
    
        /**
         * Tags
         */
        @JsonProperty("Tags")
        @SearchableField(isFilterable = true, isFacetable = true)
        public String[] tags;
    
        /**
         * Whether parking is included
         */
        @JsonProperty("ParkingIncluded")
        @SimpleField(isFilterable = true, isSortable = true, isFacetable = true)
        public Boolean parkingIncluded;
    
        /**
         * Last renovation time
         */
        @JsonProperty("LastRenovationDate")
        @SimpleField(isFilterable = true, isSortable = true, isFacetable = true)
        public OffsetDateTime lastRenovationDate;
    
        /**
         * Rating
         */
        @JsonProperty("Rating")
        @SimpleField(isFilterable = true, isSortable = true, isFacetable = true)
        public Double rating;
    
        /**
         * Address
         */
        @JsonProperty("Address")
        public Address address;
    
        @Override
        public String toString()
        {
            try
            {
                return new ObjectMapper().writeValueAsString(this);
            }
            catch (JsonProcessingException e)
            {
                e.printStackTrace();
                return "";
            }
        }
    }
    
  3. Créez un fichier nommé Address.java et collez le code suivant dans Address.java :

    import com.azure.search.documents.indexes.SearchableField;
    import com.fasterxml.jackson.annotation.JsonInclude;
    import com.fasterxml.jackson.annotation.JsonProperty;
    import com.fasterxml.jackson.annotation.JsonInclude.Include;
    
    /**
     * Model class representing an address.
     */
    @JsonInclude(Include.NON_NULL)
    public class Address {
        /**
         * Street address
         */
        @JsonProperty("StreetAddress")
        @SearchableField
        public String streetAddress;
    
        /**
         * City
         */
        @JsonProperty("City")
        @SearchableField(isFilterable = true, isSortable = true, isFacetable = true)
        public String city;
    
        /**
         * State or province
         */
        @JsonProperty("StateProvince")
        @SearchableField(isFilterable = true, isSortable = true, isFacetable = true)
        public String stateProvince;
    
        /**
         * Postal code
         */
        @JsonProperty("PostalCode")
        @SearchableField(isFilterable = true, isSortable = true, isFacetable = true)
        public String postalCode;
    
        /**
         * Country
         */
        @JsonProperty("Country")
        @SearchableField(isFilterable = true, isSortable = true, isFacetable = true)
        public String country;
    }
    
  4. Exécutez votre nouvelle application console :

    javac Address.java App.java Hotel.java -cp ".;target\dependency\*"
    java -cp ".;target\dependency\*" App
    

Explication du code

Dans les sections précédentes, vous avez créé une nouvelle application console et installé la bibliothèque de client Recherche Azure AI. Vous avez ajouté du code pour créer un index de recherche, le charger avec des documents et exécuter des requêtes. Vous avez exécuté le programme pour afficher les résultats dans la console.

Dans cette section, nous expliquons le code que vous avez ajouté à l’application console.

Créer un client de recherche

Dans App.java vous avez créé deux clients :

  • SearchIndexClient crée l’index.
  • SearchClient charge et interroge un index existant.

Les deux clients ont besoin du point de terminaison de service de recherche et des informations d’identification décrits précédemment dans la section informations sur la ressource.

L’exemple de code de ce guide de démarrage rapide utilise Microsoft Entra pour l’authentification sans clé recommandée. Si vous préférez utiliser une clé API, vous pouvez remplacer l’objet DefaultAzureCredential par un objet AzureKeyCredential.

String searchServiceEndpoint = "https://<Put your search service NAME here>.search.windows.net/";
DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();
public static void main(String[] args) {
    // Your search service endpoint
    String searchServiceEndpoint = "https://<Put your search service NAME here>.search.windows.net/";

    // Use the recommended keyless credential instead of the AzureKeyCredential credential.
    DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();
    //AzureKeyCredential credential = new AzureKeyCredential("Your search service admin key");

    // Create a SearchIndexClient to send create/delete index commands
    SearchIndexClient searchIndexClient = new SearchIndexClientBuilder()
        .endpoint(searchServiceEndpoint)
        .credential(credential)
        .buildClient();
    
    // Create a SearchClient to load and query documents
    String indexName = "hotels-quickstart-java";
    SearchClient searchClient = new SearchClientBuilder()
        .endpoint(searchServiceEndpoint)
        .credential(credential)
        .indexName(indexName)
        .buildClient();

    // Create Search Index for Hotel model
    searchIndexClient.createOrUpdateIndex(
        new SearchIndex(indexName, SearchIndexClient.buildSearchFields(Hotel.class, null))
        .setSuggesters(new SearchSuggester("sg", Arrays.asList("HotelName"))));

    // REDACTED FOR BREVITY . . . 
}

Création d'un index

Ce guide de démarrage rapide crée un index Hotels que vous allez charger avec des données sur des hôtels et sur lequel vous allez effectuer des requêtes. Dans cette étape, définissez les champs de l’index. Chaque définition de champ comprend un nom, un type de données et des attributs qui déterminent la façon dont le champ est utilisé.

Dans cet exemple, des méthodes synchrones de la bibliothèque Azure.Search.Documents sont utilisées par souci de simplicité et de lisibilité. En revanche, dans des scénarios de production, vous devez utiliser des méthodes asynchrones pour maintenir la scalabilité et la réactivité de votre application. Par exemple, vous pouvez utiliser CreateIndexAsync au lieu de CreateIndex.

Définir les structures

Vous avez créé deux classes d’assistance, Hotel.java et Address.java pour définir la structure d’un document d’hôtel et son adresse. La classe Hôtel comprend des champs pour un ID d’hôtel, nom, description, catégorie, étiquettes, parking, date de rénovation, évaluation et adresse. La classe Address inclut des champs pour l’adresse postale, la ville, l’état/la province, le code postal et le pays/région.

Dans la bibliothèque de client Azure.Search.Documents, vous pouvez utiliser SearchableField et SimpleField pour simplifier les définitions de champs.

  • SimpleField peut être n’importe quel type de données, ne peut jamais faire l’objet d’une recherche (il est ignoré pour les requêtes de recherche de texte intégral) et peut être récupéré (il n’est pas masqué). Les autres attributs sont désactivés par défaut, mais peuvent être activés. Vous pouvez utiliser un SimpleField pour les ID de document ou les champs utilisés seulement dans des filtres, des facettes ou des profils de scoring. Si c’est le cas, veillez à appliquer tous les attributs nécessaires pour le scénario, comme IsKey = true pour un ID de document.
  • SearchableField doit être une chaîne, et peut toujours faire l’objet d’une recherche et d’une récupération. Les autres attributs sont désactivés par défaut, mais peuvent être activés. Comme ce type de champ peut faire l’objet d’une recherche, il prend en charge les synonymes et l’ensemble complet des propriétés de l’analyseur.

Que vous utilisiez l’API SearchField de base ou un des modèles d’assistance, vous devez activer explicitement les attributs de filtre, de facette et de tri. Par exemple, isFilterable, isSortable et isFacetable doivent être explicitement attribués, comme indiqué dans l’exemple précédent.

Créer l’index de recherche

Dans App.java, créez un objet SearchIndex dans la méthode main, puis appelez la méthode createOrUpdateIndex pour créer l’index dans votre service de recherche. L’index comprend également un SearchSuggester pour activer l’autocomplétion sur les champs spécifiés.

// Create Search Index for Hotel model
searchIndexClient.createOrUpdateIndex(
    new SearchIndex(indexName, SearchIndexClient.buildSearchFields(Hotel.class, null))
    .setSuggesters(new SearchSuggester("sg", Arrays.asList("HotelName"))));

Chargement de documents

Recherche Azure AI effectue des recherches parmi les contenus stockés dans le service. Au cours de cette étape, vous allez charger des documents JSON conformes à l’index de l’hôtel que vous avez créé.

Dans la recherche Azure AI, les documents de recherche sont des structures de données qui sont à la fois des entrées pour l’indexation et des sorties de requêtes. Selon une source de données externe, les entrées de documents peuvent être des lignes dans une base de données, des objets blob dans le Stockage Blob ou des documents JSON sur le disque. Dans cet exemple, nous prenons un raccourci et incorporons des documents JSON pour quatre hôtels dans le code lui-même.

Lors du chargement de documents, vous devez utiliser un objet IndexDocumentsBatch. Un objet IndexDocumentsBatch contient une collection d’IndexActions, chacune contenant un document et une propriété qui indiquent à la recherche Azure AI l’action à effectuer (upload, merge, delete et mergeOrUpload).

Dans App.java, créez des documents et des actions d’index, puis passez-les à IndexDocumentsBatch. Les documents suivants sont conformes à l’index hotels-quickstart, tel que défini par la classe hotel.

private static void uploadDocuments(SearchClient searchClient)
{
    var hotelList = new ArrayList<Hotel>();

    var hotel = new Hotel();
    hotel.hotelId = "1";
    hotel.hotelName = "Stay-Kay City Hotel";
    hotel.description = "This classic hotel is fully-refurbished and ideally located on the main commercial artery of the city in the heart of New York. A few minutes away is Times Square and the historic centre of the city, as well as other places of interest that make New York one of America's most attractive and cosmopolitan cities.",
    hotel.category = "Boutique";
    hotel.tags = new String[] { "view", "air conditioning", "concierge" };
    hotel.parkingIncluded = false;
    hotel.lastRenovationDate = OffsetDateTime.of(LocalDateTime.of(LocalDate.of(2022, 1, 18), LocalTime.of(0, 0)), ZoneOffset.UTC);
    hotel.rating = 3.6;
    hotel.address = new Address();
    hotel.address.streetAddress = "677 5th Ave";
    hotel.address.city = "New York";
    hotel.address.stateProvince = "NY";
    hotel.address.postalCode = "10022";
    hotel.address.country = "USA";
    hotelList.add(hotel);
    
    // REDACTED FOR BREVITY

    var batch = new IndexDocumentsBatch<Hotel>();
    batch.addMergeOrUploadActions(hotelList);
    try
    {
        searchClient.indexDocuments(batch);
    }
    catch (Exception e)
    {
        e.printStackTrace();
        // If for some reason any documents are dropped during indexing, you can compensate by delaying and
        // retrying. This simple demo just logs failure and continues
        System.err.println("Failed to index some of the documents");
    }
}

Une fois que vous avez initialisé l’objet IndexDocumentsBatch, vous pouvez l’envoyer à l’index en appelant indexDocuments sur votre objet SearchClient.

Vous allez charger des documents en utilisant SearchClient dans main(), mais l’opération nécessite également des droits d’administrateur sur le service, généralement associé à SearchIndexClient. Une façon de configurer cette opération consiste à obtenir SearchClient via SearchIndexClient (searchIndexClient dans cet exemple).

uploadDocuments(searchClient);

Étant donné qu’il s’agit d’une application console qui exécute toutes les commandes de manière séquentielle, nous allons ajouter un délai d’attente de 2 secondes entre l’indexation et les requêtes.

// Wait 2 seconds for indexing to complete before starting queries (for demo and console-app purposes only)
System.out.println("Waiting for indexing...\n");
try
{
    Thread.sleep(2000);
}
catch (InterruptedException e)
{
}

Le retard de 2 secondes compense l’indexation, qui est asynchrone, afin que tous les documents puissent être indexés avant l’exécution des requêtes. Le codage dans un retard n’est nécessaire que dans les démonstrations, les tests et les exemples d’applications.

Rechercher dans un index

Vous pouvez obtenir les résultats de la requête dès que le premier document est indexé, mais les tests réels de votre index doivent attendre que tous les documents soient indexés.

Cette section ajoute deux éléments de fonctionnalité : logique de requête et résultats. Pour les requêtes, utilisez la méthode Rechercher. Cette méthode prend le texte de recherche (la chaîne de requête), ainsi que d’autres options.

Dans App.java, la méthode WriteDocuments imprime les résultats de recherche dans la console.

// Write search results to console
private static void WriteSearchResults(SearchPagedIterable searchResults)
{
    searchResults.iterator().forEachRemaining(result ->
    {
        Hotel hotel = result.getDocument(Hotel.class);
        System.out.println(hotel);
    });

    System.out.println();
}

// Write autocomplete results to console
private static void WriteAutocompleteResults(AutocompletePagedIterable autocompleteResults)
{
    autocompleteResults.iterator().forEachRemaining(result ->
    {
        String text = result.getText();
        System.out.println(text);
    });

    System.out.println();
}

Exemple de requête 1

La méthode RunQueries exécute des requêtes et retourne des résultats. Les résultats sont des objets Hotel. Cet exemple montre la signature de la méthode et la première requête. Cette requête montre le paramètre Select qui vous permet de composer le résultat à l’aide de champs sélectionnés dans le document.

// Run queries, use WriteDocuments to print output
private static void RunQueries(SearchClient searchClient)
{
    // Query 1
    System.out.println("Query #1: Search on empty term '*' to return all documents, showing a subset of fields...\n");

    SearchOptions options = new SearchOptions();
    options.setIncludeTotalCount(true);
    options.setFilter("");
    options.setOrderBy("");
    options.setSelect("HotelId", "HotelName", "Address/City");

    WriteSearchResults(searchClient.search("*", options, Context.NONE));
}

Exemple de requête 2

Dans la deuxième requête, recherchez un terme, ajoutez un filtre qui sélectionne les documents dont l’évaluation (Rating) est supérieure à 4, puis triez par Rating dans l’ordre décroissant. Un filtre est une expression booléenne évaluée sur des champs isFilterable dans un index. Les requêtes de filtre incluent ou excluent des valeurs. Par conséquent, aucun score de pertinence n’est associé à une requête de filtre.

// Query 2
System.out.println("Query #2: Search on 'hotels', filter on 'Rating gt 4', sort by Rating in descending order...\n");

options = new SearchOptions();
options.setFilter("Rating gt 4");
options.setOrderBy("Rating desc");
options.setSelect("HotelId", "HotelName", "Rating");

WriteSearchResults(searchClient.search("hotels", options, Context.NONE));

Exemple de requête 3

La troisième requête illustre l’utilisation de searchFields, qui sert à limiter l’étendue d’une opération de recherche en texte intégral à des champs spécifiques.

// Query 3
System.out.println("Query #3: Limit search to specific fields (pool in Tags field)...\n");

options = new SearchOptions();
options.setSearchFields("Tags");

options.setSelect("HotelId", "HotelName", "Tags");

WriteSearchResults(searchClient.search("pool", options, Context.NONE));

Exemple de requête 4

La quatrième requête illustre les facets, que vous pouvez utiliser pour créer une structure de navigation par facettes.

// Query 4
System.out.println("Query #4: Facet on 'Category'...\n");

options = new SearchOptions();
options.setFilter("");
options.setFacets("Category");
options.setSelect("HotelId", "HotelName", "Category");

WriteSearchResults(searchClient.search("*", options, Context.NONE));

Exemple de requête 5

La cinquième requête retourne un document spécifique.

// Query 5
System.out.println("Query #5: Look up a specific document...\n");

Hotel lookupResponse = searchClient.getDocument("3", Hotel.class);
System.out.println(lookupResponse.hotelId);
System.out.println();

Exemple de requête 6

La dernière requête montre la syntaxe pour l’autocomplétion, en simulant une entrée utilisateur partielle s qui est résolue en deux correspondances possibles dans les sourceFields associés au suggesteur que vous avez défini dans l’index.

// Query 6
System.out.println("Query #6: Call Autocomplete on HotelName that starts with 's'...\n");

WriteAutocompleteResults(searchClient.autocomplete("s", "sg"));

Résumé des requêtes

Les requêtes précédentes illustrent plusieurs manières d’établir des correspondances entre des termes dans une requête : recherche en texte intégral, filtres et autocomplétion.

La recherche en texte intégral et les filtres sont exécutés à l’aide de la méthode SearchClient.search. Une requête de recherche peut être transmise dans la chaîne searchText, tandis qu’une expression de filtre peut être transmise dans la propriété filter de la classe SearchOptions. Pour filtrer sans effectuer de recherche, transmettez simplement « * » pour le paramètre searchText de la méthode search. Pour effectuer une recherche sans filtrage, ne définissez pas la propriété filter et ne transmettez aucune instance SearchOptions.

Dans ce guide de démarrage rapide, vous utilisez la bibliothèque cliente Azure.Search.Documents pour créer, charger et interroger un index de recherche avec des exemples de données pour la recherche en texte intégral. La recherche en texte intégral utilise Apache Lucene pour l’indexation et les requêtes et l’algorithme de classement BM25 pour les résultats de scoring.

Ce guide de démarrage rapide utilise les données d’hôtel fictives du référentiel azure-search-sample-data pour remplir l’index.

Conseil

Vous pouvez télécharger le code source pour commencer par un projet terminé ou suivre ces étapes pour créer votre propre code.

Prérequis

Prérequis pour Microsoft Entra ID

Pour l’authentification sans clé recommandée avec l’ID Microsoft Entra, vous devez :

  • Installez Azure CLI.

  • Affectez les rôles Search Service Contributor et Search Index Data Contributor à votre compte d'utilisateur. Vous pouvez attribuer des rôles dans le Portail Azure sous Contrôle d’accès (IAM)>Ajouter une attribution de rôle. Pour plus d’informations, consultez Se connecter à la Recherche Azure AI à l’aide des rôles.

Obtenir des informations sur le service

Vous devez récupérer les informations suivantes pour authentifier votre application auprès de votre ressource Recherche Azure AI :

Nom de la variable Valeur
SEARCH_API_ENDPOINT Cette valeur se trouve dans le portail Azure. Sélectionnez votre service de recherche, puis dans le menu de gauche, sélectionnez Vue d’ensemble. La valeur d’URL sous Essentials est le point de terminaison dont vous avez besoin. Voici un exemple de point de terminaison : https://mydemo.search.windows.net.

En savoir plus sur l’authentification sans clé et la définition de variables d’environnement.

Configurer

  1. Créez un dossier full-text-quickstart pour contenir l’application et ouvrez Visual Studio Code dans ce dossier avec la commande suivante :

    mkdir full-text-quickstart && cd full-text-quickstart
    
  2. Créez le package.json avec la commande suivante :

    npm init -y
    
  3. Installez la bibliothèque de client Recherche Azure AI (Azure.Search.Documents) pour JavaScript avec :

    npm install @azure/search-documents
    
  4. Pour l’authentification sans mot de passe recommandée, installez la bibliothèque de client Azure Identity avec :

    npm install @azure/identity
    

Créer, charger et interroger un index de recherche

Dans la section de configuration précédente, vous avez installé la bibliothèque de client Recherche Azure AI et d’autres dépendances.

Dans cette section, vous ajoutez du code pour créer un index de recherche, chargez-le avec des documents et exécutez des requêtes. Vous exécutez le programme pour afficher les résultats dans la console. Pour obtenir une explication détaillée du code, consultez la section Explication du code .

L’exemple de code de ce guide de démarrage rapide utilise Microsoft Entra pour l’authentification sans clé recommandée. Si vous préférez utiliser une clé API, vous pouvez remplacer l’objet DefaultAzureCredential par un objet AzureKeyCredential.

String searchServiceEndpoint = "https://<Put your search service NAME here>.search.windows.net/";
DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();
  1. Créez un fichier nommé index.js et collez le code suivant dans index.js :

    // Import from the @azure/search-documents library
    import { SearchIndexClient, odata } from "@azure/search-documents";
    // Import from the Azure Identity library
    import { DefaultAzureCredential } from "@azure/identity";
    // Importing the hotels sample data
    import hotelData from './hotels.json' assert { type: "json" };
    // Load the .env file if it exists
    import * as dotenv from "dotenv";
    dotenv.config();
    // Defining the index definition
    const indexDefinition = {
        "name": "hotels-quickstart",
        "fields": [
            {
                "name": "HotelId",
                "type": "Edm.String",
                "key": true,
                "filterable": true
            },
            {
                "name": "HotelName",
                "type": "Edm.String",
                "searchable": true,
                "filterable": false,
                "sortable": true,
                "facetable": false
            },
            {
                "name": "Description",
                "type": "Edm.String",
                "searchable": true,
                "filterable": false,
                "sortable": false,
                "facetable": false,
                "analyzerName": "en.lucene"
            },
            {
                "name": "Description_fr",
                "type": "Edm.String",
                "searchable": true,
                "filterable": false,
                "sortable": false,
                "facetable": false,
                "analyzerName": "fr.lucene"
            },
            {
                "name": "Category",
                "type": "Edm.String",
                "searchable": true,
                "filterable": true,
                "sortable": true,
                "facetable": true
            },
            {
                "name": "Tags",
                "type": "Collection(Edm.String)",
                "searchable": true,
                "filterable": true,
                "sortable": false,
                "facetable": true
            },
            {
                "name": "ParkingIncluded",
                "type": "Edm.Boolean",
                "filterable": true,
                "sortable": true,
                "facetable": true
            },
            {
                "name": "LastRenovationDate",
                "type": "Edm.DateTimeOffset",
                "filterable": true,
                "sortable": true,
                "facetable": true
            },
            {
                "name": "Rating",
                "type": "Edm.Double",
                "filterable": true,
                "sortable": true,
                "facetable": true
            },
            {
                "name": "Address",
                "type": "Edm.ComplexType",
                "fields": [
                    {
                        "name": "StreetAddress",
                        "type": "Edm.String",
                        "filterable": false,
                        "sortable": false,
                        "facetable": false,
                        "searchable": true
                    },
                    {
                        "name": "City",
                        "type": "Edm.String",
                        "searchable": true,
                        "filterable": true,
                        "sortable": true,
                        "facetable": true
                    },
                    {
                        "name": "StateProvince",
                        "type": "Edm.String",
                        "searchable": true,
                        "filterable": true,
                        "sortable": true,
                        "facetable": true
                    },
                    {
                        "name": "PostalCode",
                        "type": "Edm.String",
                        "searchable": true,
                        "filterable": true,
                        "sortable": true,
                        "facetable": true
                    },
                    {
                        "name": "Country",
                        "type": "Edm.String",
                        "searchable": true,
                        "filterable": true,
                        "sortable": true,
                        "facetable": true
                    }
                ]
            }
        ],
        "suggesters": [
            {
                "name": "sg",
                "searchMode": "analyzingInfixMatching",
                "sourceFields": [
                    "HotelName"
                ]
            }
        ]
    };
    async function main() {
        // Your search service endpoint
        const searchServiceEndpoint = "https://<Put your search service NAME here>.search.windows.net/";
        // Use the recommended keyless credential instead of the AzureKeyCredential credential.
        const credential = new DefaultAzureCredential();
        //const credential = new AzureKeyCredential(Your search service admin key);
        // Create a SearchIndexClient to send create/delete index commands
        const searchIndexClient = new SearchIndexClient(searchServiceEndpoint, credential);
        // Creating a search client to upload documents and issue queries
        const indexName = "hotels-quickstart";
        const searchClient = searchIndexClient.getSearchClient(indexName);
        console.log('Checking if index exists...');
        await deleteIndexIfExists(searchIndexClient, indexName);
        console.log('Creating index...');
        let index = await searchIndexClient.createIndex(indexDefinition);
        console.log(`Index named ${index.name} has been created.`);
        console.log('Uploading documents...');
        let indexDocumentsResult = await searchClient.mergeOrUploadDocuments(hotelData['value']);
        console.log(`Index operations succeeded: ${JSON.stringify(indexDocumentsResult.results[0].succeeded)} `);
        // waiting one second for indexing to complete (for demo purposes only)
        sleep(1000);
        console.log('Querying the index...');
        console.log();
        await sendQueries(searchClient);
    }
    async function deleteIndexIfExists(searchIndexClient, indexName) {
        try {
            await searchIndexClient.deleteIndex(indexName);
            console.log('Deleting index...');
        }
        catch {
            console.log('Index does not exist yet.');
        }
    }
    async function sendQueries(searchClient) {
        // Query 1
        console.log('Query #1 - search everything:');
        let searchOptions = {
            includeTotalCount: true,
            select: ["HotelId", "HotelName", "Rating"]
        };
        let searchResults = await searchClient.search("*", searchOptions);
        for await (const result of searchResults.results) {
            console.log(`${JSON.stringify(result.document)}`);
        }
        console.log(`Result count: ${searchResults.count}`);
        console.log();
        // Query 2
        console.log('Query #2 - search with filter, orderBy, and select:');
        let state = 'FL';
        searchOptions = {
            filter: odata `Address/StateProvince eq ${state}`,
            orderBy: ["Rating desc"],
            select: ["HotelId", "HotelName", "Rating"]
        };
        searchResults = await searchClient.search("wifi", searchOptions);
        for await (const result of searchResults.results) {
            console.log(`${JSON.stringify(result.document)}`);
        }
        console.log();
        // Query 3
        console.log('Query #3 - limit searchFields:');
        searchOptions = {
            select: ["HotelId", "HotelName", "Rating"],
            searchFields: ["HotelName"]
        };
        searchResults = await searchClient.search("sublime palace", searchOptions);
        for await (const result of searchResults.results) {
            console.log(`${JSON.stringify(result.document)}`);
        }
        console.log();
        // Query 4
        console.log('Query #4 - limit searchFields and use facets:');
        searchOptions = {
            facets: ["Category"],
            select: ["HotelId", "HotelName", "Rating"],
            searchFields: ["HotelName"]
        };
        searchResults = await searchClient.search("*", searchOptions);
        for await (const result of searchResults.results) {
            console.log(`${JSON.stringify(result.document)}`);
        }
        console.log();
        // Query 5
        console.log('Query #5 - Lookup document:');
        let documentResult = await searchClient.getDocument('3');
        console.log(`HotelId: ${documentResult.HotelId}; HotelName: ${documentResult.HotelName}`);
        console.log();
    }
    function sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
    main().catch((err) => {
        console.error("The sample encountered an error:", err);
    });
    
  2. Créez un fichier nommé hotels.json et collez le code suivant dans hotels.json :

    {
        "value": [
            {
                "HotelId": "1",
                "HotelName": "Stay-Kay City Hotel",
                "Description": "This classic hotel is fully-refurbished and ideally located on the main commercial artery of the city in the heart of New York. A few minutes away is Times Square and the historic centre of the city, as well as other places of interest that make New York one of America's most attractive and cosmopolitan cities.",
                "Category": "Boutique",
                "Tags": ["view", "air conditioning", "concierge"],
                "ParkingIncluded": false,
                "LastRenovationDate": "2022-01-18T00:00:00Z",
                "Rating": 3.6,
                "Address": {
                    "StreetAddress": "677 5th Ave",
                    "City": "New York",
                    "StateProvince": "NY",
                    "PostalCode": "10022"
                }
            },
            {
                "HotelId": "2",
                "HotelName": "Old Century Hotel",
                "Description": "The hotel is situated in a nineteenth century plaza, which has been expanded and renovated to the highest architectural standards to create a modern, functional and first-class hotel in which art and unique historical elements coexist with the most modern comforts. The hotel also regularly hosts events like wine tastings, beer dinners, and live music.",
                "Category": "Boutique",
                "Tags": ["pool", "free wifi", "concierge"],
                "ParkingIncluded": "false",
                "LastRenovationDate": "2019-02-18T00:00:00Z",
                "Rating": 3.6,
                "Address": {
                    "StreetAddress": "140 University Town Center Dr",
                    "City": "Sarasota",
                    "StateProvince": "FL",
                    "PostalCode": "34243"
                }
            },
            {
                "HotelId": "3",
                "HotelName": "Gastronomic Landscape Hotel",
                "Description": "The Gastronomic Hotel stands out for its culinary excellence under the management of William Dough, who advises on and oversees all of the Hotel’s restaurant services.",
                "Category": "Suite",
                "Tags": ["restaurant", "bar", "continental breakfast"],
                "ParkingIncluded": "true",
                "LastRenovationDate": "2015-09-20T00:00:00Z",
                "Rating": 4.8,
                "Address": {
                    "StreetAddress": "3393 Peachtree Rd",
                    "City": "Atlanta",
                    "StateProvince": "GA",
                    "PostalCode": "30326"
                }
            },
            {
                "HotelId": "4",
                "HotelName": "Sublime Palace Hotel",
                "Description": "Sublime Palace Hotel is located in the heart of the historic center of Sublime in an extremely vibrant and lively area within short walking distance to the sites and landmarks of the city and is surrounded by the extraordinary beauty of churches, buildings, shops and monuments. Sublime Cliff is part of a lovingly restored 19th century resort, updated for every modern convenience.",
                "Category": "Boutique",
                "Tags": ["concierge", "view", "air conditioning"],
                "ParkingIncluded": true,
                "LastRenovationDate": "2020-02-06T00:00:00Z",
                "Rating": 4.6,
                "Address": {
                    "StreetAddress": "7400 San Pedro Ave",
                    "City": "San Antonio",
                    "StateProvince": "TX",
                    "PostalCode": "78216"
                }
            }
        ]
    }
    
  3. Créez un fichier nommé hotels_quickstart_index.json et collez le code suivant dans hotels_quickstart_index.json :

    {
    	"name": "hotels-quickstart",
    	"fields": [
    		{
    			"name": "HotelId",
    			"type": "Edm.String",
    			"key": true,
    			"filterable": true
    		},
    		{
    			"name": "HotelName",
    			"type": "Edm.String",
    			"searchable": true,
    			"filterable": false,
    			"sortable": true,
    			"facetable": false
    		},
    		{
    			"name": "Description",
    			"type": "Edm.String",
    			"searchable": true,
    			"filterable": false,
    			"sortable": false,
    			"facetable": false,
    			"analyzerName": "en.lucene"
    		},
    		{
    			"name": "Category",
    			"type": "Edm.String",
    			"searchable": true,
    			"filterable": true,
    			"sortable": true,
    			"facetable": true
    		},
    		{
    			"name": "Tags",
    			"type": "Collection(Edm.String)",
    			"searchable": true,
    			"filterable": true,
    			"sortable": false,
    			"facetable": true
    		},
    		{
    			"name": "ParkingIncluded",
    			"type": "Edm.Boolean",
    			"filterable": true,
    			"sortable": true,
    			"facetable": true
    		},
    		{
    			"name": "LastRenovationDate",
    			"type": "Edm.DateTimeOffset",
    			"filterable": true,
    			"sortable": true,
    			"facetable": true
    		},
    		{
    			"name": "Rating",
    			"type": "Edm.Double",
    			"filterable": true,
    			"sortable": true,
    			"facetable": true
    		},
    		{
    			"name": "Address",
    			"type": "Edm.ComplexType",
    			"fields": [
    				{
    					"name": "StreetAddress",
    					"type": "Edm.String",
    					"filterable": false,
    					"sortable": false,
    					"facetable": false,
    					"searchable": true
    				},
    				{
    					"name": "City",
    					"type": "Edm.String",
    					"searchable": true,
    					"filterable": true,
    					"sortable": true,
    					"facetable": true
    				},
    				{
    					"name": "StateProvince",
    					"type": "Edm.String",
    					"searchable": true,
    					"filterable": true,
    					"sortable": true,
    					"facetable": true
    				},
    				{
    					"name": "PostalCode",
    					"type": "Edm.String",
    					"searchable": true,
    					"filterable": true,
    					"sortable": true,
    					"facetable": true
    				},
    				{
    					"name": "Country",
    					"type": "Edm.String",
    					"searchable": true,
    					"filterable": true,
    					"sortable": true,
    					"facetable": true
    				}
    			]
    		}
    	],
    	"suggesters": [
    		{
    			"name": "sg",
    			"searchMode": "analyzingInfixMatching",
    			"sourceFields": [
    				"HotelName"
    			]
    		}
    	]
    }
    
  4. Connectez-vous à Azure à l’aide de la commande suivante :

    az login
    
  5. Exécutez le code JavaScript avec la commande suivante :

    node index.js
    

Explication du code

Créer un index

Le fichier hotels_quickstart_index.json définit le fonctionnement de Recherche Azure AI avec les documents que vous chargez à l’étape suivante. Chaque champ est identifié par un name et a un type spécifié. Chaque champ comporte également une série d’attributs d’index qui spécifient si la recherche Azure AI peut effectuer des recherches, filtrer, trier et définir des propriétés de facettes sur le champ. La plupart des champs sont des types de données simples, mais certains, comme AddressType, sont des types complexes qui vous permettent de créer des structures de données riches dans votre index. Vous pouvez en savoir plus sur les types de données pris en charge et les attributs d’index décrits dans Créer un index (REST).

Une fois notre définition d’index en place, nous voulons importer hotels_quickstart_index.json en haut du fichier index.js pour que la fonction main puisse accéder à la définition de l’index.

const indexDefinition = require('./hotels_quickstart_index.json');

Dans la fonction principale, nous créons ensuite un SearchIndexClient, qui est utilisé pour créer et gérer des index pour la recherche Azure AI.

const indexClient = new SearchIndexClient(endpoint, new AzureKeyCredential(apiKey));

Ensuite, nous voulons supprimer l’index s’il existe déjà. Il s’agit d’une opération courante pour le code de test/démonstration.

Pour ce faire, nous définissons une fonction simple qui tente de supprimer l’index.

async function deleteIndexIfExists(indexClient, indexName) {
    try {
        await indexClient.deleteIndex(indexName);
        console.log('Deleting index...');
    } catch {
        console.log('Index does not exist yet.');
    }
}

Pour exécuter la fonction, nous extrayons le nom de l’index de la définition de l’index et nous passons indexName avec indexClient à la fonction deleteIndexIfExists().

const indexName = indexDefinition["name"];

console.log('Checking if index exists...');
await deleteIndexIfExists(indexClient, indexName);

Après cela, nous sommes prêts à créer l’index avec la méthode createIndex().

console.log('Creating index...');
let index = await indexClient.createIndex(indexDefinition);

console.log(`Index named ${index.name} has been created.`);

Chargement de documents

Dans la recherche Azure AI, les documents sont des structures de données qui sont à la fois des entrées pour l’indexation et des sorties de requêtes. Vous pouvez envoyer des données de ce type dans l’index ou utiliser un indexeur. Dans ce cas, nous allons envoyer par programmation les documents à l’index.

Les entrées de documents peuvent être des lignes dans une base de données, des objets blob dans le Stockage Blob ou, comme dans cet exemple, des documents JSON sur le disque. À l’instar de ce que nous avons fait avec indexDefinition, nous devons également importer hotels.json en haut de index.js pour que les données soient accessibles dans notre fonction main.

const hotelData = require('./hotels.json');

Pour indexer les données dans l’index de recherche, nous devons maintenant créer un SearchClient. Alors que le SearchIndexClient est utilisé pour créer et gérer un index, le SearchClient est utilisé pour charger des documents et interroger l’index.

Il existe deux façons de créer un SearchClient. La première option consiste à créer un SearchClient à partir de zéro :

 const searchClient = new SearchClient(endpoint, indexName, new AzureKeyCredential(apiKey));

Vous pouvez également utiliser la méthode getSearchClient() du SearchIndexClient pour créer le SearchClient :

const searchClient = indexClient.getSearchClient(indexName);

Maintenant que le client est défini, chargez les documents dans l’index de recherche. Dans le cas présent, nous utilisons la méthode mergeOrUploadDocuments(), qui charge les documents ou les fusionne avec un document existant si un document ayant la même clé existe déjà.

console.log('Uploading documents...');
let indexDocumentsResult = await searchClient.mergeOrUploadDocuments(hotelData['value']);

console.log(`Index operations succeeded: ${JSON.stringify(indexDocumentsResult.results[0].succeeded)}`);

Rechercher dans un index

Avec un index créé et des documents chargés, vous êtes prêt à envoyer des requêtes à l’index. Dans cette section, nous envoyons cinq requêtes différentes à l’index de recherche pour illustrer différentes fonctionnalités de requête à votre disposition.

Les requêtes sont écrites dans une fonction sendQueries() que nous appelons dans la fonction main comme suit :

await sendQueries(searchClient);

Les requêtes sont envoyées en utilisant la méthode search() de searchClient. Le premier paramètre est le texte recherché et le deuxième paramètre spécifie les options de recherche.

Exemple de requête 1

La première requête recherche *, ce qui équivaut à effectuer une recherche dans tout, et sélectionne trois des champs de l’index. C’est une bonne pratique que d’appliquer un select seulement aux champs dont vous avez besoin, car l’extraction de données inutiles peut ajouter de la latence à vos requêtes.

Dans les searchOptions de cette requête, includeTotalCount est également défini sur true, ce qui retourne le nombre de résultats correspondants trouvés.

async function sendQueries(searchClient) {
    console.log('Query #1 - search everything:');
    let searchOptions = {
        includeTotalCount: true,
        select: ["HotelId", "HotelName", "Rating"]
    };

    let searchResults = await searchClient.search("*", searchOptions);
    for await (const result of searchResults.results) {
        console.log(`${JSON.stringify(result.document)}`);
    }
    console.log(`Result count: ${searchResults.count}`);

    // remaining queries go here
}

Les requêtes restantes décrites ci-dessous doivent également être ajoutées à la fonction sendQueries(). Elles sont séparées ici seulement pour des raisons de lisibilité.

Exemple de requête 2

Dans la requête suivante, nous spécifions le terme de recherche "wifi" et nous incluons aussi un filtre pour retourner seulement les résultats où l’état est égal à 'FL'. Les résultats sont également classés selon la valeur du champ Rating de l’hôtel.

console.log('Query #2 - Search with filter, orderBy, and select:');
let state = 'FL';
searchOptions = {
    filter: odata`Address/StateProvince eq ${state}`,
    orderBy: ["Rating desc"],
    select: ["HotelId", "HotelName", "Rating"]
};

searchResults = await searchClient.search("wifi", searchOptions);
for await (const result of searchResults.results) {
    console.log(`${JSON.stringify(result.document)}`);
}

Exemple de requête 3

Ensuite, la recherche est limitée à un seul champ pouvant faire l’objet d’une recherche en utilisant le paramètre searchFields. Cette approche constitue une option intéressante pour améliorer l’efficacité de votre requête si vous savez que vous êtes intéressé seulement par les correspondances dans certains champs.

console.log('Query #3 - Limit searchFields:');
searchOptions = {
    select: ["HotelId", "HotelName", "Rating"],
    searchFields: ["HotelName"]
};

searchResults = await searchClient.search("Sublime Palace", searchOptions);
for await (const result of searchResults.results) {
    console.log(`${JSON.stringify(result.document)}`);
}
console.log();

Exemple de requête 4

Une autre option courante à inclure dans une requête est facets. Les facettes vous permettent de créer des filtres sur votre interface utilisateur pour permettre aux utilisateurs de connaître facilement les valeurs sur lesquelles ils peuvent filtrer.

console.log('Query #4 - Use facets:');
searchOptions = {
    facets: ["Category"],
    select: ["HotelId", "HotelName", "Rating"],
    searchFields: ["HotelName"]
};

searchResults = await searchClient.search("*", searchOptions);
for await (const result of searchResults.results) {
    console.log(`${JSON.stringify(result.document)}`);
}

Exemple de requête 5

La dernière requête utilise la méthode getDocument() du searchClient. Ceci vous permet de récupérer efficacement un document en utilisant sa clé.

console.log('Query #5 - Lookup document:');
let documentResult = await searchClient.getDocument(key='3')
console.log(`HotelId: ${documentResult.HotelId}; HotelName: ${documentResult.HotelName}`)

Résumé des requêtes

Les requêtes précédentes illustrent plusieurs manières d’établir des correspondances entre des termes dans une requête : recherche en texte intégral, filtres et autocomplétion.

La recherche en texte intégral et les filtres sont exécutés en utilisant la méthode searchClient.search. Une requête de recherche peut être transmise dans la chaîne searchText, tandis qu’une expression de filtre peut être transmise dans la propriété filter de la classe SearchOptions. Pour filtrer sans effectuer de recherche, transmettez simplement « * » pour le paramètre searchText de la méthode search. Pour effectuer une recherche sans filtrage, ne définissez pas la propriété filter et ne transmettez aucune instance SearchOptions.

Dans ce guide de démarrage rapide, vous utilisez PowerShell et les API REST Recherche d’IA Azure pour créer, charger et interroger un index de recherche pour la recherche en texte intégral. La recherche en texte intégral utilise Apache Lucene pour l’indexation et les requêtes et l’algorithme de classement BM25 pour les résultats de scoring.

Ce guide de démarrage rapide utilise les données d’hôtel fictives du référentiel azure-search-sample-data pour remplir l’index.

Conseil

Vous pouvez télécharger le code source pour commencer par un projet terminé ou suivre ces étapes pour créer votre propre code.

Prérequis

Configurer l’accès

Vous pouvez vous connecter à votre service Recherche d’IA Azure à l’aide de clés API ou d’ID Microsoft Entra avec des attributions de rôles. Les clés sont plus faciles à utiliser, mais les rôles sont plus sécurisés.

Pour configurer l’accès en fonction du rôle recommandé :

  1. Connectez-vous au portail Azure et sélectionnez votre service de recherche.

  2. Dans le volet de gauche, sélectionnez Paramètres>Clés.

  3. Sous Contrôle d’accès à l’API, sélectionnez Les deux.

    Cette option active l’authentification basée sur des clés et sans clé. Après avoir affecté des rôles, vous pouvez revenir à cette étape et sélectionner le contrôle d’accès en fonction du rôle.

  4. Dans le volet gauche, sélectionnez Contrôle d’accès (IAM) .

  5. Sélectionnez Ajouter>Ajouter une attribution de rôle.

  6. Attribuez les rôles Contributeur du service de recherche et Contributeurde données d’index de recherche à votre compte d’utilisateur.

Pour plus d’informations, consultez Se connecter à la Recherche Azure AI à l’aide des rôles.

Obtenir un point de terminaison

Dans la section suivante, vous spécifiez le point de terminaison suivant pour établir une connexion à votre service Recherche d’IA Azure. Ces étapes supposent que vous avez configuré l’accès en fonction du rôle.

Pour obtenir votre point de terminaison de service :

  1. Connectez-vous au portail Azure et sélectionnez votre service de recherche.

  2. Dans le volet gauche, sélectionnez Vue d’ensemble.

  3. Notez l’URL, qui doit être similaire à https://my-service.search.windows.net.

Avant de pouvoir effectuer des appels d’API REST à votre service Recherche d’IA Azure, vous devez vous authentifier et vous connecter au service. Vous effectuez les étapes suivantes dans PowerShell, qui prend en charge les commandes Azure CLI utilisées dans les étapes deux et trois.

Pour vous connecter à votre service de recherche :

  1. Sur votre système local, ouvrez PowerShell.

  2. Connectez-vous à votre abonnement Azure. Si vous avez plusieurs abonnements, sélectionnez celui qui contient votre service de recherche.

    az login
    
  3. Créez un $token objet pour stocker votre jeton d’accès.

    $token = az account get-access-token --resource https://search.azure.com/ --query accessToken --output tsv
    
  4. Créez un $headers objet pour stocker votre jeton et votre type de contenu.

    $headers = @{
    'Authorization' = "Bearer $token"
    'Content-Type' = 'application/json' 
    'Accept' = 'application/json' }
    

    Vous devez uniquement définir l’en-tête une fois par session, mais vous devez l’ajouter à chaque requête.

  5. Créez un $url objet qui cible la collection d’index sur votre service de recherche. Remplacez <YOUR-SEARCH-SERVICE> par la valeur que vous avez obtenue dans Obtenir le point de terminaison.

    $url = "<YOUR-SEARCH-SERVICE>/indexes?api-version=2025-09-01&`$select=name"
    
  6. Exécutez Invoke-RestMethod pour envoyer une requête GET à votre service de recherche. Inclure ConvertTo-Json pour afficher les réponses du service.

    Invoke-RestMethod -Uri $url -Headers $headers | ConvertTo-Json
    

    Si votre service est vide et n’a pas d’index, la réponse est similaire à l’exemple suivant. Sinon, vous voyez une représentation JSON des définitions d’index.

    {
        "@odata.context":  "https://my-service.search.windows.net/$metadata#indexes",
        "value":  [
    
                  ]
    }
    

Créer un index de recherche

Avant d’ajouter du contenu à Recherche IA Azure, vous devez créer un index pour définir la façon dont le contenu est stocké et structuré. Un index est conceptuellement similaire à une table d’une base de données relationnelle, mais il est spécifiquement conçu pour les opérations de recherche, telles que la recherche en texte intégral.

Exécutez les commandes suivantes dans la même session PowerShell que vous avez démarrée dans la section précédente.

Pour créer un index :

  1. Créez un $body objet pour définir le schéma d’index.

    $body = @"
    {
        "name": "hotels-quickstart",  
        "fields": [
            {"name": "HotelId", "type": "Edm.String", "key": true, "filterable": true},
            {"name": "HotelName", "type": "Edm.String", "searchable": true, "filterable": false, "sortable": true, "facetable": false},
            {"name": "Description", "type": "Edm.String", "searchable": true, "filterable": false, "sortable": false, "facetable": false, "analyzer": "en.lucene"},
            {"name": "Category", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true},
            {"name": "Tags", "type": "Collection(Edm.String)", "searchable": true, "filterable": true, "sortable": false, "facetable": true},
            {"name": "ParkingIncluded", "type": "Edm.Boolean", "filterable": true, "sortable": true, "facetable": true},
            {"name": "LastRenovationDate", "type": "Edm.DateTimeOffset", "filterable": true, "sortable": true, "facetable": true},
            {"name": "Rating", "type": "Edm.Double", "filterable": true, "sortable": true, "facetable": true},
            {"name": "Address", "type": "Edm.ComplexType", 
                "fields": [
                {"name": "StreetAddress", "type": "Edm.String", "filterable": false, "sortable": false, "facetable": false, "searchable": true},
                {"name": "City", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true},
                {"name": "StateProvince", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true},
                {"name": "PostalCode", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true},
                {"name": "Country", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true}
            ]
         }
      ]
    }
    "@
    
  2. Mettez à jour l’objet $url pour cibler le nouvel index. Remplacez <YOUR-SEARCH-SERVICE> par la valeur que vous avez obtenue dans Obtenir le point de terminaison.

    $url = "<YOUR-SEARCH-SERVICE>/indexes/hotels-quickstart?api-version=2025-09-01"
    
  3. Exécutez Invoke-RestMethod pour créer l’index sur votre service de recherche.

    Invoke-RestMethod -Uri $url -Headers $headers -Method Put -Body $body | ConvertTo-Json
    

    La réponse doit contenir la représentation JSON du schéma d’index.

À propos de la demande de création d’index

Ce guide de démarrage rapide appelle index - Créer (API REST) pour créer un index de recherche nommé hotels-quickstart et ses structures de données physiques sur votre service de recherche.

Dans le schéma d’index, la fields collection définit la structure des documents d’hôtel. Chaque champ dispose de name données type et d'attributs qui déterminent son comportement lors de l'indexation et des requêtes. Le HotelId champ est marqué comme la clé, que recherche Azure AI nécessite pour identifier de manière unique chaque document dans un index.

Points clés sur le schéma d’index :

  • Utilisez des champs de chaîne (Edm.String) pour rendre les données numériques pouvant faire l’objet d’une recherche en texte intégral. D’autres types de données pris en charge, tels que Edm.Int32, sont filtrables, triables, facetables et récupérables, mais ne peuvent pas faire l’objet d’une recherche.

  • La plupart de nos champs sont des types de données simples, mais vous pouvez définir des types complexes pour représenter des données imbriquées, telles que le Address champ.

  • Les attributs de champ déterminent les actions autorisées. Les API REST autorisent de nombreuses actions par défaut. Par exemple, toutes les chaînes peuvent faire l’objet d’une recherche et sont récupérables. Avec les API REST, vous pouvez uniquement utiliser des attributs si vous devez désactiver un comportement.

Charger l’index

Les index nouvellement créés sont vides. Pour remplir un index et le rendre pouvant faire l’objet d’une recherche, vous devez charger des documents JSON conformes au schéma d’index.

Dans Recherche IA Azure, les documents servent d’entrées pour l’indexation et les sorties pour les requêtes. Par souci de simplicité, ce guide de démarrage rapide fournit des exemples de documents d’hôtel en tant que JSON inline. Dans les scénarios de production, toutefois, le contenu est souvent extrait de sources de données connectées et transformé en JSON à l’aide d’indexeurs.

Pour charger des documents dans votre index :

  1. Créez un $body objet pour stocker la charge utile JSON de quatre exemples de documents.

    $body = @"
        {
            "value": [
            {
            "@search.action": "upload",
            "HotelId": "1",
            "HotelName": "Stay-Kay City Hotel",
            "Description": "This classic hotel is fully-refurbished and ideally located on the main commercial artery of the city in the heart of New York. A few minutes away is Times Square and the historic centre of the city, as well as other places of interest that make New York one of America's most attractive and cosmopolitan cities.",
            "Category": "Boutique",
            "Tags": [ "view", "air conditioning", "concierge" ],
            "ParkingIncluded": false,
            "LastRenovationDate": "2022-01-18T00:00:00Z",
            "Rating": 3.60,
            "Address": 
                {
                "StreetAddress": "677 5th Ave",
                "City": "New York",
                "StateProvince": "NY",
                "PostalCode": "10022",
                "Country": "USA"
                } 
            },
            {
            "@search.action": "upload",
            "HotelId": "2",
            "HotelName": "Old Century Hotel",
            "Description": "The hotel is situated in a nineteenth century plaza, which has been expanded and renovated to the highest architectural standards to create a modern, functional and first-class hotel in which art and unique historical elements coexist with the most modern comforts. The hotel also regularly hosts events like wine tastings, beer dinners, and live music.",
            "Category": "Boutique",
            "Tags": [ "pool", "free wifi", "concierge" ],
            "ParkingIncluded": false,
            "LastRenovationDate": "2019-02-18T00:00:00Z",
            "Rating": 3.60,
            "Address": 
                {
                "StreetAddress": "140 University Town Center Dr",
                "City": "Sarasota",
                "StateProvince": "FL",
                "PostalCode": "34243",
                "Country": "USA"
                } 
            },
            {
            "@search.action": "upload",
            "HotelId": "3",
            "HotelName": "Gastronomic Landscape Hotel",
            "Description": "The Gastronomic Hotel stands out for its culinary excellence under the management of William Dough, who advises on and oversees all of the Hotel’s restaurant services.",
            "Category": "Suite",
            "Tags": [ "restaurant", "bar", "continental breakfast" ],
            "ParkingIncluded": true,
            "LastRenovationDate": "2015-09-20T00:00:00Z",
            "Rating": 4.80,
            "Address": 
                {
                "StreetAddress": "3393 Peachtree Rd",
                "City": "Atlanta",
                "StateProvince": "GA",
                "PostalCode": "30326",
                "Country": "USA"
                } 
            },
            {
            "@search.action": "upload",
            "HotelId": "4",
            "HotelName": "Sublime Palace Hotel",
            "Description": "Sublime Palace Hotel is located in the heart of the historic center of Sublime in an extremely vibrant and lively area within short walking distance to the sites and landmarks of the city and is surrounded by the extraordinary beauty of churches, buildings, shops and monuments. Sublime Cliff is part of a lovingly restored 19th century resort, updated for every modern convenience.",
            "Category": "Boutique",
            "Tags": [ "concierge", "view", "air conditioning" ],
            "ParkingIncluded": true,
            "LastRenovationDate": "2020-02-06T00:00:00Z",
            "Rating": 4.60,
            "Address": 
                {
                "StreetAddress": "7400 San Pedro Ave",
                "City": "San Antonio",
                "StateProvince": "TX",
                "PostalCode": "78216",
                "Country": "USA"
                }
            }
          ]
        }
    "@
    
  2. Mettez à jour l’objet $url pour cibler le point de terminaison d’indexation. Remplacez <YOUR-SEARCH-SERVICE> par la valeur que vous avez obtenue dans Obtenir le point de terminaison.

    $url = "<YOUR-SEARCH-SERVICE>/indexes/hotels-quickstart/docs/index?api-version=2025-09-01"
    
  3. Exécutez Invoke-RestMethod pour envoyer la demande de chargement à votre service de recherche.

    Invoke-RestMethod -Uri $url -Headers $headers -Method Post -Body $body | ConvertTo-Json
    

    La réponse doit contenir la clé et l’état de chaque document chargé.

À propos de la demande de chargement

Ce guide de démarrage rapide appelle Documents - Index (API REST) pour ajouter quatre exemples de documents d’hôtel à votre index. Par rapport à la requête précédente, l’URI est étendu pour inclure la docs collection et l’opération index.

Chaque document du value tableau représente un hôtel et contient des champs qui correspondent au schéma d’index. Le @search.action paramètre spécifie l’opération à effectuer pour chaque document. Notre exemple utilise upload, qui ajoute le document s’il n’existe pas ou met à jour le document s’il existe.

Interrogation de l'index

Maintenant que les documents sont chargés dans votre index, vous pouvez utiliser la recherche en texte intégral pour rechercher des termes ou expressions spécifiques dans leurs champs.

Pour exécuter une requête de texte intégral sur votre index :

  1. Mettez à jour l’objet $url pour spécifier les paramètres de recherche. Remplacez <YOUR-SEARCH-SERVICE> par la valeur que vous avez obtenue dans Obtenir le point de terminaison.

    $url = '<YOUR-SEARCH-SERVICE>/indexes/hotels-quickstart/docs?api-version=2025-09-01&search=attached restaurant&searchFields=Description,Tags&$select=HotelId,HotelName,Tags,Description&$count=true'
    
  2. Exécutez Invoke-RestMethod pour envoyer la demande de requête à votre service de recherche.

    Invoke-RestMethod -Uri $url -Headers $headers | ConvertTo-Json
    

    La réponse doit être similaire à l’exemple suivant, qui montre un document hôtel correspondant, son score de pertinence et ses champs sélectionnés.

    {
      "@odata.context": "https://my-service.search.windows.net/indexes('hotels-quickstart')/$metadata#docs(*)",
      "@odata.count": 1,
      "value": [
        {
          "@search.score": 0.5575875,
          "HotelId": "3",
          "HotelName": "Gastronomic Landscape Hotel",
          "Description": "The Gastronomic Hotel stands out for its culinary excellence under the management of William Dough, who advises on and oversees all of the Hotel's restaurant services.",
          "Tags": "restaurant bar continental breakfast"
        }
      ]
    }
    

À propos de la requête

Ce guide de démarrage rapide appelle Documents – de publication (API REST) pour rechercher des documents d’hôtel qui correspondent à vos critères de recherche. L’URI cible toujours la docs collection, mais n’inclut plus l’opération index .

Les demandes de recherche en texte intégral incluent toujours un search paramètre qui contient le texte de la requête. Le texte de la requête peut inclure un ou plusieurs termes, expressions ou opérateurs. En plus de search, vous pouvez spécifier d’autres paramètres pour affiner le comportement et les résultats de la recherche.

Notre requête recherche les termes « restaurant attenant » dans les champs Description et Tags de chaque document d’hôtel. Le $select paramètre limite les champs retournés dans la réponse à HotelId, HotelName, Tagset Description. Le $count paramètre demande le nombre total de documents correspondants.

Autres exemples de requêtes

Exécutez les commandes suivantes pour explorer la syntaxe de la requête. Vous pouvez effectuer des recherches de chaînes, utiliser $filter des expressions, limiter les jeux de résultats, sélectionner des champs spécifiques, etc. N’oubliez pas de remplacer <YOUR-SEARCH-SERVICE> par la valeur que vous avez obtenue dans Obtenir un point de terminaison.

# Query example 1
# Search the index for the terms 'restaurant' and 'wifi'
# Return only the HotelName, Description, and Tags fields
$url = '<YOUR-SEARCH-SERVICE>/indexes/hotels-quickstart/docs?api-version=2025-09-01&search=restaurant wifi&$count=true&$select=HotelName,Description,Tags'

# Query example 2 
# Use a filter to find hotels rated 4 or higher
# Return only the HotelName and Rating fields
$url = '<YOUR-SEARCH-SERVICE>/indexes/hotels-quickstart/docs?api-version=2025-09-01&search=*&$filter=Rating gt 4&$select=HotelName,Rating'

# Query example 3
# Take the top two results
# Return only the HotelName and Category fields
$url = '<YOUR-SEARCH-SERVICE>/indexes/hotels-quickstart/docs?api-version=2025-09-01&search=boutique&$top=2&$select=HotelName,Category'

# Query example 4
# Sort by a specific field (Address/City) in ascending order
# Return only the HotelName, Address/City, Tags, and Rating fields
$url = '<YOUR-SEARCH-SERVICE>/indexes/hotels-quickstart/docs?api-version=2025-09-01&search=pool&$orderby=Address/City asc&$select=HotelName, Address/City, Tags, Rating'

Dans ce guide de démarrage rapide, vous utilisez la bibliothèque cliente Azure.Search.Documents pour créer, charger et interroger un index de recherche avec des exemples de données pour la recherche en texte intégral. La recherche en texte intégral utilise Apache Lucene pour l’indexation et les requêtes et l’algorithme de classement BM25 pour les résultats de scoring.

Ce guide de démarrage rapide utilise les données d’hôtel fictives du référentiel azure-search-sample-data pour remplir l’index.

Conseil

Vous pouvez télécharger le code source pour commencer par un projet terminé ou suivre ces étapes pour créer votre propre code.

Prérequis

Prérequis pour Microsoft Entra ID

Pour l’authentification sans clé recommandée avec l’ID Microsoft Entra, vous devez :

  • Installez Azure CLI.

  • Affectez les rôles Search Service Contributor et Search Index Data Contributor à votre compte d'utilisateur. Vous pouvez attribuer des rôles dans le Portail Azure sous Contrôle d’accès (IAM)>Ajouter une attribution de rôle. Pour plus d’informations, consultez Se connecter à la Recherche Azure AI à l’aide des rôles.

Obtenir des informations sur le service

Vous devez récupérer les informations suivantes pour authentifier votre application auprès de votre ressource Recherche Azure AI :

Nom de la variable Valeur
SEARCH_API_ENDPOINT Cette valeur se trouve dans le portail Azure. Sélectionnez votre service de recherche, puis dans le menu de gauche, sélectionnez Vue d’ensemble. La valeur d’URL sous Essentials est le point de terminaison dont vous avez besoin. Voici un exemple de point de terminaison : https://mydemo.search.windows.net.

En savoir plus sur l’authentification sans clé et la définition de variables d’environnement.

Configurer votre environnement

Vous exécutez l’exemple de code dans un notebook Jupyter. Vous devez donc configurer votre environnement pour exécuter des notebooks Jupyter.

  1. Téléchargez ou copiez l’exemple de notebook à partir de GitHub.

  2. Ouvrez le notebook dans Visual Studio Code.

  3. Créez un environnement Python à utiliser pour installer le package dont vous avez besoin pour ce tutoriel.

    Important

    N’installez pas de packages dans votre installation globale de Python. Vous devez toujours utiliser un environnement virtuel ou conda lors de l’installation de packages Python. Sinon, vous pouvez interrompre votre installation globale de Python.

    py -3 -m venv .venv
    .venv\scripts\activate
    

    La configuration peut prendre une minute. Si vous rencontrez des problèmes, consultez Environnements Python dans VS Code.

  4. Installez les notebooks Jupyter et le noyau IPython pour les notebooks Jupyter si vous ne les avez pas déjà.

    pip install jupyter
    pip install ipykernel
    python -m ipykernel install --user --name=.venv
    
  5. Sélectionnez le noyau du bloc-notes.

    1. Dans le coin supérieur droit du bloc-notes, sélectionnez Sélectionner le noyau.
    2. Si vous voyez .venv dans la liste, sélectionnez-le. Si vous ne le voyez pas, sélectionnez Sélectionner un autre noyau>Environnements Python>.venv.

Créer, charger et interroger un index de recherche

Dans cette section, vous ajoutez du code pour créer un index de recherche, chargez-le avec des documents et exécutez des requêtes. Vous exécutez le programme pour afficher les résultats dans la console. Pour obtenir une explication détaillée du code, consultez la section Explication du code .

  1. Assurez-vous que le notebook est ouvert dans le noyau .venv, comme décrit dans la section précédente.

  2. Exécutez la première cellule de code pour installer les packages requis, y compris azure-search-documents.

    ! pip install azure-search-documents==11.6.0b1 --quiet
    ! pip install azure-identity --quiet
    ! pip install python-dotenv --quiet
    
  3. Remplacez le contenu de la deuxième cellule de code par le code suivant en fonction de votre méthode d’authentification.

    Remarque

    L’exemple de code de ce guide de démarrage rapide utilise Microsoft Entra pour l’authentification sans clé recommandée. Si vous préférez utiliser une clé API, vous pouvez remplacer l’objet DefaultAzureCredential par un objet AzureKeyCredential.

    from azure.core.credentials import AzureKeyCredential
    from azure.identity import DefaultAzureCredential, AzureAuthorityHosts
    
    search_endpoint: str = "https://<Put your search service NAME here>.search.windows.net/"
    authority = AzureAuthorityHosts.AZURE_PUBLIC_CLOUD
    credential = DefaultAzureCredential(authority=authority)
    
    index_name: str = "hotels-quickstart-python"
    
  4. Supprimez les deux lignes suivantes de la cellule de code Créer un index. Les informations d’identification sont déjà définies dans la cellule de code précédente.

    from azure.core.credentials import AzureKeyCredential
    credential = AzureKeyCredential(search_api_key)
    
  5. Exécutez la cellule de code Créer un index pour créer un index de recherche.

  6. Exécutez les cellules de code restantes de manière séquentielle pour charger des documents et exécuter des requêtes.

Explication du code

Création d'un index

SearchIndexClient est utilisé pour créer et gérer des index pour Recherche Azure AI. Chaque champ est identifié par un name et a un type spécifié.

Chaque champ comporte également une série d’attributs d’index qui spécifient si la recherche Azure AI peut effectuer des recherches, filtrer, trier et définir des propriétés de facettes sur le champ. La plupart des champs sont des types de données simples, mais certains, comme AddressType, sont des types complexes qui vous permettent de créer des structures de données riches dans votre index. Vous pouvez en savoir plus sur les types de données pris en charge et les attributs d’index décrits dans Créer un index (REST).

Créer une charge utile de documents et charger des documents

Utilisez une action d’index pour le type d’opération, comme upload ou merge-and-upload. Les documents proviennent de l’exemple HotelsData sur GitHub.

Rechercher dans un index

Vous pouvez obtenir les résultats de la requête dès que le premier document est indexé, mais les tests réels de votre index doivent attendre que tous les documents soient indexés.

Utilisez la méthode search de la classe search.client.

Les exemples de requêtes dans le notebook sont les suivants :

  • Requête basique : exécute une recherche vide (search=*), qui retourne une liste non classée (score de recherche = 1.0) de documents arbitraires. Étant donné qu’il n’y a aucun critère, tous les documents sont inclus dans les résultats.
  • Requête de termes : ajoute des termes entiers à l’expression de recherche (« wifi »). Cette requête spécifie que les résultats contiennent uniquement les champs de l’instruction select. Le fait de limiter les champs de retour réduit la quantité de données renvoyées sur le réseau ainsi que la latence de recherche.
  • Requête filtrée : ajoute une expression de filtre afin de retourner uniquement les hôtels ayant une évaluation supérieure à quatre, triés par ordre décroissant.
  • Étendue champée : ajoute search_fields à l’exécution de requête d’étendue à des champs spécifiques.
  • Facettes : génère des facettes pour les correspondances positives trouvées dans les résultats de recherche. Il n’y a pas de correspondance nulle. Si les résultats de la recherche n’incluent pas le terme wifi, alors wifi n’apparaît pas dans la structure de navigation par facettes.
  • Rechercher un document : retourne un document en fonction de sa clé. Cette opération est utile si vous souhaitez fournir une extraction quand un utilisateur sélectionne un élément dans un résultat de recherche.
  • Autocomplétion : fournit des correspondances potentielles au fur et à mesure que l’utilisateur tape dans la zone de recherche. L’autocomplétion utilise un suggesteur (sg) pour savoir quels champs contiennent des correspondances potentielles aux demandes du suggesteur. Dans ce guide de démarrage rapide, ces champs sont Tags, Address/City et Address/Country. Pour simuler l’autocomplétion, passez les lettres sa en tant que chaîne partielle. La méthode d’autocomplétion de SearchClient renvoie les correspondances de termes potentielles.

Supprimer l’index

Si vous avez terminé avec cet index, vous pouvez le supprimer en exécutant la cellule de code Nettoyer. La suppression d’index inutiles libère de l’espace pour parcourir plus de guides de démarrage rapide et de tutoriels.

Dans ce guide de démarrage rapide, vous utilisez les API REST Recherche d’IA Azure pour créer, charger et interroger un index de recherche pour la recherche en texte intégral. La recherche en texte intégral utilise Apache Lucene pour l’indexation et les requêtes et l’algorithme de classement BM25 pour les résultats de scoring.

Ce guide de démarrage rapide utilise les données d’hôtel fictives du référentiel azure-search-sample-data pour remplir l’index.

Conseil

Vous pouvez télécharger le code source pour commencer par un projet terminé ou suivre ces étapes pour créer votre propre code.

Prérequis

Configurer l’accès

Vous pouvez vous connecter à votre service Recherche d’IA Azure à l’aide de clés API ou d’ID Microsoft Entra avec des attributions de rôles. Les clés sont plus faciles à utiliser, mais les rôles sont plus sécurisés.

Pour configurer l’accès en fonction du rôle recommandé :

  1. Connectez-vous au portail Azure et sélectionnez votre service de recherche.

  2. Dans le volet de gauche, sélectionnez Paramètres>Clés.

  3. Sous Contrôle d’accès à l’API, sélectionnez Les deux.

    Cette option active l’authentification basée sur des clés et sans clé. Après avoir affecté des rôles, vous pouvez revenir à cette étape et sélectionner le contrôle d’accès en fonction du rôle.

  4. Dans le volet gauche, sélectionnez Contrôle d’accès (IAM) .

  5. Sélectionnez Ajouter>Ajouter une attribution de rôle.

  6. Attribuez les rôles Contributeur du service de recherche et Contributeurde données d’index de recherche à votre compte d’utilisateur.

Pour plus d’informations, consultez Se connecter à la Recherche Azure AI à l’aide des rôles.

Obtenir l'adresse de point d'accès et le jeton

Dans la section suivante, vous spécifiez le point de terminaison et le jeton suivants pour établir une connexion à votre service Recherche d’IA Azure. Ces étapes supposent que vous avez configuré l’accès en fonction du rôle.

Pour obtenir votre point de terminaison de service et votre jeton :

  1. Connectez-vous au portail Azure et sélectionnez votre service de recherche.

  2. Dans le volet gauche, sélectionnez Vue d’ensemble.

  3. Notez l’URL, qui doit être similaire à https://my-service.search.windows.net.

  4. Sur votre système local, ouvrez un terminal.

  5. Connectez-vous à votre abonnement Azure. Si vous avez plusieurs abonnements, sélectionnez celui qui contient votre service de recherche.

    az login
    
  6. Notez votre jeton Microsoft Entra.

    az account get-access-token --scope https://search.azure.com/.default
    

Configurer votre fichier

Avant de pouvoir effectuer des appels d’API REST à votre service Recherche d’IA Azure, vous devez créer un fichier pour stocker votre point de terminaison de service, votre jeton d’authentification et les requêtes ultérieures. L’extension client REST dans Visual Studio Code prend en charge cette tâche.

Pour configurer votre fichier de requête :

  1. Sur votre système local, ouvrez Visual Studio Code.

  2. Créez un fichier .rest ou .http.

  3. Collez les éléments de substitution suivants ainsi que la requête dans le fichier.

    @baseUrl = PUT-YOUR-SEARCH-SERVICE-ENDPOINT-HERE
    @token = PUT-YOUR-PERSONAL-IDENTITY-TOKEN-HERE
    
    ### List existing indexes by name
    GET {{baseUrl}}/indexes?api-version=2025-09-01  HTTP/1.1
        Authorization: Bearer {{token}}
    
  4. Remplacez les espaces réservés @baseUrl et @token avec les valeurs que vous avez obtenues dans Obtenir le point de terminaison et le jeton. N’incluez pas de guillemets.

  5. Sous ### List existing indexes by name, sélectionnez Envoyer une demande.

    Une réponse doit apparaître dans un volet adjacent. Si vous avez des index existants, ceux-ci sont répertoriés. Sinon, la liste est vide. Si le code HTTP est 200 OK, vous êtes prêt pour les étapes suivantes.

    Capture d’écran illustrant un client REST configuré pour une requête de service de recherche.

Créer un index de recherche

Avant d’ajouter du contenu à Recherche IA Azure, vous devez créer un index pour définir la façon dont le contenu est stocké et structuré. Un index est conceptuellement similaire à une table d’une base de données relationnelle, mais il est spécifiquement conçu pour les opérations de recherche, telles que la recherche en texte intégral.

Pour créer un index :

  1. Collez la requête suivante dans votre fichier.

    ### Create a new index
    POST {{baseUrl}}/indexes?api-version=2025-09-01  HTTP/1.1
        Content-Type: application/json
        Authorization: Bearer {{token}}
    
        {
            "name": "hotels-quickstart",  
            "fields": [
                {"name": "HotelId", "type": "Edm.String", "key": true, "filterable": true},
                {"name": "HotelName", "type": "Edm.String", "searchable": true, "filterable": false, "sortable": true, "facetable": false},
                {"name": "Description", "type": "Edm.String", "searchable": true, "filterable": false, "sortable": false, "facetable": false, "analyzer": "en.lucene"},
                {"name": "Category", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true},
                {"name": "Tags", "type": "Collection(Edm.String)", "searchable": true, "filterable": true, "sortable": false, "facetable": true},
                {"name": "ParkingIncluded", "type": "Edm.Boolean", "filterable": true, "sortable": true, "facetable": true},
                {"name": "LastRenovationDate", "type": "Edm.DateTimeOffset", "filterable": true, "sortable": true, "facetable": true},
                {"name": "Rating", "type": "Edm.Double", "filterable": true, "sortable": true, "facetable": true},
                {"name": "Address", "type": "Edm.ComplexType", 
                    "fields": [
                    {"name": "StreetAddress", "type": "Edm.String", "filterable": false, "sortable": false, "facetable": false, "searchable": true},
                    {"name": "City", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true},
                    {"name": "StateProvince", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true},
                    {"name": "PostalCode", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true},
                    {"name": "Country", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true}
                    ]
                }
            ]
        }
    
  2. Sous ### Create a new index, sélectionnez Envoyer une demande.

    Vous devez recevoir une HTTP/1.1 201 Created réponse dont le corps contient la représentation JSON du schéma d’index.

À propos de la demande de création d’index

Ce guide de démarrage rapide appelle index - Créer (API REST) pour créer un index de recherche nommé hotels-quickstart et ses structures de données physiques sur votre service de recherche.

Dans le schéma d’index, la fields collection définit la structure des documents d’hôtel. Chaque champ dispose de name données type et d'attributs qui déterminent son comportement lors de l'indexation et des requêtes. Le HotelId champ est marqué comme la clé, que recherche Azure AI nécessite pour identifier de manière unique chaque document dans un index.

Points clés sur le schéma d’index :

  • Utilisez des champs de chaîne (Edm.String) pour rendre les données numériques pouvant faire l’objet d’une recherche en texte intégral. D’autres types de données pris en charge, tels que Edm.Int32, sont filtrables, triables, facetables et récupérables, mais ne peuvent pas faire l’objet d’une recherche.

  • La plupart de nos champs sont des types de données simples, mais vous pouvez définir des types complexes pour représenter des données imbriquées, telles que le Address champ.

  • Les attributs de champ déterminent les actions autorisées. Les API REST autorisent de nombreuses actions par défaut. Par exemple, toutes les chaînes peuvent faire l’objet d’une recherche et sont récupérables. Avec les API REST, vous pouvez uniquement utiliser des attributs si vous devez désactiver un comportement.

Charger l’index

Les index nouvellement créés sont vides. Pour remplir un index et le rendre pouvant faire l’objet d’une recherche, vous devez charger des documents JSON conformes au schéma d’index.

Dans Recherche IA Azure, les documents servent d’entrées pour l’indexation et les sorties pour les requêtes. Par souci de simplicité, ce guide de démarrage rapide fournit des exemples de documents d’hôtel en tant que JSON inline. Dans les scénarios de production, toutefois, le contenu est souvent extrait de sources de données connectées et transformé en JSON à l’aide d’indexeurs.

Pour charger des documents dans votre index :

  1. Collez la requête suivante dans votre fichier.

    ### Upload documents
    POST {{baseUrl}}/indexes/hotels-quickstart/docs/index?api-version=2025-09-01  HTTP/1.1
        Content-Type: application/json
        Authorization: Bearer {{token}}
    
        {
            "value": [
            {
            "@search.action": "upload",
            "HotelId": "1",
            "HotelName": "Stay-Kay City Hotel",
            "Description": "This classic hotel is fully-refurbished and ideally located on the main commercial artery of the city in the heart of New York. A few minutes away is Times Square and the historic centre of the city, as well as other places of interest that make New York one of America's most attractive and cosmopolitan cities.",
            "Category": "Boutique",
            "Tags": [ "view", "air conditioning", "concierge" ],
            "ParkingIncluded": false,
            "LastRenovationDate": "2022-01-18T00:00:00Z",
            "Rating": 3.60,
            "Address": 
                {
                "StreetAddress": "677 5th Ave",
                "City": "New York",
                "StateProvince": "NY",
                "PostalCode": "10022",
                "Country": "USA"
                } 
            },
            {
            "@search.action": "upload",
            "HotelId": "2",
            "HotelName": "Old Century Hotel",
            "Description": "The hotel is situated in a nineteenth century plaza, which has been expanded and renovated to the highest architectural standards to create a modern, functional and first-class hotel in which art and unique historical elements coexist with the most modern comforts. The hotel also regularly hosts events like wine tastings, beer dinners, and live music.",
             "Category": "Boutique",
            "Tags": [ "pool", "free wifi", "concierge" ],
            "ParkingIncluded": false,
            "LastRenovationDate": "2019-02-18T00:00:00Z",
            "Rating": 3.60,
            "Address": 
                {
                "StreetAddress": "140 University Town Center Dr",
                "City": "Sarasota",
                "StateProvince": "FL",
                "PostalCode": "34243",
                "Country": "USA"
                } 
            },
            {
            "@search.action": "upload",
            "HotelId": "3",
            "HotelName": "Gastronomic Landscape Hotel",
            "Description": "The Gastronomic Hotel stands out for its culinary excellence under the management of William Dough, who advises on and oversees all of the Hotel's restaurant services.",
            "Category": "Suite",
            "Tags": [ "restaurant", "bar", "continental breakfast" ],
            "ParkingIncluded": true,
            "LastRenovationDate": "2015-09-20T00:00:00Z",
            "Rating": 4.80,
            "Address": 
                {
                "StreetAddress": "3393 Peachtree Rd",
                "City": "Atlanta",
                "StateProvince": "GA",
                "PostalCode": "30326",
                "Country": "USA"
                } 
            },
            {
            "@search.action": "upload",
            "HotelId": "4",
            "HotelName": "Sublime Palace Hotel",
            "Description": "Sublime Palace Hotel is located in the heart of the historic center of Sublime in an extremely vibrant and lively area within short walking distance to the sites and landmarks of the city and is surrounded by the extraordinary beauty of churches, buildings, shops and monuments. Sublime Cliff is part of a lovingly restored 19th century resort, updated for every modern convenience.",
            "Category": "Luxury",
            "Tags": [ "concierge", "view", "air conditioning" ],
            "ParkingIncluded": true,
            "LastRenovationDate": "2020-02-06T00:00:00Z",
            "Rating": 4.60,
            "Address": 
                {
                "StreetAddress": "7400 San Pedro Ave",
                "City": "San Antonio",
                "StateProvince": "TX",
                "PostalCode": "78216",
                "Country": "USA"
                }
            }
          ]
        }
    
  2. Sous ### Upload documents, sélectionnez Envoyer une demande.

    Vous devez recevoir une HTTP/1.1 200 OK réponse dont le corps contient la clé et l’état de chaque document chargé.

À propos de la demande de chargement

Ce guide de démarrage rapide appelle Documents - Index (API REST) pour ajouter quatre exemples de documents d’hôtel à votre index. Par rapport à la requête précédente, l’URI est étendu pour inclure la docs collection et l’opération index.

Chaque document du value tableau représente un hôtel et contient des champs qui correspondent au schéma d’index. Le @search.action paramètre spécifie l’opération à effectuer pour chaque document. Notre exemple utilise upload, qui ajoute le document s’il n’existe pas ou met à jour le document s’il existe.

Interrogation de l'index

Maintenant que les documents sont chargés dans votre index, vous pouvez utiliser la recherche en texte intégral pour rechercher des termes ou expressions spécifiques dans leurs champs.

Pour exécuter une requête de texte intégral sur votre index :

  1. Collez la requête suivante dans votre fichier.

    ### Run a query
    POST {{baseUrl}}/indexes/hotels-quickstart/docs/search?api-version=2025-09-01  HTTP/1.1
      Content-Type: application/json
      Authorization: Bearer {{token}}
    
      {
          "search": "attached restaurant",
          "select": "HotelId, HotelName, Tags, Description",
          "searchFields": "Description, Tags",
          "count": true
      }
    
  2. Sous ### Run a query, sélectionnez Envoyer une demande.

    Vous allez recevoir une HTTP/1.1 200 OK réponse similaire à l’exemple suivant, qui montre un document d'hôtel correspondant, son score de pertinence et ses champs sélectionnés.

    {
      "@odata.context": "https://my-service.search.windows.net/indexes('hotels-quickstart')/$metadata#docs(*)",
      "@odata.count": 1,
      "value": [
        {
          "@search.score": 0.5575875,
          "HotelId": "3",
          "HotelName": "Gastronomic Landscape Hotel",
          "Description": "The Gastronomic Hotel stands out for its culinary excellence under the management of William Dough, who advises on and oversees all of the Hotel\u2019s restaurant services.",
          "Tags": [
            "restaurant",
            "bar",
            "continental breakfast"
          ]
        }
      ]
    }
    

À propos de la requête

Ce guide de démarrage rapide appelle Documents – de publication (API REST) pour rechercher des documents d’hôtel qui correspondent à vos critères de recherche. L’URI cible désormais l’opération /docs/search .

Les demandes de recherche en texte intégral incluent toujours un search paramètre qui contient le texte de la requête. Le texte de la requête peut inclure un ou plusieurs termes, expressions ou opérateurs. En plus de search, vous pouvez spécifier d’autres paramètres pour affiner le comportement et les résultats de la recherche.

Notre requête recherche les termes « restaurant attenant » dans les champs Description et Tags de chaque document d’hôtel. Le select paramètre limite les champs retournés dans la réponse à HotelId, HotelName, Tagset Description. Le count paramètre demande le nombre total de documents correspondants.

Dans ce guide de démarrage rapide, vous utilisez la bibliothèque cliente Azure.Search.Documents pour créer, charger et interroger un index de recherche avec des exemples de données pour la recherche en texte intégral. La recherche en texte intégral utilise Apache Lucene pour l’indexation et les requêtes et l’algorithme de classement BM25 pour les résultats de scoring.

Ce guide de démarrage rapide utilise les données d’hôtel fictives du référentiel azure-search-sample-data pour remplir l’index.

Conseil

Vous pouvez télécharger le code source pour commencer par un projet terminé ou suivre ces étapes pour créer votre propre code.

Prérequis

Prérequis pour Microsoft Entra ID

Pour l’authentification sans clé recommandée avec l’ID Microsoft Entra, vous devez :

  • Installez Azure CLI.

  • Affectez les rôles Search Service Contributor et Search Index Data Contributor à votre compte d'utilisateur. Vous pouvez attribuer des rôles dans le Portail Azure sous Contrôle d’accès (IAM)>Ajouter une attribution de rôle. Pour plus d’informations, consultez Se connecter à la Recherche Azure AI à l’aide des rôles.

Obtenir des informations sur le service

Vous devez récupérer les informations suivantes pour authentifier votre application auprès de votre ressource Recherche Azure AI :

Nom de la variable Valeur
SEARCH_API_ENDPOINT Cette valeur se trouve dans le portail Azure. Sélectionnez votre service de recherche, puis dans le menu de gauche, sélectionnez Vue d’ensemble. La valeur d’URL sous Essentials est le point de terminaison dont vous avez besoin. Voici un exemple de point de terminaison : https://mydemo.search.windows.net.

En savoir plus sur l’authentification sans clé et la définition de variables d’environnement.

Configurer

  1. Créez un dossier full-text-quickstart pour contenir l’application et ouvrez Visual Studio Code dans ce dossier avec la commande suivante :

    mkdir full-text-quickstart && cd full-text-quickstart
    
  2. Créez le package.json avec la commande suivante :

    npm init -y
    
  3. Mettez à jour le package.json vers ECMAScript avec la commande suivante :

    npm pkg set type=module
    
  4. Installez la bibliothèque de client Recherche Azure AI (Azure.Search.Documents) pour JavaScript avec :

    npm install @azure/search-documents
    
  5. Pour l’authentification sans mot de passe recommandée, installez la bibliothèque de client Azure Identity avec :

    npm install @azure/identity
    

Créer, charger et interroger un index de recherche

Dans la section de configuration précédente, vous avez installé la bibliothèque de client Recherche Azure AI et d’autres dépendances.

Dans cette section, vous ajoutez du code pour créer un index de recherche, chargez-le avec des documents et exécutez des requêtes. Vous exécutez le programme pour afficher les résultats dans la console. Pour obtenir une explication détaillée du code, consultez la section Explication du code .

L’exemple de code de ce guide de démarrage rapide utilise Microsoft Entra pour l’authentification sans clé recommandée. Si vous préférez utiliser une clé API, vous pouvez remplacer l’objet DefaultAzureCredential par un objet AzureKeyCredential.

const searchServiceEndpoint = "https://<Put your search service NAME here>.search.windows.net/";
const credential = new DefaultAzureCredential();
  1. Créez un fichier nommé index.ts et collez le code suivant dans index.ts :

    // Import from the @azure/search-documents library
    import {
        SearchIndexClient,
        SearchClient,
        SearchFieldDataType,
        AzureKeyCredential,
        odata,
        SearchIndex
    } from "@azure/search-documents";
    
    // Import from the Azure Identity library
    import { DefaultAzureCredential } from "@azure/identity";
    
    // Importing the hotels sample data
    import hotelData from './hotels.json' assert { type: "json" };
    
    // Load the .env file if it exists
    import * as dotenv from "dotenv";
    dotenv.config();
    
    // Defining the index definition
    const indexDefinition: SearchIndex = {
    	"name": "hotels-quickstart",
    	"fields": [
    		{
    			"name": "HotelId",
    			"type": "Edm.String" as SearchFieldDataType,
    			"key": true,
    			"filterable": true
    		},
    		{
    			"name": "HotelName",
    			"type": "Edm.String" as SearchFieldDataType,
    			"searchable": true,
    			"filterable": false,
    			"sortable": true,
    			"facetable": false
    		},
    		{
    			"name": "Description",
    			"type": "Edm.String" as SearchFieldDataType,
    			"searchable": true,
    			"filterable": false,
    			"sortable": false,
    			"facetable": false,
    			"analyzerName": "en.lucene"
    		},
    		{
    			"name": "Category",
    			"type": "Edm.String" as SearchFieldDataType,
    			"searchable": true,
    			"filterable": true,
    			"sortable": true,
    			"facetable": true
    		},
    		{
    			"name": "Tags",
    			"type": "Collection(Edm.String)",
    			"searchable": true,
    			"filterable": true,
    			"sortable": false,
    			"facetable": true
    		},
    		{
    			"name": "ParkingIncluded",
    			"type": "Edm.Boolean",
    			"filterable": true,
    			"sortable": true,
    			"facetable": true
    		},
    		{
    			"name": "LastRenovationDate",
    			"type": "Edm.DateTimeOffset",
    			"filterable": true,
    			"sortable": true,
    			"facetable": true
    		},
    		{
    			"name": "Rating",
    			"type": "Edm.Double",
    			"filterable": true,
    			"sortable": true,
    			"facetable": true
    		},
    		{
    			"name": "Address",
    			"type": "Edm.ComplexType",
    			"fields": [
    				{
    					"name": "StreetAddress",
    					"type": "Edm.String" as SearchFieldDataType,
    					"filterable": false,
    					"sortable": false,
    					"facetable": false,
    					"searchable": true
    				},
    				{
    					"name": "City",
    					"type": "Edm.String" as SearchFieldDataType,
    					"searchable": true,
    					"filterable": true,
    					"sortable": true,
    					"facetable": true
    				},
    				{
    					"name": "StateProvince",
    					"type": "Edm.String" as SearchFieldDataType,
    					"searchable": true,
    					"filterable": true,
    					"sortable": true,
    					"facetable": true
    				},
    				{
    					"name": "PostalCode",
    					"type": "Edm.String" as SearchFieldDataType,
    					"searchable": true,
    					"filterable": true,
    					"sortable": true,
    					"facetable": true
    				},
    				{
    					"name": "Country",
    					"type": "Edm.String" as SearchFieldDataType,
    					"searchable": true,
    					"filterable": true,
    					"sortable": true,
    					"facetable": true
    				}
    			]
    		}
    	],
    	"suggesters": [
    		{
    			"name": "sg",
    			"searchMode": "analyzingInfixMatching",
    			"sourceFields": [
    				"HotelName"
    			]
    		}
    	]
    };
    
    async function main() {
    
    	// Your search service endpoint
    	const searchServiceEndpoint = "https://<Put your search service NAME here>.search.windows.net/";
    
    	// Use the recommended keyless credential instead of the AzureKeyCredential credential.
    	const credential = new DefaultAzureCredential();
    	//const credential = new AzureKeyCredential(Your search service admin key);
    
    	// Create a SearchIndexClient to send create/delete index commands
    	const searchIndexClient: SearchIndexClient = new SearchIndexClient(
    		searchServiceEndpoint,
    		credential
    	);
    
    	// Creating a search client to upload documents and issue queries
    	const indexName: string  = "hotels-quickstart";
        const searchClient: SearchClient<any> = searchIndexClient.getSearchClient(indexName);
    
        console.log('Checking if index exists...');
        await deleteIndexIfExists(searchIndexClient, indexName);
    
        console.log('Creating index...');
        let index: SearchIndex = await searchIndexClient.createIndex(indexDefinition);
        console.log(`Index named ${index.name} has been created.`);
    
        console.log('Uploading documents...');
        let indexDocumentsResult = await searchClient.mergeOrUploadDocuments(hotelData['value']);
        console.log(`Index operations succeeded: ${JSON.stringify(indexDocumentsResult.results[0].succeeded)} `);
    
        // waiting one second for indexing to complete (for demo purposes only)
        sleep(1000);
    
        console.log('Querying the index...');
        console.log();
        await sendQueries(searchClient);
    }
    
    async function deleteIndexIfExists(searchIndexClient: SearchIndexClient, indexName: string) {
        try {
            await searchIndexClient.deleteIndex(indexName);
            console.log('Deleting index...');
        } catch {
            console.log('Index does not exist yet.');
        }
    }
    
    async function sendQueries(searchClient: SearchClient<any>) {
        // Query 1
        console.log('Query #1 - search everything:');
        let searchOptions: any = {
            includeTotalCount: true,
            select: ["HotelId", "HotelName", "Rating"]
        };
    
        let searchResults = await searchClient.search("*", searchOptions);
        for await (const result of searchResults.results) {
            console.log(`${JSON.stringify(result.document)}`);
        }
        console.log(`Result count: ${searchResults.count}`);
        console.log();
    
    
        // Query 2
        console.log('Query #2 - search with filter, orderBy, and select:');
        let state = 'FL';
        searchOptions = {
            filter: odata`Address/StateProvince eq ${state}`,
            orderBy: ["Rating desc"],
            select: ["HotelId", "HotelName", "Rating"]
        };
    
        searchResults = await searchClient.search("wifi", searchOptions);
        for await (const result of searchResults.results) {
            console.log(`${JSON.stringify(result.document)}`);
        }
        console.log();
    
        // Query 3
        console.log('Query #3 - limit searchFields:');
        searchOptions = {
            select: ["HotelId", "HotelName", "Rating"],
            searchFields: ["HotelName"]
        };
    
        searchResults = await searchClient.search("sublime palace", searchOptions);
        for await (const result of searchResults.results) {
            console.log(`${JSON.stringify(result.document)}`);
        }
        console.log();
    
        // Query 4
        console.log('Query #4 - limit searchFields and use facets:');
        searchOptions = {
            facets: ["Category"],
            select: ["HotelId", "HotelName", "Rating"],
            searchFields: ["HotelName"]
        };
    
        searchResults = await searchClient.search("*", searchOptions);
        for await (const result of searchResults.results) {
            console.log(`${JSON.stringify(result.document)}`);
        }
        console.log();
    
        // Query 5
        console.log('Query #5 - Lookup document:');
        let documentResult = await searchClient.getDocument('3');
        console.log(`HotelId: ${documentResult.HotelId}; HotelName: ${documentResult.HotelName}`);
        console.log();
    }
    
    function sleep(ms: number) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
    
    main().catch((err) => {
        console.error("The sample encountered an error:", err);
    });
    
  2. Créez un fichier nommé hotels.json et collez le code suivant dans hotels.json :

    {
        "value": [
            {
                "HotelId": "1",
                "HotelName": "Stay-Kay City Hotel",
                "Description": "This classic hotel is fully-refurbished and ideally located on the main commercial artery of the city in the heart of New York. A few minutes away is Times Square and the historic centre of the city, as well as other places of interest that make New York one of America's most attractive and cosmopolitan cities.",
                "Category": "Boutique",
                "Tags": ["view", "air conditioning", "concierge"],
                "ParkingIncluded": false,
                "LastRenovationDate": "2022-01-18T00:00:00Z",
                "Rating": 3.6,
                "Address": {
                    "StreetAddress": "677 5th Ave",
                    "City": "New York",
                    "StateProvince": "NY",
                    "PostalCode": "10022"
                }
            },
            {
                "HotelId": "2",
                "HotelName": "Old Century Hotel",
                "Description": "The hotel is situated in a nineteenth century plaza, which has been expanded and renovated to the highest architectural standards to create a modern, functional and first-class hotel in which art and unique historical elements coexist with the most modern comforts. The hotel also regularly hosts events like wine tastings, beer dinners, and live music.",
                "Category": "Boutique",
                "Tags": ["pool", "free wifi", "concierge"],
                "ParkingIncluded": "false",
                "LastRenovationDate": "2019-02-18T00:00:00Z",
                "Rating": 3.6,
                "Address": {
                    "StreetAddress": "140 University Town Center Dr",
                    "City": "Sarasota",
                    "StateProvince": "FL",
                    "PostalCode": "34243"
                }
            },
            {
                "HotelId": "3",
                "HotelName": "Gastronomic Landscape Hotel",
                "Description": "The Gastronomic Hotel stands out for its culinary excellence under the management of William Dough, who advises on and oversees all of the Hotel’s restaurant services.",
                "Category": "Suite",
                "Tags": ["restaurant, "bar", "continental breakfast"],
                "ParkingIncluded": "true",
                "LastRenovationDate": "2015-09-20T00:00:00Z",
                "Rating": 4.8,
                "Address": {
                    "StreetAddress": "3393 Peachtree Rd",
                    "City": "Atlanta",
                    "StateProvince": "GA",
                    "PostalCode": "30326"
                }
            },
            {
                "HotelId": "4",
                "HotelName": "Sublime Palace Hotel",
                "Description": "Sublime Palace Hotel is located in the heart of the historic center of Sublime in an extremely vibrant and lively area within short walking distance to the sites and landmarks of the city and is surrounded by the extraordinary beauty of churches, buildings, shops and monuments. Sublime Cliff is part of a lovingly restored 19th century resort, updated for every modern convenience.",
                "Category": "Boutique",
                "Tags": ["concierge", "view", "air conditioning"],
                "ParkingIncluded": true,
                "LastRenovationDate": "2020-02-06T00:00:00Z",
                "Rating": 4.6,
                "Address": {
                    "StreetAddress": "7400 San Pedro Ave",
                    "City": "San Antonio",
                    "StateProvince": "TX",
                    "PostalCode": "78216"
                }
            }
        ]
    }
    
  3. Créez le fichier tsconfig.json pour transpiler le code TypeScript et copiez le code suivant pour ECMAScript.

    {
        "compilerOptions": {
          "module": "NodeNext",
          "target": "ES2022", // Supports top-level await
          "moduleResolution": "NodeNext",
          "skipLibCheck": true, // Avoid type errors from node_modules
          "strict": true // Enable strict type-checking options
        },
        "include": ["*.ts"]
    }
    
  4. Transpiler de TypeScript à JavaScript.

    tsc
    
  5. Connectez-vous à Azure à l’aide de la commande suivante :

    az login
    
  6. Exécutez le code JavaScript avec la commande suivante :

    node index.js
    

Explication du code

Créer un index

Créez un fichier hotels_quickstart_index.json. Ce fichier définit le fonctionnement de la Recherche Azure AI avec les documents que vous allez charger à l’étape suivante. Chaque champ est identifié par un name et a un type spécifié. Chaque champ comporte également une série d’attributs d’index qui spécifient si la recherche Azure AI peut effectuer des recherches, filtrer, trier et définir des propriétés de facettes sur le champ. La plupart des champs sont des types de données simples, mais certains, comme AddressType, sont des types complexes qui vous permettent de créer des structures de données riches dans votre index. Vous pouvez en savoir plus sur les types de données pris en charge et les attributs d’index décrits dans Créer un index (REST).

Nous voulons importer hotels_quickstart_index.json afin que la fonction principale puisse accéder à la définition d’index.

import indexDefinition from './hotels_quickstart_index.json';

interface HotelIndexDefinition {
    name: string;
    fields: SimpleField[] | ComplexField[];
    suggesters: SearchSuggester[];
};
const hotelIndexDefinition: HotelIndexDefinition = indexDefinition as HotelIndexDefinition;

Dans la fonction principale, nous créons ensuite un SearchIndexClient, qui est utilisé pour créer et gérer des index pour la recherche Azure AI.

const indexClient = new SearchIndexClient(endpoint, new AzureKeyCredential(apiKey));

Ensuite, nous voulons supprimer l’index s’il existe déjà. Il s’agit d’une opération courante pour le code de test/démonstration.

Pour ce faire, nous définissons une fonction simple qui tente de supprimer l’index.

async function deleteIndexIfExists(indexClient: SearchIndexClient, indexName: string): Promise<void> {
    try {
        await indexClient.deleteIndex(indexName);
        console.log('Deleting index...');
    } catch {
        console.log('Index does not exist yet.');
    }
}

Pour exécuter la fonction, nous extrayons le nom de l’index de la définition de l’index et nous passons indexName avec indexClient à la fonction deleteIndexIfExists().

// Getting the name of the index from the index definition
const indexName: string = hotelIndexDefinition.name;

console.log('Checking if index exists...');
await deleteIndexIfExists(indexClient, indexName);

Après cela, nous sommes prêts à créer l’index avec la méthode createIndex().

console.log('Creating index...');
let index = await indexClient.createIndex(hotelIndexDefinition);

console.log(`Index named ${index.name} has been created.`);

Chargement de documents

Dans la recherche Azure AI, les documents sont des structures de données qui sont à la fois des entrées pour l’indexation et des sorties de requêtes. Vous pouvez envoyer des données de ce type dans l’index ou utiliser un indexeur. Dans ce cas, nous allons envoyer par programmation les documents à l’index.

Les entrées de documents peuvent être des lignes dans une base de données, des objets blob dans le Stockage Blob ou, comme dans cet exemple, des documents JSON sur le disque. Vous pouvez télécharger hotels.json ou créer votre propre fichier hotels.json avec le contenu suivant :

À l’instar de ce que nous avons fait avec indexDefinition, nous devons aussi importer hotels.json au-dessus de index.ts pour que les données soient accessibles dans notre fonction main.

import hotelData from './hotels.json';

interface Hotel {
    HotelId: string;
    HotelName: string;
    Description: string;
    Category: string;
    Tags: string[];
    ParkingIncluded: string | boolean;
    LastRenovationDate: string;
    Rating: number;
    Address: {
        StreetAddress: string;
        City: string;
        StateProvince: string;
        PostalCode: string;
    };
};

const hotels: Hotel[] = hotelData["value"];

Pour indexer les données dans l’index de recherche, nous devons maintenant créer un SearchClient. Alors que le SearchIndexClient est utilisé pour créer et gérer un index, le SearchClient est utilisé pour charger des documents et interroger l’index.

Il existe deux façons de créer un SearchClient. La première option consiste à créer un SearchClient à partir de zéro :

 const searchClient = new SearchClient<Hotel>(endpoint, indexName, new AzureKeyCredential(apiKey));

Vous pouvez également utiliser la méthode getSearchClient() du SearchIndexClient pour créer le SearchClient :

const searchClient = indexClient.getSearchClient<Hotel>(indexName);

Maintenant que le client est défini, chargez les documents dans l’index de recherche. Dans le cas présent, nous utilisons la méthode mergeOrUploadDocuments(), qui charge les documents ou les fusionne avec un document existant si un document ayant la même clé existe déjà. Vérifiez ensuite que l’opération a réussi, car au moins le premier document existe.

console.log("Uploading documents...");
const indexDocumentsResult = await searchClient.mergeOrUploadDocuments(hotels);

console.log(`Index operations succeeded: ${JSON.stringify(indexDocumentsResult.results[0].succeeded)}`);

Exécutez à nouveau le programme avec tsc && node index.ts. Vous devriez voir un ensemble de messages légèrement différents de ceux que vous avez vus à l’étape 1. Cette fois, l’index existe et vous voyez normalement un message à propos de sa suppression avant que l’application ne crée l’index et n’y envoie des données.

Avant d’exécuter les requêtes à l’étape suivante, définissez une fonction pour que le programme attende une seconde. Faites-le seulement à des fins de test ou de démonstration pour garantir que l’indexation se termine et que les documents sont disponibles dans l’index pour nos requêtes.

function sleep(ms: number): Promise<void> {
    return new Promise((resolve) => setTimeout(resolve, ms));
}

Pour que le programme attende une seconde, appelez la fonction sleep :

sleep(1000);

Rechercher dans un index

Avec un index créé et des documents chargés, vous êtes prêt à envoyer des requêtes à l’index. Dans cette section, nous envoyons cinq requêtes différentes à l’index de recherche pour illustrer différentes fonctionnalités de requête à votre disposition.

Les requêtes sont écrites dans une fonction sendQueries() que nous appelons dans la fonction main comme suit :

await sendQueries(searchClient);

Les requêtes sont envoyées en utilisant la méthode search() de searchClient. Le premier paramètre est le texte recherché et le deuxième paramètre spécifie les options de recherche.

Exemple de requête 1

La première requête recherche *, ce qui équivaut à effectuer une recherche dans tout, et sélectionne trois des champs de l’index. C’est une bonne pratique que d’appliquer un select seulement aux champs dont vous avez besoin, car l’extraction de données inutiles peut ajouter de la latence à vos requêtes.

Les searchOptions de cette requête ont également includeTotalCount défini sur true, ce qui retourne le nombre de résultats correspondants trouvés.

async function sendQueries(
    searchClient: SearchClient<Hotel>
): Promise<void> {

    // Query 1
    console.log('Query #1 - search everything:');
    const selectFields: SearchFieldArray<Hotel> = [
        "HotelId",
        "HotelName",
        "Rating",
    ];
    const searchOptions1 = { 
        includeTotalCount: true, 
        select: selectFields 
    };

    let searchResults = await searchClient.search("*", searchOptions1);
    for await (const result of searchResults.results) {
        console.log(`${JSON.stringify(result.document)}`);
    }
    console.log(`Result count: ${searchResults.count}`);

    // remaining queries go here
}

Les requêtes restantes décrites ci-dessous doivent également être ajoutées à la fonction sendQueries(). Elles sont séparées ici seulement pour des raisons de lisibilité.

Exemple de requête 2

Dans la requête suivante, nous spécifions le terme de recherche "wifi" et nous incluons aussi un filtre pour retourner seulement les résultats où l’état est égal à 'FL'. Les résultats sont également classés selon la valeur du champ Rating de l’hôtel.

console.log('Query #2 - search with filter, orderBy, and select:');
let state = 'FL';
const searchOptions2 = {
    filter: odata`Address/StateProvince eq ${state}`,
    orderBy: ["Rating desc"],
    select: selectFields
};
searchResults = await searchClient.search("wifi", searchOptions2);
for await (const result of searchResults.results) {
    console.log(`${JSON.stringify(result.document)}`);
}

Exemple de requête 3

Ensuite, la recherche est limitée à un seul champ pouvant faire l’objet d’une recherche en utilisant le paramètre searchFields. Cette approche constitue une option intéressante pour améliorer l’efficacité de votre requête si vous savez que vous êtes intéressé seulement par les correspondances dans certains champs.

console.log('Query #3 - limit searchFields:');
const searchOptions3 = {
    select: selectFields,
    searchFields: ["HotelName"] as const
};

searchResults = await searchClient.search("Sublime Palace", searchOptions3);
for await (const result of searchResults.results) {
    console.log(`${JSON.stringify(result.document)}`);
}

Exemple de requête 4

Une autre option courante à inclure dans une requête est facets. Les facettes vous permettent de fournir une exploration auto-dirigée à partir des résultats dans votre interface utilisateur. Les résultats des facettes peuvent être transformés en cases à cocher dans le volet de résultats.

console.log('Query #4 - limit searchFields and use facets:');
const searchOptions4 = {
    facets: ["Category"],
    select: selectFields,
    searchFields: ["HotelName"] as const
};

searchResults = await searchClient.search("*", searchOptions4);
for await (const result of searchResults.results) {
    console.log(`${JSON.stringify(result.document)}`);
}

Exemple de requête 5

La dernière requête utilise la méthode getDocument() du searchClient. Ceci vous permet de récupérer efficacement un document en utilisant sa clé.

console.log('Query #5 - Lookup document:');
let documentResult = await searchClient.getDocument('3')
console.log(`HotelId: ${documentResult.HotelId}; HotelName: ${documentResult.HotelName}`)

Résumé des requêtes

Les requêtes précédentes illustrent plusieurs manières d’établir des correspondances entre des termes dans une requête : recherche en texte intégral, filtres et autocomplétion.

La recherche en texte intégral et les filtres sont exécutés en utilisant la méthode searchClient.search. Une requête de recherche peut être transmise dans la chaîne searchText, tandis qu’une expression de filtre peut être transmise dans la propriété filter de la classe SearchOptions. Pour filtrer sans effectuer de recherche, transmettez simplement « * » pour le paramètre searchText de la méthode search. Pour effectuer une recherche sans filtrage, ne définissez pas la propriété filter et ne transmettez aucune instance SearchOptions.

Nettoyer les ressources

Lorsque vous travaillez dans votre propre abonnement, il est judicieux de terminer un projet en déterminant si vous avez toujours besoin des ressources que vous avez créées. Les ressources laissées actives peuvent vous coûter de l'argent. Vous pouvez supprimer des ressources individuellement ou supprimer le groupe de ressources pour supprimer l’ensemble des ressources.

Dans le portail Azure, vous pouvez rechercher et gérer des ressources en sélectionnant Toutes les ressources ou groupes de ressources dans le volet gauche.

Si vous utilisez un service gratuit, n'oubliez pas que vous êtes limité à trois index, indexeurs et sources de données. Vous pouvez supprimer des éléments un par un sur le portail Azure pour ne pas dépasser la limite.