Sdílet prostřednictvím


Rychlý start: Fulltextové vyhledávání pomocí sad SDK Azure

Naučte se používat klientskou knihovnu Azure.Search.Documents k vytvoření, načtení a dotazování indexu vyhledávání pomocí ukázkových dat pro fulltextové vyhledávání. Fulltextové vyhledávání používá Apache Lucene k indexování a dotazům a algoritmus hodnocení BM25 pro vyhodnocování výsledků.

V tomto rychlém startu se vytvoří a dotazuje malý index rychlého startu obsahující data o čtyřech hotelech.

Tip

Zdrojový kód si můžete stáhnout, abyste mohli začít s hotovým projektem, nebo si podle těchto kroků vytvořte vlastní.

Požadavky

Požadavky pro Microsoft Entra ID

Pro doporučené ověřování bez klíčů s ID Microsoft Entra musíte:

  • Nainstalujte Azure CLI, které se používá pro ověřování bez klíčů pomocí ID Microsoft Entra.
  • Přiřaďte uživatelskému Search Service Contributor účtu obě role i Search Index Data Contributor role. Role můžete přiřadit na webu Azure Portal v části Řízení přístupu (IAM)>Přidat přiřazení role. Další informace najdete v tématu Připojení k Azure AI Search pomocí rolí.

Načtení informací o prostředcích

Abyste mohli aplikaci ověřit pomocí Search Azure AI, musíte načíst následující informace:

Název proměnné Hodnota
SEARCH_API_ENDPOINT Tuto hodnotu najdete na webu Azure Portal. Vyberte vyhledávací službu a pak v nabídce vlevo vyberte Přehled. Hodnota url v části Essentials je koncový bod, který potřebujete. Příkladem koncového bodu může být https://mydemo.search.windows.net.

Přečtěte si další informace o ověřování bez klíčů a nastavení proměnných prostředí.

Nastavení

  1. Vytvořte novou složku full-text-quickstart , která bude obsahovat aplikaci, a otevřete v této složce Visual Studio Code pomocí následujícího příkazu:

    mkdir full-text-quickstart && cd full-text-quickstart
    
  2. Vytvořte novou konzolovou aplikaci pomocí následujícího příkazu:

    dotnet new console
    
  3. Nainstalujte klientskou knihovnu Azure AI Search (Azure.Search.Documents) pro .NET pomocí:

    dotnet add package Azure.Search.Documents
    
  4. Pro doporučené ověřování bez klíčů s ID Microsoft Entra nainstalujte balíček Azure.Identity pomocí:

    dotnet add package Azure.Identity
    
  5. Pro doporučené ověřování bez klíčů pomocí ID Microsoft Entra se přihlaste k Azure pomocí následujícího příkazu:

    az login
    

Vytvoření, načtení a dotazování indexu vyhledávání

V předchozí části nastavení jste vytvořili novou konzolovou aplikaci a nainstalovali klientskou knihovnu Azure AI Search.

V této části přidáte kód pro vytvoření indexu vyhledávání, načtení s dokumenty a spouštění dotazů. Spuštěním programu zobrazíte výsledky v konzole. Podrobné vysvětlení kódu najdete v části s vysvětlením kódu .

Ukázkový kód v tomto rychlém startu používá PRO doporučené ověřování bez klíčů ID Microsoft Entra. Pokud dáváte přednost použití klíče rozhraní API, můžete objekt nahradit DefaultAzureCredential objektem AzureKeyCredential .

Uri serviceEndpoint = new Uri($"https://<Put your search service NAME here>.search.windows.net/");
DefaultAzureCredential credential = new();
  1. Do Program.cs vložte následující kód. serviceName Upravte proměnné apiKey pomocí názvu vyhledávací služby a klíče rozhraní API správce.

    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 = "Secret Point Motel",
                            Description = "The hotel is ideally located on the main commercial artery of the city in the heart of New York. A few minutes away is Time's 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.",
                            DescriptionFr = "L'hôtel est idéalement situé sur la principale artère commerciale de la ville en plein cœur de New York. A quelques minutes se trouve la place du temps et le centre historique de la ville, ainsi que d'autres lieux d'intérêt qui font de New York l'une des villes les plus attractives et cosmopolites de l'Amérique.",
                            Category = "Boutique",
                            Tags = new[] { "pool", "air conditioning", "concierge" },
                            ParkingIncluded = false,
                            LastRenovationDate = new DateTimeOffset(1970, 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 = "Twin Dome Motel",
                            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.",
                            DescriptionFr = "L'hôtel est situé dans une place du XIXe siècle, qui a été agrandie et rénovée aux plus hautes normes architecturales pour créer un hôtel moderne, fonctionnel et de première classe dans lequel l'art et les éléments historiques uniques coexistent avec le confort le plus moderne.",
                            Category = "Boutique",
                            Tags = new[] { "pool", "free wifi", "concierge" },
                            ParkingIncluded = false,
                            LastRenovationDate = new DateTimeOffset(1979, 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 = "Triple Landscape Hotel",
                            Description = "The Hotel stands out for its gastronomic excellence under the management of William Dough, who advises on and oversees all of the Hotel’s restaurant services.",
                            DescriptionFr = "L'hôtel est situé dans une place du XIXe siècle, qui a été agrandie et rénovée aux plus hautes normes architecturales pour créer un hôtel moderne, fonctionnel et de première classe dans lequel l'art et les éléments historiques uniques coexistent avec le confort le plus moderne.",
                            Category = "Resort and Spa",
                            Tags = new[] { "air conditioning", "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 Cliff Hotel",
                            Description = "Sublime Cliff 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 1800 palace.",
                            DescriptionFr = "Le sublime Cliff Hotel est situé au coeur du centre historique de sublime dans un quartier extrêmement animé et vivant, à courte distance de marche des sites et monuments de la ville et est entouré par l'extraordinaire beauté des églises, des bâtiments, des commerces et Monuments. Sublime Cliff fait partie d'un Palace 1800 restauré avec amour.",
                            Category = "Boutique",
                            Tags = new[] { "concierge", "view", "24-hour front desk service" },
                            ParkingIncluded = true,
                            LastRenovationDate = new DateTimeOffset(1960, 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. Ve stejné složce vytvořte nový soubor s názvem Hotel.cs a vložte následující kód. Tento kód definuje strukturu hotelového dokumentu.

    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(AnalyzerName = LexicalAnalyzerName.Values.FrLucene)]
            [JsonPropertyName("Description_fr")]
            public string DescriptionFr { 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. Vytvořte nový soubor s názvem Hotel.cs a vložte následující kód, který definuje strukturu hotelového dokumentu. Atributy v poli určují, jak se používá v aplikaci. Atribut musí být například IsFilterable přiřazen ke každému poli, které podporuje výraz filtru.

    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(AnalyzerName = LexicalAnalyzerName.Values.FrLucene)]
            [JsonPropertyName("Description_fr")]
            public string DescriptionFr { 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. Vytvořte nový soubor s názvem Address.cs a vložte následující kód, který definuje strukturu dokumentu adresy.

    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. Vytvořte nový soubor s názvem Hotel.Methods.cs a vložte následující kód, který definuje přepsání ToString() pro Hotel třídu.

    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(DescriptionFr))
                {
                    builder.AppendFormat("Description (French): {0}\n", DescriptionFr);
                }
    
                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. Vytvořte nový soubor s názvem Address.Methods.cs a vložte následující kód, který definuje přepsání ToString() pro Address třídu.

    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. Sestavte a spusťte aplikaci pomocí následujícího příkazu:

    dotnet run
    

Výstup obsahuje zprávy z Console.WriteLine s přidáním informací o dotazu a výsledků.

Vysvětlení kódu

V předchozích částech jste vytvořili novou konzolovou aplikaci a nainstalovali klientskou knihovnu Azure AI Search. Přidali jste kód pro vytvoření indexu vyhledávání, načtení s dokumenty a spouštění dotazů. Spustili jste program, abyste zobrazili výsledky v konzole.

V této části vysvětlujeme kód, který jste přidali do konzolové aplikace.

Vytvoření vyhledávacího klienta

V Program.cs jste vytvořili dva klienty:

Oba klienti potřebují koncový bod vyhledávací služby a přihlašovací údaje popsané výše v části s informacemi o prostředcích.

Ukázkový kód v tomto rychlém startu používá PRO doporučené ověřování bez klíčů ID Microsoft Entra. Pokud dáváte přednost použití klíče rozhraní API, můžete objekt nahradit DefaultAzureCredential objektem 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 . . . 
}

Vytvoření indexu

V tomto rychlém startu vytvoříte index hotelů, na který načtete data hotelů, a spustíte dotazy. V tomto kroku definujete pole v indexu. Každá definice pole obsahuje název, datový typ a atributy, které určují způsob použití pole.

V tomto příkladu se pro jednoduchost a čitelnost používají synchronní metody knihovny Azure.Search.Documents . V produkčních scénářích byste ale měli použít asynchronní metody, které umožňují udržovat aplikaci škálovatelnou a responzivní. Místo CreateIndex byste například použili CreateIndexAsync.

Definování struktur

Vytvořili jste dvě pomocné třídy, Hotel.cs a Address.cs, abyste definovali strukturu hotelového dokumentu a jeho adresy. Třída Hotel obsahuje pole pro ID hotelu, název, popis, kategorii, značky, parkování, datum renovace, hodnocení a adresu. Třída Address obsahuje pole pro adresu ulice, město, stát/kraj, PSČ a zemi/oblast.

V klientské knihovně Azure.Search.Documents můžete k zjednodušení definic polí použít SearchableField a SimpleField . Oba jsou deriváty vyhledávacího pole a můžou potenciálně zjednodušit váš kód:

  • SimpleField může být libovolný datový typ, je vždy nehledatelný (ignorován pro dotazy fulltextového vyhledávání) a je možné je načíst (není skrytý). Ostatní atributy jsou ve výchozím nastavení vypnuté, ale je možné je povolit. Můžete použít SimpleField pro ID dokumentu nebo pole použitá pouze v filtrech, omezujících vlastností nebo v bodovacích profilech. Pokud ano, nezapomeňte použít všechny atributy, které jsou nezbytné pro daný scénář, například IsKey = true pro ID dokumentu. Další informace najdete v tématu SimpleFieldAttribute.cs ve zdrojovém kódu.

  • SearchableField musí být řetězec a je vždy prohledávatelný a načístelný. Ostatní atributy jsou ve výchozím nastavení vypnuté, ale je možné je povolit. Vzhledem k tomu, že tento typ pole je prohledávatelný, podporuje synonyma a úplný doplněk vlastností analyzátoru. Další informace najdete v SearchableFieldAttribute.cs ve zdrojovém kódu.

Bez ohledu na to, jestli používáte základní SearchField rozhraní API nebo jeden z pomocných modelů, musíte explicitně povolit atributy filtru, omezující vlastnosti a řazení. Například IsFilterable, IsSortable a IsFacetable musí být explicitně přiřazeny, jak je znázorněno v předchozí ukázce.

Vytvoření indexu vyhledávání

V Program.cs vytvoříte SearchIndex objekt a pak zavoláte CreateIndex metoda vyjádřit index ve vyhledávací službě. Index obsahuje také SearchSuggester , který povolí automatické dokončování v zadaných polích.

// 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);
}

Nahrání dokumentů

Azure AI Search vyhledá obsah uložený ve službě. V tomto kroku načtete dokumenty JSON, které odpovídají indexu hotelu, který jste vytvořili.

Ve službě Azure AI Search jsou vyhledávací dokumenty datové struktury, které jsou vstupy indexování a výstupy z dotazů. Jak je získáno z externího zdroje dat, vstupy dokumentů můžou být řádky v databázi, objekty blob v úložišti objektů blob nebo dokumenty JSON na disku. V tomto příkladu přebíráme zástupce a vkládáme dokumenty JSON pro čtyři hotely v samotném kódu.

Při nahrávání dokumentů musíte použít objekt IndexDocumentsBatch . Objekt IndexDocumentsBatch obsahuje kolekci akcí, z nichž každý obsahuje dokument a vlastnost, která službě Azure AI Search říká, jakou akci provést (nahrání, sloučení, odstranění a mergeOrUpload).

V Program.cs vytvoříte pole dokumentů a akcí indexu a pak předáte pole do IndexDocumentsBatch. Následující dokumenty odpovídají indexu pro rychlý start hotelů, jak je definováno hotelovou třídou.

// 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 = "The hotel is ideally located on the main commercial artery of the city in the heart of New York. A few minutes away is Time's 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.",
                DescriptionFr = "L'hôtel est idéalement situé sur la principale artère commerciale de la ville en plein cœur de New York. A quelques minutes se trouve la place du temps et le centre historique de la ville, ainsi que d'autres lieux d'intérêt qui font de New York l'une des villes les plus attractives et cosmopolites de l'Amérique.",
                Category = "Boutique",
                Tags = new[] { "pool", "air conditioning", "concierge" },
                ParkingIncluded = false,
                LastRenovationDate = new DateTimeOffset(1970, 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
}

Jakmile inicializujete IndexDocumentsBatch objekt, můžete jej odeslat do indexu voláním IndexDocuments na objekt SearchClient .

Dokumenty načítáte pomocí SearchClient in Main(), ale operace také vyžaduje oprávnění správce služby, která je obvykle přidružena k SearchIndexClient. Jedním zezpůsobůch SearchIndexClientsearchIndexClient

SearchClient ingesterClient = searchIndexClient.GetSearchClient(indexName);

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

Vzhledem k tomu, že máme konzolovou aplikaci, která spouští všechny příkazy postupně, přidáme 2sekundovou dobu čekání mezi indexováním a dotazy.

// 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);

Dvousekundové zpoždění kompenzuje indexování, což je asynchronní, aby se všechny dokumenty mohly indexovat před spuštěním dotazů. Kódování ve zpoždění je obvykle nezbytné pouze v ukázkách, testech a ukázkových aplikacích.

Prohledání indexu

Výsledky dotazu můžete získat hned po indexování prvního dokumentu, ale skutečné testování indexu by mělo počkat na indexování všech dokumentů.

Tato část přidává dvě funkce: logiku dotazu a výsledky. Pro dotazy použijte metodu Search . Tato metoda přebírá hledaný text (řetězec dotazu) a další možnosti.

SearchResults třída představuje výsledky.

V Program.csWriteDocuments metoda vytiskne výsledky hledání do konzoly.

// 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();
}

Příklad dotazu 1

Metoda RunQueries provádí dotazy a vrací výsledky. Výsledky jsou objekty Hotelu. Tato ukázka ukazuje podpis metody a první dotaz. Tento dotaz ukazuje Select parametr, který umožňuje vytvořit výsledek pomocí vybraných polí z dokumentu.

// 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
}

Příklad dotazu 2

Ve druhém dotazu vyhledejte termín, přidejte filtr, který vybere dokumenty, ve kterých je hodnocení větší než 4, a potom řadit podle hodnocení v sestupném pořadí. Filtr je logický výraz, který se vyhodnocuje přes pole IsFilterable v indexu. Dotazy filtrování zahrnují nebo vylučují hodnoty. Proto neexistuje žádné skóre relevance přidružené k dotazu filtru.

// 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);

Příklad dotazu 3

Třetí dotaz ukazuje searchFields, který slouží k určení rozsahu operace fulltextového vyhledávání na konkrétní pole.

// 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);

Příklad dotazu 4

Čtvrtý dotaz ukazuje facets, který lze použít ke strukturování fasetové navigační struktury.

// 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);

Příklad dotazu 5

V pátém dotazu vraťte konkrétní dokument. Vyhledání dokumentu je typická odpověď na OnClick událost v sadě výsledků.

// 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);

Příklad dotazu 6

Poslední dotaz zobrazí syntaxi automatického dokončování, která simuluje částečný vstup uživatele sa , který se přeloží na dvě možné shody ve zdrojových polích přidružených k sugestivnímu modulu, který jste definovali v indexu.

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

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

Souhrn dotazů

Předchozí dotazy zobrazují v dotazu několik způsobů párování termínů: fulltextové vyhledávání, filtry a automatické dokončování.

Fulltextové vyhledávání a filtry se provádějí pomocí metody SearchClient.Search . Vyhledávací dotaz lze předat v řetězcisearchText, zatímco výraz filtru lze předat ve vlastnosti Filter třídy SearchOptions. Pokud chcete filtrovat bez hledání, stačí předat "*"searchText parametr metody Search . Pokud chcete hledat bez filtrování, nechejte Filter vlastnost nenasazenou nebo vůbec nepředávejte SearchOptions instanci.

Naučte se používat klientskou knihovnu Azure.Search.Documents k vytvoření, načtení a dotazování indexu vyhledávání pomocí ukázkových dat pro fulltextové vyhledávání. Fulltextové vyhledávání používá Apache Lucene k indexování a dotazům a algoritmus hodnocení BM25 pro vyhodnocování výsledků.

V tomto rychlém startu se vytvoří a dotazuje malý index rychlého startu obsahující data o čtyřech hotelech.

Tip

Zdrojový kód si můžete stáhnout, abyste mohli začít s hotovým projektem, nebo si podle těchto kroků vytvořte vlastní.

Požadavky

Požadavky pro Microsoft Entra ID

Pro doporučené ověřování bez klíčů s ID Microsoft Entra musíte:

  • Nainstalujte Azure CLI, které se používá pro ověřování bez klíčů pomocí ID Microsoft Entra.
  • Přiřaďte uživatelskému Search Service Contributor účtu obě role i Search Index Data Contributor role. Role můžete přiřadit na webu Azure Portal v části Řízení přístupu (IAM)>Přidat přiřazení role. Další informace najdete v tématu Připojení k Azure AI Search pomocí rolí.

Načtení informací o prostředcích

Abyste mohli aplikaci ověřit pomocí Search Azure AI, musíte načíst následující informace:

Název proměnné Hodnota
SEARCH_API_ENDPOINT Tuto hodnotu najdete na webu Azure Portal. Vyberte vyhledávací službu a pak v nabídce vlevo vyberte Přehled. Hodnota url v části Essentials je koncový bod, který potřebujete. Příkladem koncového bodu může být https://mydemo.search.windows.net.

Přečtěte si další informace o ověřování bez klíčů a nastavení proměnných prostředí.

Nastavení

Ukázka v tomto rychlém startu funguje s modulem Runtime Java. Nainstalujte sadu Java Development Kit, jako je Azul Zulu OpenJDK. Měl by fungovat také microsoft build OpenJDK nebo upřednostňovaná sada JDK.

  1. Nainstalujte Apache Maven. Pak spusťte a potvrďte mvn -v úspěšnou instalaci.

  2. V kořenovém adresáři projektu vytvořte nový pom.xml soubor a zkopírujte do něj následující kód:

    <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. Nainstalujte závislosti včetně klientské knihovny Azure AI Search (Azure.Search.Documents) pro klientskou knihovnu Java a Azure Identity pro Javu pomocí:

    mvn clean dependency:copy-dependencies
    
  4. Pro doporučené ověřování bez klíčů pomocí ID Microsoft Entra se přihlaste k Azure pomocí následujícího příkazu:

    az login
    

Vytvoření, načtení a dotazování indexu vyhledávání

V předchozí části nastavení jste nainstalovali klientskou knihovnu Azure AI Search a další závislosti.

V této části přidáte kód pro vytvoření indexu vyhledávání, načtení s dokumenty a spouštění dotazů. Spuštěním programu zobrazíte výsledky v konzole. Podrobné vysvětlení kódu najdete v části s vysvětlením kódu .

Ukázkový kód v tomto rychlém startu používá PRO doporučené ověřování bez klíčů ID Microsoft Entra. Pokud dáváte přednost použití klíče rozhraní API, můžete objekt nahradit DefaultAzureCredential objektem AzureKeyCredential .

String searchServiceEndpoint = "https://<Put your search service NAME here>.search.windows.net/";
DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();
  1. Vytvořte nový soubor s názvem App.java a vložte do App.java následující kód:

    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 = "The hotel is ideally located on the main commercial artery of the city in the heart of New York. A few minutes away is Time's 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.descriptionFr = "L'hôtel est idéalement situé sur la principale artère commerciale de la ville en plein cœur de New York. A quelques minutes se trouve la place du temps et le centre historique de la ville, ainsi que d'autres lieux d'intérêt qui font de New York l'une des villes les plus attractives et cosmopolites de l'Amérique.";
            hotel.category = "Boutique";
            hotel.tags = new String[] { "pool", "air conditioning", "concierge" };
            hotel.parkingIncluded = false;
            hotel.lastRenovationDate = OffsetDateTime.of(LocalDateTime.of(LocalDate.of(1970, 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.";
            hotel.descriptionFr = "L'hôtel est situé dans une place du XIXe siècle, qui a été agrandie et rénovée aux plus hautes normes architecturales pour créer un hôtel moderne, fonctionnel et de première classe dans lequel l'art et les éléments historiques uniques coexistent avec le confort le plus moderne.";
            hotel.category = "Boutique";
            hotel.tags = new String[] { "pool", "free wifi", "concierge" };
            hotel.parkingIncluded = false;
            hotel.lastRenovationDate = OffsetDateTime.of(LocalDateTime.of(LocalDate.of(1979, 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 Hotel stands out for its gastronomic excellence under the management of William Dough, who advises on and oversees all of the Hotel’s restaurant services.";
            hotel.descriptionFr = "L'hôtel est situé dans une place du XIXe siècle, qui a été agrandie et rénovée aux plus hautes normes architecturales pour créer un hôtel moderne, fonctionnel et de première classe dans lequel l'art et les éléments historiques uniques coexistent avec le confort le plus moderne.";
            hotel.category = "Resort and Spa";
            hotel.tags = new String[] { "air conditioning", "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 Palace is part of a lovingly restored 1800 palace.";
            hotel.descriptionFr = "Le Sublime Palace Hotel est situé au coeur du centre historique de sublime dans un quartier extrêmement animé et vivant, à courte distance de marche des sites et monuments de la ville et est entouré par l'extraordinaire beauté des églises, des bâtiments, des commerces et Monuments. Sublime Palace fait partie d'un Palace 1800 restauré avec amour.";
            hotel.category = "Boutique";
            hotel.tags = new String[] { "concierge", "view", "24-hour front desk service" };
            hotel.parkingIncluded = true;
            hotel.lastRenovationDate = OffsetDateTime.of(LocalDateTime.of(LocalDate.of(1960, 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. Vytvořte nový soubor s názvem Hotel.java a vložte do Hotel.java následující kód:

    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;
    
        /**
         * French description
         */
        @JsonProperty("DescriptionFr")
        @SearchableField(analyzerName = "fr.lucene")
        public String descriptionFr;
    
        /**
         * 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. Vytvořte nový soubor s názvem Address.java a vložte do Address.java následující kód:

    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. Spusťte novou konzolovou aplikaci:

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

Vysvětlení kódu

V předchozích částech jste vytvořili novou konzolovou aplikaci a nainstalovali klientskou knihovnu Azure AI Search. Přidali jste kód pro vytvoření indexu vyhledávání, načtení s dokumenty a spouštění dotazů. Spustili jste program, abyste zobrazili výsledky v konzole.

V této části vysvětlujeme kód, který jste přidali do konzolové aplikace.

Vytvoření vyhledávacího klienta

V App.java jste vytvořili dva klienty:

  • SearchIndexClient vytvoří index.
  • SearchClient načte a dotazuje existující index.

Oba klienti potřebují koncový bod vyhledávací služby a přihlašovací údaje popsané výše v části s informacemi o prostředcích.

Ukázkový kód v tomto rychlém startu používá PRO doporučené ověřování bez klíčů ID Microsoft Entra. Pokud dáváte přednost použití klíče rozhraní API, můžete objekt nahradit DefaultAzureCredential objektem 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 . . . 
}

Vytvoření indexu

V tomto rychlém startu vytvoříte index hotelů, na který načtete data hotelů, a spustíte dotazy. V tomto kroku definujete pole v indexu. Každá definice pole obsahuje název, datový typ a atributy, které určují způsob použití pole.

V tomto příkladu se pro jednoduchost a čitelnost používají synchronní metody knihovny Azure.Search.Documents . V produkčních scénářích byste ale měli použít asynchronní metody, které umožňují udržovat aplikaci škálovatelnou a responzivní. Místo CreateIndex byste například použili CreateIndexAsync.

Definování struktur

Vytvořili jste dvě pomocné třídy, Hotel.java a Address.java, abyste definovali strukturu hotelového dokumentu a jeho adresy. Třída hotelu obsahuje pole pro ID hotelu, název, popis, kategorii, značky, parkování, datum renovace, hodnocení a adresu. Třída Adresa obsahuje pole pro adresu ulice, město, stát/kraj, PSČ a zemi/oblast.

V klientské knihovně Azure.Search.Documents můžete k zjednodušení definic polí použít SearchableField a SimpleField .

  • SimpleField může být libovolný datový typ, je vždy nehledatelný (ignorován pro dotazy fulltextového vyhledávání) a je možné je načíst (není skrytý). Ostatní atributy jsou ve výchozím nastavení vypnuté, ale je možné je povolit. Pro ID dokumentu nebo pole použitá pouze v filtrech, fazetách nebo v bodovacích profilech můžete použít SimpleField. Pokud ano, nezapomeňte použít všechny atributy, které jsou nezbytné pro scénář, například IsKey = true pro ID dokumentu.
  • SearchableField musí být řetězec a je vždy prohledávatelný a načístelný. Ostatní atributy jsou ve výchozím nastavení vypnuté, ale je možné je povolit. Vzhledem k tomu, že tento typ pole je prohledávatelný, podporuje synonyma a úplný doplněk vlastností analyzátoru.

Bez ohledu na to, jestli používáte základní SearchField rozhraní API nebo jeden z pomocných modelů, musíte explicitně povolit atributy filtru, omezující vlastnosti a řazení. Například isFilterable, isSortablea isFacetable musí být explicitně atribut, jak je znázorněno v předchozí ukázce.

Vytvoření indexu vyhledávání

V App.javaaplikaci vytvoříte SearchIndex objekt v main metodě a potom zavoláte metodu createOrUpdateIndex pro vytvoření indexu ve vyhledávací službě. Index obsahuje SearchSuggester také povolení automatického dokončování u zadaných polí.

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

Nahrání dokumentů

Azure AI Search vyhledá obsah uložený ve službě. V tomto kroku načtete dokumenty JSON, které odpovídají indexu hotelu, který jste vytvořili.

Ve službě Azure AI Search jsou vyhledávací dokumenty datové struktury, které jsou vstupy indexování a výstupy z dotazů. Jak je získáno z externího zdroje dat, vstupy dokumentů můžou být řádky v databázi, objekty blob v úložišti objektů blob nebo dokumenty JSON na disku. V tomto příkladu přebíráme zástupce a vkládáme dokumenty JSON pro čtyři hotely v samotném kódu.

Při nahrávání dokumentů musíte použít objekt IndexDocumentsBatch . Objekt IndexDocumentsBatch obsahuje kolekci IndexActions, z nichž každý obsahuje dokument a vlastnost, která službě Azure AI Search říká, jakou akci provést (nahrání, sloučení, odstranění a mergeOrUpload).

V App.javaaplikaci vytvoříte dokumenty a akce indexu a pak je IndexDocumentsBatchpředáte . Následující dokumenty odpovídají indexu pro rychlý start hotelů, jak je definováno hotelovou třídou.

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 = "The hotel is ideally located on the main commercial artery of the city in the heart of New York. A few minutes away is Time's 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.descriptionFr = "L'hôtel est idéalement situé sur la principale artère commerciale de la ville en plein cœur de New York. A quelques minutes se trouve la place du temps et le centre historique de la ville, ainsi que d'autres lieux d'intérêt qui font de New York l'une des villes les plus attractives et cosmopolites de l'Amérique.";
    hotel.category = "Boutique";
    hotel.tags = new String[] { "pool", "air conditioning", "concierge" };
    hotel.parkingIncluded = false;
    hotel.lastRenovationDate = OffsetDateTime.of(LocalDateTime.of(LocalDate.of(1970, 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");
    }
}

Jakmile objekt inicializujete IndexDocumentsBatch , můžete ho odeslat do indexu voláním indexDocuments ve vašem SearchClient objektu.

Dokumenty načítáte pomocí SearchClient in main(), ale operace také vyžaduje oprávnění správce služby, která je obvykle přidružena k SearchIndexClient. Jedním zezpůsobůch SearchIndexClientsearchIndexClient

uploadDocuments(searchClient);

Vzhledem k tomu, že máme konzolovou aplikaci, která spouští všechny příkazy postupně, přidáme 2sekundovou dobu čekání mezi indexováním a dotazy.

// 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)
{
}

Dvousekundové zpoždění kompenzuje indexování, což je asynchronní, aby se všechny dokumenty mohly indexovat před spuštěním dotazů. Kódování ve zpoždění je obvykle nezbytné pouze v ukázkách, testech a ukázkových aplikacích.

Prohledání indexu

Výsledky dotazu můžete získat hned po indexování prvního dokumentu, ale skutečné testování indexu by mělo počkat na indexování všech dokumentů.

Tato část přidá dvě části funkčnosti: logiku dotazu a výsledky. Pro dotazy použijte metodu Search. Tato metoda přebírá hledaný text (řetězec dotazu) a další možnosti.

Metoda App.javavypíše WriteDocuments výsledky hledání do konzoly.

// 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();
}

Příklad dotazu 1

Metoda RunQueries provádí dotazy a vrací výsledky. Výsledky jsou objekty Hotelu. Tato ukázka ukazuje podpis metody a první dotaz. Tento dotaz ukazuje Select parametr, který umožňuje vytvořit výsledek pomocí vybraných polí z dokumentu.

// 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));
}

Příklad dotazu 2

Ve druhém dotazu vyhledejte termín, přidejte filtr, který vybere dokumenty, ve kterých je hodnocení větší než 4, a potom řadit podle hodnocení v sestupném pořadí. Filtr je logický výraz, který se vyhodnocuje přes isFilterable pole v indexu. Dotazy filtrování zahrnují nebo vylučují hodnoty. Proto neexistuje žádné skóre relevance přidružené k dotazu filtru.

// 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));

Příklad dotazu 3

Třetí dotaz ukazuje searchFields, který slouží k určení rozsahu operace fulltextového vyhledávání na konkrétní pole.

// 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));

Příklad dotazu 4

Čtvrtý dotaz ukazuje facets, který lze použít ke strukturování fasetové navigační struktury.

// 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));

Příklad dotazu 5

V pátém dotazu vraťte konkrétní dokument.

// 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();

Příklad dotazu 6

Poslední dotaz ukazuje syntaxi automatického dokončování, která simuluje částečný uživatelský vstup s , který se přeloží na dvě možné shody v sourceFields přidruženém s návrhu, který jste definovali v indexu.

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

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

Souhrn dotazů

Předchozí dotazy zobrazují v dotazu několik způsobů párování termínů: fulltextové vyhledávání, filtry a automatické dokončování.

Fulltextové vyhledávání a filtry se provádějí pomocí metody SearchClient.search . Vyhledávací dotaz lze předat v searchText řetězci, zatímco výraz filtru lze předat ve filter vlastnosti SearchOptions třídy. Pokud chcete filtrovat bez hledání, stačí předat searchText parametr search metody "*". Pokud chcete hledat bez filtrování, nechejte filter vlastnost nenasazenou nebo vůbec nepředávejte SearchOptions instanci.

Naučte se používat klientskou knihovnu Azure.Search.Documents k vytvoření, načtení a dotazování indexu vyhledávání pomocí ukázkových dat pro fulltextové vyhledávání. Fulltextové vyhledávání používá Apache Lucene k indexování a dotazům a algoritmus hodnocení BM25 pro vyhodnocování výsledků.

V tomto rychlém startu se vytvoří a dotazuje malý index rychlého startu obsahující data o čtyřech hotelech.

Tip

Zdrojový kód si můžete stáhnout, abyste mohli začít s hotovým projektem, nebo si podle těchto kroků vytvořte vlastní.

Požadavky

Požadavky pro Microsoft Entra ID

Pro doporučené ověřování bez klíčů s ID Microsoft Entra musíte:

  • Nainstalujte Azure CLI, které se používá pro ověřování bez klíčů pomocí ID Microsoft Entra.
  • Přiřaďte uživatelskému Search Service Contributor účtu obě role i Search Index Data Contributor role. Role můžete přiřadit na webu Azure Portal v části Řízení přístupu (IAM)>Přidat přiřazení role. Další informace najdete v tématu Připojení k Azure AI Search pomocí rolí.

Načtení informací o prostředcích

Abyste mohli aplikaci ověřit pomocí Search Azure AI, musíte načíst následující informace:

Název proměnné Hodnota
SEARCH_API_ENDPOINT Tuto hodnotu najdete na webu Azure Portal. Vyberte vyhledávací službu a pak v nabídce vlevo vyberte Přehled. Hodnota url v části Essentials je koncový bod, který potřebujete. Příkladem koncového bodu může být https://mydemo.search.windows.net.

Přečtěte si další informace o ověřování bez klíčů a nastavení proměnných prostředí.

Nastavení

  1. Vytvořte novou složku full-text-quickstart , která bude obsahovat aplikaci, a otevřete v této složce Visual Studio Code pomocí následujícího příkazu:

    mkdir full-text-quickstart && cd full-text-quickstart
    
  2. Vytvořte následující package.json příkaz:

    npm init -y
    
  3. Nainstalujte klientskou knihovnu Azure AI Search (Azure.Search.Documents) pro JavaScript pomocí:

    npm install @azure/search-documents
    
  4. Pro doporučené ověřování bez hesla nainstalujte klientskou knihovnu Azure Identity pomocí:

    npm install @azure/identity
    

Vytvoření, načtení a dotazování indexu vyhledávání

V předchozí části nastavení jste nainstalovali klientskou knihovnu Azure AI Search a další závislosti.

V této části přidáte kód pro vytvoření indexu vyhledávání, načtení s dokumenty a spouštění dotazů. Spuštěním programu zobrazíte výsledky v konzole. Podrobné vysvětlení kódu najdete v části s vysvětlením kódu .

Ukázkový kód v tomto rychlém startu používá PRO doporučené ověřování bez klíčů ID Microsoft Entra. Pokud dáváte přednost použití klíče rozhraní API, můžete objekt nahradit DefaultAzureCredential objektem AzureKeyCredential .

String searchServiceEndpoint = "https://<Put your search service NAME here>.search.windows.net/";
DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();
  1. Vytvořte nový soubor s názvem index.js a vložte do index.js následující kód:

    // 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 cliff", 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. Vytvořte soubor s názvem hotels.json a vložte do hotels.json následující kód:

    {
        "value": [
            {
                "HotelId": "1",
                "HotelName": "Secret Point Motel",
                "Description": "The hotel is ideally located on the main commercial artery of the city in the heart of New York. A few minutes away is Time's 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.",
                "Description_fr": "L'hôtel est idéalement situé sur la principale artère commerciale de la ville en plein cœur de New York. A quelques minutes se trouve la place du temps et le centre historique de la ville, ainsi que d'autres lieux d'intérêt qui font de New York l'une des villes les plus attractives et cosmopolites de l'Amérique.",
                "Category": "Boutique",
                "Tags": ["pool", "air conditioning", "concierge"],
                "ParkingIncluded": false,
                "LastRenovationDate": "1970-01-18T00:00:00Z",
                "Rating": 3.6,
                "Address": {
                    "StreetAddress": "677 5th Ave",
                    "City": "New York",
                    "StateProvince": "NY",
                    "PostalCode": "10022"
                }
            },
            {
                "HotelId": "2",
                "HotelName": "Twin Dome Motel",
                "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.",
                "Description_fr": "L'hôtel est situé dans une place du XIXe siècle, qui a été agrandie et rénovée aux plus hautes normes architecturales pour créer un hôtel moderne, fonctionnel et de première classe dans lequel l'art et les éléments historiques uniques coexistent avec le confort le plus moderne.",
                "Category": "Boutique",
                "Tags": ["pool", "free wifi", "concierge"],
                "ParkingIncluded": "false",
                "LastRenovationDate": "1979-02-18T00:00:00Z",
                "Rating": 3.6,
                "Address": {
                    "StreetAddress": "140 University Town Center Dr",
                    "City": "Sarasota",
                    "StateProvince": "FL",
                    "PostalCode": "34243"
                }
            },
            {
                "HotelId": "3",
                "HotelName": "Triple Landscape Hotel",
                "Description": "The Hotel stands out for its gastronomic excellence under the management of William Dough, who advises on and oversees all of the Hotel’s restaurant services.",
                "Description_fr": "L'hôtel est situé dans une place du XIXe siècle, qui a été agrandie et rénovée aux plus hautes normes architecturales pour créer un hôtel moderne, fonctionnel et de première classe dans lequel l'art et les éléments historiques uniques coexistent avec le confort le plus moderne.",
                "Category": "Resort and Spa",
                "Tags": ["air conditioning", "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 Cliff Hotel",
                "Description": "Sublime Cliff 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 1800 palace.",
                "Description_fr": "Le sublime Cliff Hotel est situé au coeur du centre historique de sublime dans un quartier extrêmement animé et vivant, à courte distance de marche des sites et monuments de la ville et est entouré par l'extraordinaire beauté des églises, des bâtiments, des commerces et Monuments. Sublime Cliff fait partie d'un Palace 1800 restauré avec amour.",
                "Category": "Boutique",
                "Tags": ["concierge", "view", "24-hour front desk service"],
                "ParkingIncluded": true,
                "LastRenovationDate": "1960-02-06T00:00:00Z",
                "Rating": 4.6,
                "Address": {
                    "StreetAddress": "7400 San Pedro Ave",
                    "City": "San Antonio",
                    "StateProvince": "TX",
                    "PostalCode": "78216"
                }
            }
        ]
    }
    
  3. Vytvořte soubor s názvem hotels_quickstart_index.json a vložte do hotels_quickstart_index.json následující kód:

    {
    	"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"
    			]
    		}
    	]
    }
    
  4. Přihlaste se k Azure pomocí následujícího příkazu:

    az login
    
  5. Spusťte kód JavaScriptu pomocí následujícího příkazu:

    node index.js
    

Vysvětlení kódu

Vytvoření indexu

Soubor hotels_quickstart_index.json definuje, jak Azure AI Search funguje s dokumenty, které načtete v dalším kroku. Každé pole je identifikováno name a má zadané type. Každé pole má také řadu atributů indexu, které určují, jestli může Azure AI Search prohledávat, filtrovat, řadit a omezující vlastnosti pole. Většina polí je jednoduchých datových typů, ale některé, jako AddressType jsou složité typy, které umožňují vytvářet bohaté datové struktury v indexu. Další informace opodporovaných

S naší definicí indexu chceme importovat hotels_quickstart_index.json v horní části index.js , aby hlavní funkce přistupovala k definici indexu.

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

V rámci hlavní funkce pak vytvoříme , SearchIndexClientkterá se použije k vytváření a správě indexů pro Azure AI Search.

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

Dále chceme odstranit index, pokud už existuje. Tato operace je běžným postupem pro testovací nebo ukázkový kód.

Provedeme to tak, že definujeme jednoduchou funkci, která se pokusí odstranit index.

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

Ke spuštění funkce extrahujeme název indexu z definice indexu indexClientdeleteIndexIfExists() a předáme indexName funkci spolu s funkcí.

const indexName = indexDefinition["name"];

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

Potom jsme připraveni vytvořit index pomocí createIndex() metody.

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

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

Nahrání dokumentů

Ve službě Azure AI Search jsou dokumenty datové struktury, které jsou vstupy indexování a výstupy z dotazů. Tato data můžete odeslat do indexu nebo použít indexer. V tomto případě naprogramujeme dokumenty do indexu.

Vstupy dokumentů můžou být řádky v databázi, objekty blob v úložišti objektů blob nebo jako v této ukázce dokumenty JSON na disku. Podobně jako v případě, že jsme to udělali indexDefinition, musíme také importovat hotels.json v horní části index.js , aby k datům bylo možné přistupovat v naší hlavní funkci.

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

Abychom mohli data indexovat do vyhledávacího indexu, musíme teď vytvořit .SearchClient SearchIndexClient Zatímco se používá k vytvoření a správě indexu, SearchClient slouží k nahrání dokumentů a dotazování indexu.

Existují dva způsoby, jak vytvořit SearchClient. První možností je vytvořit úplně SearchClient od začátku:

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

Alternativně můžete použít getSearchClient() metodu SearchIndexClient vytvoření SearchClient:

const searchClient = indexClient.getSearchClient(indexName);

Teď, když je klient definovaný, nahrajte dokumenty do indexu vyhledávání. V tomto případě použijeme metodu mergeOrUploadDocuments() , která nahraje dokumenty nebo je sloučí s existujícím dokumentem, pokud už existuje dokument se stejným klíčem.

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

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

Prohledání indexu

Když jste vytvořili index a nahráli jste dokumenty, můžete do indexu odesílat dotazy. V této části pošleme do indexu vyhledávání pět různých dotazů, abychom vám ukázali různé části funkcí dotazů, které jsou vám k dispozici.

Dotazy jsou napsané ve sendQueries() funkci, kterou voláme v hlavní funkci následujícím způsobem:

await sendQueries(searchClient);

Dotazy se odesílají pomocí search() metody searchClient. Prvním parametrem je hledaný text a druhý parametr určuje možnosti hledání.

Příklad dotazu 1

První dotaz vyhledá *, což je ekvivalent pro hledání všeho a vybere tři pole v indexu. Osvědčeným postupem je pouze select pole, která potřebujete, protože stažení nepotřebných dat může do dotazů přidat latenci.

Pro searchOptions tento dotaz je includeTotalCount také nastavena truehodnota , která vrátí počet nalezených odpovídajících výsledků.

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
}

Zbývající níže uvedené dotazy by se také měly přidat do sendQueries() funkce. Jsou zde odděleny pro čitelnost.

Příklad dotazu 2

V dalším dotazu určíme hledaný termín "wifi" a zahrneme také filtr, který vrátí pouze výsledky, ve kterých je stav roven 'FL'. Výsledky jsou také objednány hotelovým hotelem Rating.

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)}`);
}

Příklad dotazu 3

Dále je hledání omezeno na jedno prohledávatelné pole pomocí parametru searchFields . Tento přístup je skvělou možností, jak zefektivnit dotaz, pokud víte, že vás zajímají jenom shody v určitých polích.

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();

Příklad dotazu 4

Další běžnou možností zahrnutí do dotazu je facets. Omezující vlastnosti umožňují vytvářet filtry v uživatelském rozhraní, aby uživatelé snadno věděli, na jaké hodnoty můžou filtrovat.

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)}`);
}

Příklad dotazu 5

Poslední dotaz používá getDocument() metodu searchClient. Díky tomu můžete dokument efektivně načíst podle jeho klíče.

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

Souhrn dotazů

Předchozí dotazy zobrazují v dotazu několik způsobů párování termínů: fulltextové vyhledávání, filtry a automatické dokončování.

Fulltextové vyhledávání a filtry se provádějí pomocí searchClient.search metody. Vyhledávací dotaz lze předat v řetězci searchText , zatímco výraz filtru lze předat ve filter vlastnosti SearchOptions třídy. Pokud chcete filtrovat bez hledání, stačí předat searchText parametr search metody "*". Pokud chcete hledat bez filtrování, nechejte filter vlastnost nenasazenou nebo vůbec nepředávejte SearchOptions instanci.

Naučte se používat klientskou knihovnu Azure.Search.Documents k vytvoření, načtení a dotazování indexu vyhledávání pomocí ukázkových dat pro fulltextové vyhledávání. Fulltextové vyhledávání používá Apache Lucene k indexování a dotazům a algoritmus hodnocení BM25 pro vyhodnocování výsledků.

V tomto rychlém startu se vytvoří a dotazuje malý index rychlého startu obsahující data o čtyřech hotelech.

Tip

Dokončený poznámkový blok si můžete stáhnout a spustit.

Požadavky

Požadavky pro Microsoft Entra ID

Pro doporučené ověřování bez klíčů s ID Microsoft Entra musíte:

  • Nainstalujte Azure CLI, které se používá pro ověřování bez klíčů pomocí ID Microsoft Entra.
  • Přiřaďte uživatelskému Search Service Contributor účtu obě role i Search Index Data Contributor role. Role můžete přiřadit na webu Azure Portal v části Řízení přístupu (IAM)>Přidat přiřazení role. Další informace najdete v tématu Připojení k Azure AI Search pomocí rolí.

Načtení informací o prostředcích

Abyste mohli aplikaci ověřit pomocí Search Azure AI, musíte načíst následující informace:

Název proměnné Hodnota
SEARCH_API_ENDPOINT Tuto hodnotu najdete na webu Azure Portal. Vyberte vyhledávací službu a pak v nabídce vlevo vyberte Přehled. Hodnota url v části Essentials je koncový bod, který potřebujete. Příkladem koncového bodu může být https://mydemo.search.windows.net.

Přečtěte si další informace o ověřování bez klíčů a nastavení proměnných prostředí.

Nastavení prostředí

Vzorový kód spustíte v poznámkovém bloku Jupyter. Proto musíte nastavit prostředí pro spouštění poznámkových bloků Jupyter.

  1. Stáhněte nebo zkopírujte ukázkový poznámkový blok z GitHubu.

  2. Otevřete poznámkový blok v editoru Visual Studio Code.

  3. Vytvořte nové prostředí Pythonu, které se použije k instalaci balíčků, které potřebujete pro účely tohoto kurzu.

    Důležité

    Neinstalujte balíčky do globální instalace Pythonu. Při instalaci balíčků Pythonu byste měli vždy používat virtuální prostředí nebo prostředí Conda, jinak můžete přerušit globální instalaci Pythonu.

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

    Nastavení může trvat minutu. Pokud narazíte na problémy, prohlédni si prostředí Pythonu ve VS Code.

  4. Pokud je ještě nemáte, nainstalujte poznámkové bloky Jupyter a jádro IPythonu pro poznámkové bloky Jupyter.

    pip install jupyter
    pip install ipykernel
    python -m ipykernel install --user --name=.venv
    
  5. Vyberte jádro poznámkového bloku.

    1. V pravém horním rohu poznámkového bloku vyberte Vybrat jádro.
    2. Pokud se .venv zobrazí v seznamu, vyberte ho. Pokud ho nevidíte, vyberte Vybrat jiné prostředí>.venv Pythonu jádra.>

Vytvoření, načtení a dotazování indexu vyhledávání

V této části přidáte kód pro vytvoření indexu vyhledávání, načtení s dokumenty a spouštění dotazů. Spuštěním programu zobrazíte výsledky v konzole. Podrobné vysvětlení kódu najdete v části s vysvětlením kódu .

  1. Ujistěte se, že je poznámkový blok otevřený v jádru .venv , jak je popsáno v předchozí části.

  2. Spuštěním první buňky kódu nainstalujte požadované balíčky, včetně azure-search-documents.

    ! pip install azure-search-documents==11.6.0b1 --quiet
    ! pip install azure-identity --quiet
    ! pip install python-dotenv --quiet
    
  3. Obsah druhé buňky kódu nahraďte následujícím kódem v závislosti na metodě ověřování.

    Poznámka:

    Ukázkový kód v tomto rychlém startu používá PRO doporučené ověřování bez klíčů ID Microsoft Entra. Pokud dáváte přednost použití klíče rozhraní API, můžete objekt nahradit DefaultAzureCredential objektem 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. Odeberte následující dva řádky z buňky Vytvořit kód indexu. Přihlašovací údaje jsou již nastaveny v předchozí buňce kódu.

    from azure.core.credentials import AzureKeyCredential
    credential = AzureKeyCredential(search_api_key)
    
  5. Spuštěním buňky Vytvořit index kódu vytvořte vyhledávací index.

  6. Spusťte zbývající buňky kódu postupně, aby se načetly dokumenty a spouštěly dotazy.

Vysvětlení kódu

Vytvoření indexu

SearchIndexClient slouží k vytváření a správě indexů pro Azure AI Search. Každé pole je identifikováno a name má zadané type.

Každé pole má také řadu atributů indexu, které určují, jestli může Azure AI Search prohledávat, filtrovat, řadit a omezující vlastnosti pole. Většina polí je jednoduchých datových typů, ale některé, jako AddressType jsou složité typy, které umožňují vytvářet bohaté datové struktury v indexu. Další informace opodporovaných

Vytvoření datové části dokumentů a nahrání dokumentů

Použijte akci indexu pro typ operace, například nahrání nebo sloučení a nahrání. Dokumenty pocházejí z ukázky HotelsData na GitHubu.

Prohledání indexu

Výsledky dotazu můžete získat hned po indexování prvního dokumentu, ale skutečné testování indexu by mělo počkat na indexování všech dokumentů.

Použijte metodu vyhledávání třídy search.client.

Ukázkové dotazy v poznámkovém bloku jsou:

  • Základní dotaz: Provede prázdné hledání (search=*), vrátí neřaděný seznam (skóre hledání = 1,0) libovolných dokumentů. Vzhledem k tomu, že neexistují žádná kritéria, jsou ve výsledcích zahrnuty všechny dokumenty.
  • Dotaz termínů: Přidá do vyhledávacího výrazu celé termíny ("wifi"). Tento dotaz určuje, že výsledky obsahují pouze tato pole v select příkazu. Omezení polí, která se vrátí, minimalizuje množství dat odesílaných zpět přes drát a snižuje latenci vyhledávání.
  • Filtrovaný dotaz: Přidejte výraz filtru, který vrací pouze ty hotely s hodnocením větším než čtyři, seřazené sestupně.
  • Obory polí: Přidejte search_fields do oboru provádění dotazu na konkrétní pole.
  • Omezující vlastnosti: Vygenerujte omezující vlastnosti pro kladné shody nalezené ve výsledcích hledání. Neexistují žádné nulové shody. Pokud výsledky hledání neobsahují termín wifi, wifi se nezobrazí ve fasetové navigační struktuře.
  • Vyhledání dokumentu: Vrátí dokument na základě jeho klíče. Tato operace je užitečná, pokud chcete poskytnout podrobnou analýzu, když uživatel vybere položku ve výsledku hledání.
  • Automatické dokončování: Zadejte potenciální shody, protože uživatel zadá do vyhledávacího pole. Automatické dokončování používá modul pro návrhy (sg) ke zjištění, která pole obsahují potenciální shody pro žádosti s návrhy. V tomto rychlém startu jsou Tagstato pole , Address/City, Address/Country. Pokud chcete simulovat automatické dokončování, předejte písmena sa jako částečný řetězec. Metoda automatického dokončování SearchClient odesílá zpět potenciální shody termínů.

Odebrání indexu

Pokud jste s tímto indexem hotovi, můžete ho odstranit spuštěním buňky Vyčistit kód. Odstranění nepotřebných indexů uvolní místo pro procházení dalších rychlých startů a kurzů.

Naučte se používat klientskou knihovnu Azure.Search.Documents k vytvoření, načtení a dotazování indexu vyhledávání pomocí ukázkových dat pro fulltextové vyhledávání. Fulltextové vyhledávání používá Apache Lucene k indexování a dotazům a algoritmus hodnocení BM25 pro vyhodnocování výsledků.

V tomto rychlém startu se vytvoří a dotazuje malý index rychlého startu obsahující data o čtyřech hotelech.

Tip

Zdrojový kód si můžete stáhnout, abyste mohli začít s hotovým projektem, nebo si podle těchto kroků vytvořte vlastní.

Požadavky

Požadavky pro Microsoft Entra ID

Pro doporučené ověřování bez klíčů s ID Microsoft Entra musíte:

  • Nainstalujte Azure CLI, které se používá pro ověřování bez klíčů pomocí ID Microsoft Entra.
  • Přiřaďte uživatelskému Search Service Contributor účtu obě role i Search Index Data Contributor role. Role můžete přiřadit na webu Azure Portal v části Řízení přístupu (IAM)>Přidat přiřazení role. Další informace najdete v tématu Připojení k Azure AI Search pomocí rolí.

Načtení informací o prostředcích

Abyste mohli aplikaci ověřit pomocí Search Azure AI, musíte načíst následující informace:

Název proměnné Hodnota
SEARCH_API_ENDPOINT Tuto hodnotu najdete na webu Azure Portal. Vyberte vyhledávací službu a pak v nabídce vlevo vyberte Přehled. Hodnota url v části Essentials je koncový bod, který potřebujete. Příkladem koncového bodu může být https://mydemo.search.windows.net.

Přečtěte si další informace o ověřování bez klíčů a nastavení proměnných prostředí.

Nastavení

  1. Vytvořte novou složku full-text-quickstart , která bude obsahovat aplikaci, a otevřete v této složce Visual Studio Code pomocí následujícího příkazu:

    mkdir full-text-quickstart && cd full-text-quickstart
    
  2. Vytvořte následující package.json příkaz:

    npm init -y
    
  3. package.json Aktualizujte na ECMAScript následujícím příkazem:

    npm pkg set type=module
    
  4. Nainstalujte klientskou knihovnu Azure AI Search (Azure.Search.Documents) pro JavaScript pomocí:

    npm install @azure/search-documents
    
  5. Pro doporučené ověřování bez hesla nainstalujte klientskou knihovnu Azure Identity pomocí:

    npm install @azure/identity
    

Vytvoření, načtení a dotazování indexu vyhledávání

V předchozí části nastavení jste nainstalovali klientskou knihovnu Azure AI Search a další závislosti.

V této části přidáte kód pro vytvoření indexu vyhledávání, načtení s dokumenty a spouštění dotazů. Spuštěním programu zobrazíte výsledky v konzole. Podrobné vysvětlení kódu najdete v části s vysvětlením kódu .

Ukázkový kód v tomto rychlém startu používá PRO doporučené ověřování bez klíčů ID Microsoft Entra. Pokud dáváte přednost použití klíče rozhraní API, můžete objekt nahradit DefaultAzureCredential objektem AzureKeyCredential .

const searchServiceEndpoint = "https://<Put your search service NAME here>.search.windows.net/";
const credential = new DefaultAzureCredential();
  1. Vytvořte nový soubor s názvem index.ts a vložte do index.ts následující kód:

    // 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": "Description_fr",
    			"type": "Edm.String" as SearchFieldDataType,
    			"searchable": true,
    			"filterable": false,
    			"sortable": false,
    			"facetable": false,
    			"analyzerName": "fr.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 cliff", 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. Vytvořte soubor s názvem hotels.json a vložte do hotels.json následující kód:

    {
        "value": [
            {
                "HotelId": "1",
                "HotelName": "Secret Point Motel",
                "Description": "The hotel is ideally located on the main commercial artery of the city in the heart of New York. A few minutes away is Time's 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.",
                "Description_fr": "L'hôtel est idéalement situé sur la principale artère commerciale de la ville en plein cœur de New York. A quelques minutes se trouve la place du temps et le centre historique de la ville, ainsi que d'autres lieux d'intérêt qui font de New York l'une des villes les plus attractives et cosmopolites de l'Amérique.",
                "Category": "Boutique",
                "Tags": ["pool", "air conditioning", "concierge"],
                "ParkingIncluded": false,
                "LastRenovationDate": "1970-01-18T00:00:00Z",
                "Rating": 3.6,
                "Address": {
                    "StreetAddress": "677 5th Ave",
                    "City": "New York",
                    "StateProvince": "NY",
                    "PostalCode": "10022"
                }
            },
            {
                "HotelId": "2",
                "HotelName": "Twin Dome Motel",
                "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.",
                "Description_fr": "L'hôtel est situé dans une place du XIXe siècle, qui a été agrandie et rénovée aux plus hautes normes architecturales pour créer un hôtel moderne, fonctionnel et de première classe dans lequel l'art et les éléments historiques uniques coexistent avec le confort le plus moderne.",
                "Category": "Boutique",
                "Tags": ["pool", "free wifi", "concierge"],
                "ParkingIncluded": "false",
                "LastRenovationDate": "1979-02-18T00:00:00Z",
                "Rating": 3.6,
                "Address": {
                    "StreetAddress": "140 University Town Center Dr",
                    "City": "Sarasota",
                    "StateProvince": "FL",
                    "PostalCode": "34243"
                }
            },
            {
                "HotelId": "3",
                "HotelName": "Triple Landscape Hotel",
                "Description": "The Hotel stands out for its gastronomic excellence under the management of William Dough, who advises on and oversees all of the Hotel’s restaurant services.",
                "Description_fr": "L'hôtel est situé dans une place du XIXe siècle, qui a été agrandie et rénovée aux plus hautes normes architecturales pour créer un hôtel moderne, fonctionnel et de première classe dans lequel l'art et les éléments historiques uniques coexistent avec le confort le plus moderne.",
                "Category": "Resort and Spa",
                "Tags": ["air conditioning", "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 Cliff Hotel",
                "Description": "Sublime Cliff 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 1800 palace.",
                "Description_fr": "Le sublime Cliff Hotel est situé au coeur du centre historique de sublime dans un quartier extrêmement animé et vivant, à courte distance de marche des sites et monuments de la ville et est entouré par l'extraordinaire beauté des églises, des bâtiments, des commerces et Monuments. Sublime Cliff fait partie d'un Palace 1800 restauré avec amour.",
                "Category": "Boutique",
                "Tags": ["concierge", "view", "24-hour front desk service"],
                "ParkingIncluded": true,
                "LastRenovationDate": "1960-02-06T00:00:00Z",
                "Rating": 4.6,
                "Address": {
                    "StreetAddress": "7400 San Pedro Ave",
                    "City": "San Antonio",
                    "StateProvince": "TX",
                    "PostalCode": "78216"
                }
            }
        ]
    }
    
  3. tsconfig.json Vytvořte soubor pro transpilování kódu TypeScript a zkopírujte následující kód pro 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. Transpilovat z TypeScriptu do JavaScriptu.

    tsc
    
  5. Přihlaste se k Azure pomocí následujícího příkazu:

    az login
    
  6. Spusťte kód JavaScriptu pomocí následujícího příkazu:

    node index.js
    

Vysvětlení kódu

Vytvoření indexu

Vytvořte soubor hotels_quickstart_index.json. Tento soubor definuje, jak Azure AI Search funguje s dokumenty, které načtete v dalším kroku. Každé pole je identifikováno name a má zadané type. Každé pole má také řadu atributů indexu, které určují, jestli může Azure AI Search prohledávat, filtrovat, řadit a omezující vlastnosti pole. Většina polí je jednoduchých datových typů, ale některé, jako AddressType jsou složité typy, které umožňují vytvářet bohaté datové struktury v indexu. Další informace opodporovaných

Chceme importovat hotels_quickstart_index.json , aby hlavní funkce přistupovala k definici indexu.

import indexDefinition from './hotels_quickstart_index.json';

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

V rámci hlavní funkce pak vytvoříme , SearchIndexClientkterá se použije k vytváření a správě indexů pro Azure AI Search.

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

Dále chceme odstranit index, pokud už existuje. Tato operace je běžným postupem pro testovací nebo ukázkový kód.

Provedeme to tak, že definujeme jednoduchou funkci, která se pokusí odstranit 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.');
    }
}

Ke spuštění funkce extrahujeme název indexu z definice indexu indexClientdeleteIndexIfExists() a předáme indexName funkci spolu s funkcí.

// 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);

Potom jsme připraveni vytvořit index pomocí createIndex() metody.

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

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

Nahrání dokumentů

Ve službě Azure AI Search jsou dokumenty datové struktury, které jsou vstupy indexování a výstupy z dotazů. Tato data můžete odeslat do indexu nebo použít indexer. V tomto případě naprogramujeme dokumenty do indexu.

Vstupy dokumentů můžou být řádky v databázi, objekty blob v úložišti objektů blob nebo jako v této ukázce dokumenty JSON na disku. Můžete si stáhnout hotels.json nebo vytvořit vlastní soubor hotels.json s následujícím obsahem:

Podobně jako u indexDefinition je potřeba importovat hotels.json také do horní části index.ts , aby k datům bylo možné přistupovat v hlavní funkci.

import hotelData from './hotels.json';

interface Hotel {
    HotelId: string;
    HotelName: string;
    Description: string;
    Description_fr: 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"];

Abychom mohli data indexovat do vyhledávacího indexu, musíme teď vytvořit .SearchClient SearchIndexClient Zatímco se používá k vytvoření a správě indexu, SearchClient slouží k nahrání dokumentů a dotazování indexu.

Existují dva způsoby, jak vytvořit SearchClient. První možností je vytvořit úplně SearchClient od začátku:

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

Alternativně můžete použít getSearchClient() metodu SearchIndexClient vytvoření SearchClient:

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

Teď, když je klient definovaný, nahrajte dokumenty do indexu vyhledávání. V tomto případě použijeme metodu mergeOrUploadDocuments() , která nahraje dokumenty nebo je sloučí s existujícím dokumentem, pokud už existuje dokument se stejným klíčem. Pak zkontrolujte, jestli operace proběhla úspěšně, protože existuje alespoň první dokument.

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

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

Spusťte program znovu pomocí tsc && node index.tspříkazu . Měli byste vidět trochu odlišnou sadu zpráv od zpráv, které jste viděli v kroku 1. Tentokrát existuje index a měla by se zobrazit zpráva o jejím odstranění, než aplikace vytvoří nový index a publikuje do něj data.

Než spustíme dotazy v dalším kroku, definujte funkci, která má program čekat na jednu sekundu. To se provádí jenom pro účely testování/ukázky, aby se zajistilo dokončení indexování a dostupnost dokumentů v indexu pro naše dotazy.

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

Pokud chcete, aby program čekal na jednu sekundu sleep , zavolejte funkci:

sleep(1000);

Prohledání indexu

Když jste vytvořili index a nahráli jste dokumenty, můžete do indexu odesílat dotazy. V této části pošleme do indexu vyhledávání pět různých dotazů, abychom vám ukázali různé části funkcí dotazů, které jsou vám k dispozici.

Dotazy jsou napsané ve sendQueries() funkci, kterou voláme v hlavní funkci následujícím způsobem:

await sendQueries(searchClient);

Dotazy se odesílají pomocí search() metody searchClient. Prvním parametrem je hledaný text a druhý parametr určuje možnosti hledání.

Příklad dotazu 1

První dotaz vyhledá *, což je ekvivalent pro hledání všeho a vybere tři pole v indexu. Osvědčeným postupem je pouze select pole, která potřebujete, protože stažení nepotřebných dat může do dotazů přidat latenci.

U searchOptions tohoto dotazu je includeTotalCount také nastavena hodnota true, která vrátí počet nalezených odpovídajících výsledků.

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
}

Zbývající níže uvedené dotazy by se také měly přidat do sendQueries() funkce. Jsou zde odděleny pro čitelnost.

Příklad dotazu 2

V dalším dotazu určíme hledaný termín "wifi" a zahrneme také filtr, který vrátí pouze výsledky, ve kterých je stav roven 'FL'. Výsledky jsou také objednány hotelovým hotelem Rating.

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)}`);
}

Příklad dotazu 3

Dále je hledání omezeno na jedno prohledávatelné pole pomocí parametru searchFields . Tento přístup je skvělou možností, jak zefektivnit dotaz, pokud víte, že vás zajímají jenom shody v určitých polích.

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)}`);
}

Příklad dotazu 4

Další běžnou možností zahrnutí do dotazu je facets. Fasety umožňují poskytovat samoobslužné přechody k podrobnostem z výsledků v uživatelském rozhraní. Výsledky omezujících vlastností se dají v podokně výsledků převést na zaškrtávací políčka.

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)}`);
}

Příklad dotazu 5

Poslední dotaz používá getDocument() metodu searchClient. Díky tomu můžete dokument efektivně načíst podle jeho klíče.

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

Souhrn dotazů

Předchozí dotazy zobrazují v dotazu několik způsobů párování termínů: fulltextové vyhledávání, filtry a automatické dokončování.

Fulltextové vyhledávání a filtry se provádějí pomocí searchClient.search metody. Vyhledávací dotaz lze předat v řetězci searchText , zatímco výraz filtru lze předat ve filter vlastnosti SearchOptions třídy. Pokud chcete filtrovat bez hledání, stačí předat searchText parametr search metody "*". Pokud chcete hledat bez filtrování, nechejte filter vlastnost nenasazenou nebo vůbec nepředávejte SearchOptions instanci.

Vyčištění prostředků

Pokud pracujete s vlastním předplatným, je vhodné vždy na konci projektu zkontrolovat, jestli budete vytvořené prostředky ještě potřebovat. Prostředky, které necháte spuštěné, vás stojí peníze. Prostředky můžete odstraňovat jednotlivě nebo můžete odstranit skupinu prostředků, a odstranit tak celou sadu prostředků najednou.

Prostředky můžete najít a spravovat na webu Azure Portal pomocí odkazu Všechny prostředky nebo skupiny prostředků v levém navigačním podokně.

Pokud používáte bezplatnou službu, mějte na paměti, že jste omezeni na tři indexy, indexery a zdroje dat. Jednotlivé položky na webu Azure Portal můžete odstranit, abyste zůstali pod limitem.

Další krok

V tomto rychlém startu jste prošli sadou úloh, kterými jste vytvořili index, načetli ho s dokumenty a spustili dotazy. V různých fázích jsme vzali zástupce, abychom zjednodušili kód pro čitelnost a porozumění. Teď, když znáte základní koncepty, vyzkoušejte kurz, který volá rozhraní API služby Azure AI Search ve webové aplikaci.