Udostępnij za pośrednictwem


Szybki start: wyszukiwanie pełnotekstowe

W tym krótkim przewodniku użyjesz biblioteki klienta Azure.Search.Documents do tworzenia, ładowania i wykonywania zapytań względem indeksu wyszukiwania z przykładowymi danymi na potrzeby wyszukiwania pełnotekstowego. Wyszukiwanie pełnotekstowe używa platformy Apache Lucene do indeksowania i zapytań oraz algorytmu klasyfikacji BM25 na potrzeby oceniania wyników.

Ten szybki start używa fikcyjnych danych hotelowych z repozytorium azure-search-sample-data do wypełnienia indeksu.

Napiwek

Możesz pobrać kod źródłowy , aby rozpocząć od ukończonego projektu lub wykonać następujące kroki, aby utworzyć własny.

Wymagania wstępne

  • Konto Azure z aktywną subskrypcją. Utwórz konto bezpłatnie.

  • Usługa wyszukiwania sztucznej inteligencji platformy Azure. Utwórz usługę , jeśli jej nie masz. Możesz skorzystać z bezpłatnej usługi w ramach szybkiego startu.

Wymagania wstępne dotyczące identyfikatora entra firmy Microsoft

W przypadku zalecanego uwierzytelniania bez klucza za pomocą identyfikatora Entra firmy Microsoft należy:

Pobieranie informacji o zasobie

Aby uwierzytelnić aplikację przy użyciu usługi Azure AI usługa wyszukiwania, należy pobrać następujące informacje:

Nazwa zmiennej Wartość
SEARCH_API_ENDPOINT Tę wartość można znaleźć w witrynie Azure Portal. Wybierz usługę wyszukiwania, a następnie z menu po lewej stronie wybierz pozycję Przegląd. Wartość adresu URL w obszarze Podstawy to potrzebny punkt końcowy. Przykładowy punkt końcowy może wyglądać podobnie jak https://mydemo.search.windows.net.

Dowiedz się więcej na temat uwierzytelniania bez klucza i ustawiania zmiennych środowiskowych.

Konfiguruj

  1. Utwórz nowy folder full-text-quickstart zawierający aplikację i otwórz program Visual Studio Code w tym folderze za pomocą następującego polecenia:

    mkdir full-text-quickstart && cd full-text-quickstart
    
  2. Utwórz nową aplikację konsolową za pomocą następującego polecenia:

    dotnet new console
    
  3. Zainstaluj bibliotekę klienta usługi Azure AI Search (Azure.Search.Documents) dla platformy .NET przy użyciu następujących elementów:

    dotnet add package Azure.Search.Documents
    
  4. Aby uzyskać zalecane uwierzytelnianie bez klucza za pomocą identyfikatora Entra firmy Microsoft, zainstaluj pakiet Azure.Identity za pomocą polecenia:

    dotnet add package Azure.Identity
    
  5. Aby uzyskać zalecane uwierzytelnianie bez klucza przy użyciu identyfikatora Entra firmy Microsoft, zaloguj się na platformie Azure za pomocą następującego polecenia:

    az login
    

Tworzenie, ładowanie i wykonywanie zapytań względem indeksu wyszukiwania

W poprzedniej sekcji konfiguracji utworzono nową aplikację konsolową i zainstalowano bibliotekę klienta usługi Azure AI Search.

W tej sekcji dodasz kod, aby utworzyć indeks wyszukiwania, załadować go przy użyciu dokumentów i uruchomić zapytania. Uruchom program, aby wyświetlić wyniki w konsoli programu . Aby uzyskać szczegółowe wyjaśnienie kodu, zobacz sekcję wyjaśniającą kod .

Przykładowy kod w tym przewodniku Szybki start używa identyfikatora Entra firmy Microsoft do zalecanego uwierzytelniania bez klucza. Jeśli wolisz użyć klucza interfejsu API, możesz zastąpić DefaultAzureCredential obiekt obiektem AzureKeyCredential .

Uri serviceEndpoint = new Uri($"https://<Put your search service NAME here>.search.windows.net/");
DefaultAzureCredential credential = new();
  1. W Program.cs wklej następujący kod. serviceName Edytuj zmienne i apiKey przy użyciu nazwy usługi wyszukiwania i klucza interfejsu API administratora.

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

    using System;
    using System.Text.Json.Serialization;
    using Azure.Search.Documents.Indexes;
    using Azure.Search.Documents.Indexes.Models;
    
    namespace AzureSearch.Quickstart
    {
        public partial class Hotel
        {
            [SimpleField(IsKey = true, IsFilterable = true)]
            public string HotelId { get; set; }
    
            [SearchableField(IsSortable = true)]
            public string HotelName { get; set; }
    
            [SearchableField(AnalyzerName = LexicalAnalyzerName.Values.EnLucene)]
            public string Description { get; set; }
    
            [SearchableField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
            public string Category { get; set; }
    
            [SearchableField(IsFilterable = true, IsFacetable = true)]
            public string[] Tags { get; set; }
    
            [SimpleField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
            public bool? ParkingIncluded { get; set; }
    
            [SimpleField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
            public DateTimeOffset? LastRenovationDate { get; set; }
    
            [SimpleField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
            public double? Rating { get; set; }
    
            [SearchableField]
            public Address Address { get; set; }
        }
    }
    
  3. Utwórz nowy plik o nazwie Hotel.cs i wklej następujący kod, aby zdefiniować strukturę dokumentu hotelowego. Atrybuty w polu określają sposób jej użycia w aplikacji. Na przykład IsFilterable atrybut musi być przypisany do każdego pola obsługującego wyrażenie 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(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. Utwórz nowy plik o nazwie Address.cs i wklej następujący kod, aby zdefiniować strukturę dokumentu adresu.

    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. Utwórz nowy plik o nazwie Hotel.Methods.cs i wklej następujący kod, aby zdefiniować ToString() przesłonięcia dla Hotel klasy.

    using System;
    using System.Text;
    
    namespace AzureSearch.Quickstart
    {
        public partial class Hotel
        {
            public override string ToString()
            {
                var builder = new StringBuilder();
    
                if (!String.IsNullOrEmpty(HotelId))
                {
                    builder.AppendFormat("HotelId: {0}\n", HotelId);
                }
    
                if (!String.IsNullOrEmpty(HotelName))
                {
                    builder.AppendFormat("Name: {0}\n", HotelName);
                }
    
                if (!String.IsNullOrEmpty(Description))
                {
                    builder.AppendFormat("Description: {0}\n", Description);
                }
    
                if (!String.IsNullOrEmpty(Category))
                {
                    builder.AppendFormat("Category: {0}\n", Category);
                }
    
                if (Tags != null && Tags.Length > 0)
                {
                    builder.AppendFormat("Tags: [ {0} ]\n", String.Join(", ", Tags));
                }
    
                if (ParkingIncluded.HasValue)
                {
                    builder.AppendFormat("Parking included: {0}\n", ParkingIncluded.Value ? "yes" : "no");
                }
    
                if (LastRenovationDate.HasValue)
                {
                    builder.AppendFormat("Last renovated on: {0}\n", LastRenovationDate);
                }
    
                if (Rating.HasValue)
                {
                    builder.AppendFormat("Rating: {0}\n", Rating);
                }
    
                if (Address != null && !Address.IsEmpty)
                {
                    builder.AppendFormat("Address: \n{0}\n", Address.ToString());
                }
    
                return builder.ToString();
            }
        }
    }
    
  6. Utwórz nowy plik o nazwie

    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. Skompiluj i uruchom aplikację za pomocą następującego polecenia:

    dotnet run
    

Dane wyjściowe obejmują komunikaty z elementu Console.WriteLine z dodawaniem informacji o zapytaniu i wynikach.

Wyjaśnienie kodu

W poprzednich sekcjach utworzono nową aplikację konsolową i zainstalowano bibliotekę klienta usługi Azure AI Search. Dodano kod umożliwiający utworzenie indeksu wyszukiwania, załadowanie go za pomocą dokumentów i uruchomienie zapytań. Uruchomiono program, aby wyświetlić wyniki w konsoli programu .

W tej sekcji wyjaśnimy kod dodany do aplikacji konsolowej.

Tworzenie klienta wyszukiwania

W Program.cs utworzono dwóch klientów:

Oba klienci potrzebują punktu końcowego usługi wyszukiwania i poświadczeń opisanych wcześniej w sekcji informacji o zasobie.

Przykładowy kod w tym przewodniku Szybki start używa identyfikatora Entra firmy Microsoft do zalecanego uwierzytelniania bez klucza. Jeśli wolisz użyć klucza interfejsu API, możesz zastąpić DefaultAzureCredential obiekt obiektem 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 . . . 
}

Tworzenie indeksu

Ten przewodnik Szybki start tworzy indeks Hotels ładowany przy użyciu danych hotelowych i wykonywania zapytań względem. W tym kroku zdefiniujesz pola w indeksie. Każda definicja pola zawiera nazwę, typ danych i atrybuty określające sposób użycia pola.

W tym przykładzie metody synchroniczne biblioteki Azure.Search.Documents są używane dla uproszczenia i czytelności. Jednak w przypadku scenariuszy produkcyjnych należy użyć metod asynchronicznych, aby zapewnić skalowalność i elastyczność aplikacji. Na przykład należy użyć polecenia CreateIndexAsync zamiast polecenia CreateIndex.

Definiowanie struktur

Utworzono dwie klasy pomocnicze, Hotel.cs i Address.cs, aby zdefiniować strukturę dokumentu hotelowego i jego adresu. Klasa Hotel zawiera pola dla identyfikatora hotelu, nazwy, opisu, kategorii, tagów, parkingu, daty renowacji, klasyfikacji i adresu. Klasa Address zawiera pola adresów ulicznych, miasta, stanu/prowincji, kodu pocztowego i kraju/regionu.

W bibliotece klienta Azure.Search.Documents można użyć pól SearchableField i SimpleField, aby usprawnić definicje pól. Oba są pochodnymi pola wyszukiwania i mogą potencjalnie uprościć kod:

  • SimpleField może być dowolnym typem danych, jest zawsze niemożliwy do przeszukiwania (ignorowany w przypadku zapytań wyszukiwania pełnotekstowego) i jest pobierany (nie jest ukryty). Inne atrybuty są domyślnie wyłączone, ale można je włączyć. Można użyć SimpleField elementu dla identyfikatorów dokumentów lub pól używanych tylko w filtrach, aspektach lub profilach oceniania. Jeśli tak, pamiętaj, aby zastosować wszelkie atrybuty niezbędne do scenariusza, takie jak IsKey = true identyfikator dokumentu. Aby uzyskać więcej informacji, zobacz SimpleFieldAttribute.cs w kodzie źródłowym.

  • SearchableField musi być ciągiem i zawsze można wyszukiwać i pobierać. Inne atrybuty są domyślnie wyłączone, ale można je włączyć. Ponieważ ten typ pola można wyszukiwać, obsługuje synonimy i pełne uzupełnienie właściwości analizatora. Aby uzyskać więcej informacji, zobacz SearchableFieldAttribute.cs w kodzie źródłowym.

Niezależnie od tego, czy używasz podstawowego SearchField interfejsu API, czy jednego z modeli pomocnika, musisz jawnie włączyć atrybuty filtru, aspektu i sortowania. Na przykład IsFilterable, IsSortable i IsFacetable muszą być jawnie przypisane, jak pokazano w poprzednim przykładzie.

Tworzenie indeksu wyszukiwania

W Program.cs utworzysz obiekt SearchIndex, a następnie wywołasz metodę CreateIndex, aby wyrazić indeks w usłudze wyszukiwania. Indeks zawiera również element SearchSuggester umożliwiający automatyczne uzupełnianie w określonych polach.

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

Ładowanie dokumentów

Usługa Azure AI Search wyszukuje zawartość przechowywaną w usłudze. W tym kroku załadujesz dokumenty JSON zgodne z utworzonym indeksem hotelowym.

W usłudze Azure AI Search dokumenty wyszukiwania to struktury danych, które są danymi wejściowymi do indeksowania i danych wyjściowych z zapytań. Dane wejściowe dokumentu uzyskane z zewnętrznego źródła danych mogą być wierszami w bazie danych, obiektami blob w usłudze Blob Storage lub dokumentami JSON na dysku. W tym przykładzie używamy skrótu i osadzamy dokumenty JSON dla czterech hoteli w samym kodzie.

Podczas przekazywania dokumentów należy użyć obiektu IndexDocumentsBatch . Obiekt IndexDocumentsBatch zawiera kolekcję akcji, z których każda zawiera dokument i właściwość informującą usługę Azure AI Search o tym, jaką akcję wykonać (przekazywanie, scalanie, usuwanie i scalanieOrUpload).

W Program.cs utworzysz tablicę dokumentów i akcji indeksu, a następnie przekażesz tablicę do IndexDocumentsBatch. Następujące dokumenty są zgodne z indeksem hotels-quickstart zdefiniowanym przez klasę hotelową.

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

Po zainicjowaniu obiektu IndexDocumentsBatch możesz wysłać go do indeksu, wywołując element IndexDocuments w obiekcie SearchClient.

Dokumenty są ładowane przy użyciu elementu SearchClient w Main()programie , ale operacja wymaga również uprawnień administratora w usłudze, która jest zwykle skojarzona z elementem SearchIndexClient. Jednym ze sposobów skonfigurowania tej operacji jest pobranie elementu SearchClient za pośrednictwem SearchIndexClient (searchIndexClient w tym przykładzie).

SearchClient ingesterClient = searchIndexClient.GetSearchClient(indexName);

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

Ponieważ mamy aplikację konsolową, która uruchamia wszystkie polecenia sekwencyjnie, dodamy 2-sekundowy czas oczekiwania między indeksowaniem a zapytaniami.

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

2-sekundowe opóźnienie rekompensuje indeksowanie, co jest asynchroniczne, dzięki czemu wszystkie dokumenty można indeksować przed wykonaniem zapytań. Kodowanie w opóźnieniu jest zwykle konieczne tylko w przypadku pokazów, testów i przykładowych aplikacji.

Przeszukiwanie indeksu

Wyniki zapytania można uzyskać zaraz po indeksowanym pierwszym dokumencie, ale rzeczywiste testowanie indeksu powinno poczekać, aż wszystkie dokumenty zostaną zindeksowane.

W tej sekcji dodano dwie funkcje: logikę zapytań i wyniki. W przypadku zapytań użyj metody Search . Ta metoda przyjmuje tekst wyszukiwania (ciąg zapytania) i inne opcje.

Klasa SearchResults reprezentuje wyniki.

W Program.csWriteDocuments metoda wyświetla wyniki wyszukiwania w konsoli programu .

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

Przykład zapytania 1

Metoda RunQueries wykonuje zapytania i zwraca wyniki. Wyniki to obiekty hotelowe. W tym przykładzie przedstawiono podpis metody i pierwsze zapytanie. To zapytanie demonstruje Select parametr, który umożliwia tworzenie wyniku przy użyciu wybranych pól 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
}

Przykład zapytania 2

W drugim zapytaniu wyszukaj termin, dodaj filtr, który wybiera dokumenty, w których ocena jest większa niż 4, a następnie sortuj według klasyfikacji w kolejności malejącej. Filter to wyrażenie logiczne, które jest obliczane za pośrednictwem pól IsFilterable w indeksie. Filtrowanie zapytań obejmuje lub wyklucza wartości. W związku z tym nie ma wskaźnika istotności skojarzonego z zapytaniem 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);

Przykład zapytania 3

Trzecie zapytanie demonstruje searchFieldsmetodę , używaną do określania zakresu operacji wyszukiwania pełnotekstowego do określonych pól.

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

Przykład zapytania 4

Czwarte zapytanie demonstruje facetsmetodę , która może służyć do struktury struktury nawigacji aspektowej.

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

Przykład zapytania 5

W piątym zapytaniu zwróć określony dokument. Wyszukiwanie dokumentu to typowa odpowiedź na OnClick zdarzenie w zestawie wyników.

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

Przykład zapytania 6

Ostatnie zapytanie pokazuje składnię autouzupełniania, symulując częściowe dane wejściowe użytkownika sa , która rozpoznaje dwa możliwe dopasowania w polach źródłowych skojarzonych z sugerowanym elementem zdefiniowanym w indeksie.

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

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

Podsumowanie zapytań

Poprzednie zapytania pokazują wiele sposobów dopasowywania terminów w zapytaniu: wyszukiwanie pełnotekstowe, filtry i autouzupełnianie.

Wyszukiwanie pełnotekstowe i filtry są wykonywane przy użyciu metody SearchClient.Search . Zapytanie wyszukiwania można przekazać w searchText ciągu, a wyrażenie filtru można przekazać we właściwości Filter klasy SearchOptions. Aby filtrować bez wyszukiwania, wystarczy przekazać "*"searchText parametr metody Search . Aby wyszukać bez filtrowania, pozostaw Filter właściwość niezastawioną lub nie przekazuj SearchOptions w ogóle wystąpienia.

W tym szybkim starcie użyjesz biblioteki klienta Azure.Search.Documents do tworzenia, ładowania i wykonywania zapytań względem indeksu wyszukiwania z przykładowymi danymi do wyszukiwania pełnotekstowego. Wyszukiwanie pełnotekstowe używa platformy Apache Lucene do indeksowania i zapytań oraz algorytmu klasyfikacji BM25 na potrzeby oceniania wyników.

Ten szybki start używa fikcyjnych danych hotelowych z repozytorium azure-search-sample-data do wypełniania indeksu.

Napiwek

Możesz pobrać kod źródłowy , aby rozpocząć od ukończonego projektu lub wykonać następujące kroki, aby utworzyć własny.

Wymagania wstępne

  • Konto Azure z aktywną subskrypcją. Utwórz konto bezpłatnie.

  • Usługa wyszukiwania sztucznej inteligencji platformy Azure. Utwórz usługę , jeśli jej nie masz. Możesz skorzystać z bezpłatnej usługi w ramach szybkiego startu.

Wymagania wstępne dotyczące identyfikatora entra firmy Microsoft

W przypadku zalecanego uwierzytelniania bez klucza za pomocą identyfikatora Entra firmy Microsoft należy:

Pobieranie informacji o zasobie

Aby uwierzytelnić aplikację przy użyciu usługi Azure AI usługa wyszukiwania, należy pobrać następujące informacje:

Nazwa zmiennej Wartość
SEARCH_API_ENDPOINT Tę wartość można znaleźć w witrynie Azure Portal. Wybierz usługę wyszukiwania, a następnie z menu po lewej stronie wybierz pozycję Przegląd. Wartość adresu URL w obszarze Podstawy to potrzebny punkt końcowy. Przykładowy punkt końcowy może wyglądać podobnie jak https://mydemo.search.windows.net.

Dowiedz się więcej na temat uwierzytelniania bez klucza i ustawiania zmiennych środowiskowych.

Konfiguruj

Przykład w tym przewodniku Szybki start współpracuje ze środowiskiem uruchomieniowym Języka Java. Zainstaluj zestaw Java Development Kit, taki jak Azul Zulu OpenJDK. Pakiet Microsoft Build zestawu OpenJDK lub preferowany zestaw JDK powinien również działać.

  1. Zainstaluj narzędzie Apache Maven. Następnie uruchom polecenie mvn -v , aby potwierdzić pomyślną instalację.

  2. Utwórz nowy pom.xml plik w katalogu głównym projektu i skopiuj do niego następujący kod:

    <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. Zainstaluj zależności, w tym bibliotekę klienta usługi Azure AI Search (Azure.Search.Documents) dla języka Java i bibliotekę klienta tożsamości platformy Azure dla języka Java za pomocą następujących elementów:

    mvn clean dependency:copy-dependencies
    
  4. Aby uzyskać zalecane uwierzytelnianie bez klucza przy użyciu identyfikatora Entra firmy Microsoft, zaloguj się na platformie Azure za pomocą następującego polecenia:

    az login
    

Tworzenie, ładowanie i wykonywanie zapytań względem indeksu wyszukiwania

W poprzedniej sekcji konfiguracji zainstalowano bibliotekę klienta usługi Azure AI Search i inne zależności.

W tej sekcji dodasz kod, aby utworzyć indeks wyszukiwania, załadować go przy użyciu dokumentów i uruchomić zapytania. Uruchom program, aby wyświetlić wyniki w konsoli programu . Aby uzyskać szczegółowe wyjaśnienie kodu, zobacz sekcję wyjaśniającą kod .

Przykładowy kod w tym przewodniku Szybki start używa identyfikatora Entra firmy Microsoft do zalecanego uwierzytelniania bez klucza. Jeśli wolisz użyć klucza interfejsu API, możesz zastąpić DefaultAzureCredential obiekt obiektem AzureKeyCredential .

String searchServiceEndpoint = "https://<Put your search service NAME here>.search.windows.net/";
DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();
  1. Utwórz nowy plik o nazwie App.java i wklej następujący kod do App.java:

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

    import com.azure.search.documents.indexes.SearchableField;
    import com.azure.search.documents.indexes.SimpleField;
    import com.fasterxml.jackson.annotation.JsonInclude;
    import com.fasterxml.jackson.annotation.JsonProperty;
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.annotation.JsonInclude.Include;
    
    import java.time.OffsetDateTime;
    
    /**
     * Model class representing a hotel.
     */
    @JsonInclude(Include.NON_NULL)
    public class Hotel {
        /**
         * Hotel ID
         */
        @JsonProperty("HotelId")
        @SimpleField(isKey = true)
        public String hotelId;
    
        /**
         * Hotel name
         */
        @JsonProperty("HotelName")
        @SearchableField(isSortable = true)
        public String hotelName;
    
        /**
         * Description
         */
        @JsonProperty("Description")
        @SearchableField(analyzerName = "en.microsoft")
        public String description;
    
        /**
         * Category
         */
        @JsonProperty("Category")
        @SearchableField(isFilterable = true, isSortable = true, isFacetable = true)
        public String category;
    
        /**
         * Tags
         */
        @JsonProperty("Tags")
        @SearchableField(isFilterable = true, isFacetable = true)
        public String[] tags;
    
        /**
         * Whether parking is included
         */
        @JsonProperty("ParkingIncluded")
        @SimpleField(isFilterable = true, isSortable = true, isFacetable = true)
        public Boolean parkingIncluded;
    
        /**
         * Last renovation time
         */
        @JsonProperty("LastRenovationDate")
        @SimpleField(isFilterable = true, isSortable = true, isFacetable = true)
        public OffsetDateTime lastRenovationDate;
    
        /**
         * Rating
         */
        @JsonProperty("Rating")
        @SimpleField(isFilterable = true, isSortable = true, isFacetable = true)
        public Double rating;
    
        /**
         * Address
         */
        @JsonProperty("Address")
        public Address address;
    
        @Override
        public String toString()
        {
            try
            {
                return new ObjectMapper().writeValueAsString(this);
            }
            catch (JsonProcessingException e)
            {
                e.printStackTrace();
                return "";
            }
        }
    }
    
  3. Utwórz nowy plik o nazwie Address.java i wklej następujący kod do Address.java:

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

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

Wyjaśnienie kodu

W poprzednich sekcjach utworzono nową aplikację konsolową i zainstalowano bibliotekę klienta usługi Azure AI Search. Dodano kod umożliwiający utworzenie indeksu wyszukiwania, załadowanie go za pomocą dokumentów i uruchomienie zapytań. Uruchomiono program, aby wyświetlić wyniki w konsoli programu .

W tej sekcji wyjaśnimy kod dodany do aplikacji konsolowej.

Tworzenie klienta wyszukiwania

W App.java utworzono dwóch klientów:

  • Element SearchIndexClient tworzy indeks.
  • Element SearchClient ładuje istniejący indeks i wykonuje zapytanie względem istniejącego indeksu.

Oba klienci potrzebują punktu końcowego usługi wyszukiwania i poświadczeń opisanych wcześniej w sekcji informacji o zasobie.

Przykładowy kod w tym przewodniku Szybki start używa identyfikatora Entra firmy Microsoft do zalecanego uwierzytelniania bez klucza. Jeśli wolisz użyć klucza interfejsu API, możesz zastąpić DefaultAzureCredential obiekt obiektem 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 . . . 
}

Tworzenie indeksu

Ten przewodnik Szybki start tworzy indeks Hotels ładowany przy użyciu danych hotelowych i wykonywania zapytań względem. W tym kroku zdefiniujesz pola w indeksie. Każda definicja pola zawiera nazwę, typ danych i atrybuty określające sposób użycia pola.

W tym przykładzie metody synchroniczne biblioteki Azure.Search.Documents są używane dla uproszczenia i czytelności. Jednak w przypadku scenariuszy produkcyjnych należy użyć metod asynchronicznych, aby zapewnić skalowalność i elastyczność aplikacji. Na przykład należy użyć polecenia CreateIndexAsync zamiast polecenia CreateIndex.

Definiowanie struktur

Utworzono dwie klasy pomocnicze, Hotel.java i Address.java, aby zdefiniować strukturę dokumentu hotelowego i jego adres. Klasa Hotel zawiera pola dla identyfikatora hotelu, nazwy, opisu, kategorii, tagów, parkingu, daty renowacji, oceny i adresu. Klasa Address zawiera pola dla adresu ulicznego, miasta, stanu/prowincji, kodu pocztowego i kraju/regionu.

W bibliotece klienta Azure.Search.Documents można użyć pól SearchableField i SimpleField , aby usprawnić definicje pól.

  • SimpleField może być dowolnym typem danych, jest zawsze niemożliwy do przeszukiwania (ignorowany w przypadku zapytań wyszukiwania pełnotekstowego) i jest pobierany (nie jest ukryty). Inne atrybuty są domyślnie wyłączone, ale można je włączyć. Możesz użyć pola SimpleField dla identyfikatorów dokumentów lub pól używanych tylko w filtrach, aspektach lub profilach oceniania. Jeśli tak, pamiętaj, aby zastosować wszelkie atrybuty, które są niezbędne dla scenariusza, takie jak IsKey = true dla identyfikatora dokumentu.
  • SearchableField musi być ciągiem i zawsze można wyszukiwać i pobierać. Inne atrybuty są domyślnie wyłączone, ale można je włączyć. Ponieważ ten typ pola można wyszukiwać, obsługuje synonimy i pełne uzupełnienie właściwości analizatora.

Niezależnie od tego, czy używasz podstawowego SearchField interfejsu API, czy jednego z modeli pomocnika, musisz jawnie włączyć atrybuty filtru, aspektu i sortowania. Na przykład isFilterable, isSortablei isFacetable muszą być jawnie przypisane, jak pokazano w poprzednim przykładzie.

Tworzenie indeksu wyszukiwania

W App.javapliku utworzysz SearchIndex obiekt w metodzie main , a następnie wywołaj createOrUpdateIndex metodę , aby utworzyć indeks w usłudze wyszukiwania. Indeks zawiera również element umożliwiający SearchSuggester włączenie autouzupełniania w określonych polach.

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

Ładowanie dokumentów

Usługa Azure AI Search wyszukuje zawartość przechowywaną w usłudze. W tym kroku załadujesz dokumenty JSON zgodne z utworzonym indeksem hotelowym.

W usłudze Azure AI Search dokumenty wyszukiwania to struktury danych, które są danymi wejściowymi do indeksowania i danych wyjściowych z zapytań. Dane wejściowe dokumentu uzyskane z zewnętrznego źródła danych mogą być wierszami w bazie danych, obiektami blob w usłudze Blob Storage lub dokumentami JSON na dysku. W tym przykładzie używamy skrótu i osadzamy dokumenty JSON dla czterech hoteli w samym kodzie.

Podczas przekazywania dokumentów należy użyć obiektu IndexDocumentsBatch . Obiekt IndexDocumentsBatch zawiera kolekcję indeksów, z których każda zawiera dokument i właściwość informującą usługę Azure AI Search o tym, jaką akcję należy wykonać (przekazywanie, scalanie, usuwanie i scalanieOrUpload).

W App.javaprogramie tworzysz dokumenty i akcje indeksu, a następnie przekazujesz je do IndexDocumentsBatchelementu . Następujące dokumenty są zgodne z indeksem hotels-quickstart zdefiniowanym przez klasę hotelową.

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

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

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

Po zainicjowaniu obiektu można wysłać go do indeksu IndexDocumentsBatch , wywołując element indexDocuments w SearchClient obiekcie.

Dokumenty są ładowane przy użyciu elementu SearchClient w main()programie , ale operacja wymaga również uprawnień administratora w usłudze, która jest zwykle skojarzona z elementem SearchIndexClient. Jednym ze sposobów skonfigurowania tej operacji jest pobranie elementu SearchClient za pośrednictwem SearchIndexClient (searchIndexClient w tym przykładzie).

uploadDocuments(searchClient);

Ponieważ mamy aplikację konsolową, która uruchamia wszystkie polecenia sekwencyjnie, dodamy 2-sekundowy czas oczekiwania między indeksowaniem a zapytaniami.

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

2-sekundowe opóźnienie rekompensuje indeksowanie, co jest asynchroniczne, dzięki czemu wszystkie dokumenty można indeksować przed wykonaniem zapytań. Kodowanie w opóźnieniu jest zwykle konieczne tylko w przypadku pokazów, testów i przykładowych aplikacji.

Przeszukiwanie indeksu

Wyniki zapytania można uzyskać zaraz po indeksowanym pierwszym dokumencie, ale rzeczywiste testowanie indeksu powinno poczekać, aż wszystkie dokumenty zostaną zindeksowane.

W tej sekcji dodano dwie funkcje: logikę zapytań i wyniki. W przypadku zapytań użyj metody Search. Ta metoda przyjmuje tekst wyszukiwania (ciąg zapytania) i inne opcje.

W App.javapliku WriteDocuments metoda wyświetla wyniki wyszukiwania w konsoli programu .

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

Przykład zapytania 1

Metoda RunQueries wykonuje zapytania i zwraca wyniki. Wyniki to obiekty hotelowe. W tym przykładzie przedstawiono podpis metody i pierwsze zapytanie. To zapytanie demonstruje Select parametr, który umożliwia tworzenie wyniku przy użyciu wybranych pól 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));
}

Przykład zapytania 2

W drugim zapytaniu wyszukaj termin, dodaj filtr, który wybiera dokumenty, w których ocena jest większa niż 4, a następnie sortuj według klasyfikacji w kolejności malejącej. Filter jest wyrażeniem logicznym, które jest obliczane względem isFilterable pól w indeksie. Filtrowanie zapytań obejmuje lub wyklucza wartości. W związku z tym nie ma wskaźnika istotności skojarzonego z zapytaniem 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));

Przykład zapytania 3

Trzecie zapytanie demonstruje searchFieldsmetodę , używaną do określania zakresu operacji wyszukiwania pełnotekstowego do określonych pól.

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

Przykład zapytania 4

Czwarte zapytanie demonstruje facetsmetodę , która może służyć do struktury struktury nawigacji aspektowej.

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

Przykład zapytania 5

W piątym zapytaniu zwróć określony 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();

Przykład zapytania 6

Ostatnie zapytanie pokazuje składnię autouzupełniania, s, która rozwiązuje dwa możliwe dopasowania w sourceFields skojarzonym z sugerowanym elementem zdefiniowanym w indeksie.

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

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

Podsumowanie zapytań

Poprzednie zapytania pokazują wiele sposobów dopasowywania terminów w zapytaniu: wyszukiwanie pełnotekstowe, filtry i autouzupełnianie.

Wyszukiwanie pełnotekstowe i filtry są wykonywane przy użyciu metody SearchClient.search . Zapytanie wyszukiwania można przekazać w searchText ciągu, a wyrażenie filtru można przekazać we filter właściwości klasy SearchOptions . Aby filtrować bez wyszukiwania, wystarczy przekazać wartość "*" dla searchText parametru search metody . Aby wyszukać bez filtrowania, pozostaw filter właściwość niezastawioną lub nie przekazuj SearchOptions w ogóle wystąpienia.

W przewodniku szybkiego startu użyjesz biblioteki klienta Azure.Search.Documents do tworzenia, ładowania i wykonywania zapytań względem indeksu wyszukiwania z przykładowymi danymi na potrzeby wyszukiwania pełnotekstowego. Wyszukiwanie pełnotekstowe używa platformy Apache Lucene do indeksowania i zapytań oraz algorytmu klasyfikacji BM25 na potrzeby oceniania wyników.

Ten przewodnik szybkiego startu używa fikcyjnych danych hotelowych z repozytorium azure-search-sample-data, aby wypełnić indeks.

Napiwek

Możesz pobrać kod źródłowy , aby rozpocząć od ukończonego projektu lub wykonać następujące kroki, aby utworzyć własny.

Wymagania wstępne

  • Konto Azure z aktywną subskrypcją. Utwórz konto bezpłatnie.

  • Usługa wyszukiwania sztucznej inteligencji platformy Azure. Utwórz usługę , jeśli jej nie masz. Możesz skorzystać z bezpłatnej usługi w ramach szybkiego startu.

Wymagania wstępne dotyczące identyfikatora entra firmy Microsoft

W przypadku zalecanego uwierzytelniania bez klucza za pomocą identyfikatora Entra firmy Microsoft należy:

Pobieranie informacji o zasobie

Aby uwierzytelnić aplikację przy użyciu usługi Azure AI usługa wyszukiwania, należy pobrać następujące informacje:

Nazwa zmiennej Wartość
SEARCH_API_ENDPOINT Tę wartość można znaleźć w witrynie Azure Portal. Wybierz usługę wyszukiwania, a następnie z menu po lewej stronie wybierz pozycję Przegląd. Wartość adresu URL w obszarze Podstawy to potrzebny punkt końcowy. Przykładowy punkt końcowy może wyglądać podobnie jak https://mydemo.search.windows.net.

Dowiedz się więcej na temat uwierzytelniania bez klucza i ustawiania zmiennych środowiskowych.

Konfiguruj

  1. Utwórz nowy folder full-text-quickstart zawierający aplikację i otwórz program Visual Studio Code w tym folderze za pomocą następującego polecenia:

    mkdir full-text-quickstart && cd full-text-quickstart
    
  2. Utwórz element package.json za pomocą następującego polecenia:

    npm init -y
    
  3. Zainstaluj bibliotekę klienta usługi Azure AI Search (Azure.Search.Documents) dla języka JavaScript za pomocą następujących elementów:

    npm install @azure/search-documents
    
  4. W przypadku zalecanego uwierzytelniania bez hasła zainstaluj bibliotekę klienta tożsamości platformy Azure za pomocą polecenia:

    npm install @azure/identity
    

Tworzenie, ładowanie i wykonywanie zapytań względem indeksu wyszukiwania

W poprzedniej sekcji konfiguracji zainstalowano bibliotekę klienta usługi Azure AI Search i inne zależności.

W tej sekcji dodasz kod, aby utworzyć indeks wyszukiwania, załadować go przy użyciu dokumentów i uruchomić zapytania. Uruchom program, aby wyświetlić wyniki w konsoli programu . Aby uzyskać szczegółowe wyjaśnienie kodu, zobacz sekcję wyjaśniającą kod .

Przykładowy kod w tym przewodniku Szybki start używa identyfikatora Entra firmy Microsoft do zalecanego uwierzytelniania bez klucza. Jeśli wolisz użyć klucza interfejsu API, możesz zastąpić DefaultAzureCredential obiekt obiektem AzureKeyCredential .

String searchServiceEndpoint = "https://<Put your search service NAME here>.search.windows.net/";
DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();
  1. Utwórz nowy plik o nazwie index.js i wklej następujący kod do index.js:

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

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

    {
    	"name": "hotels-quickstart",
    	"fields": [
    		{
    			"name": "HotelId",
    			"type": "Edm.String",
    			"key": true,
    			"filterable": true
    		},
    		{
    			"name": "HotelName",
    			"type": "Edm.String",
    			"searchable": true,
    			"filterable": false,
    			"sortable": true,
    			"facetable": false
    		},
    		{
    			"name": "Description",
    			"type": "Edm.String",
    			"searchable": true,
    			"filterable": false,
    			"sortable": false,
    			"facetable": false,
    			"analyzerName": "en.lucene"
    		},
    		{
    			"name": "Category",
    			"type": "Edm.String",
    			"searchable": true,
    			"filterable": true,
    			"sortable": true,
    			"facetable": true
    		},
    		{
    			"name": "Tags",
    			"type": "Collection(Edm.String)",
    			"searchable": true,
    			"filterable": true,
    			"sortable": false,
    			"facetable": true
    		},
    		{
    			"name": "ParkingIncluded",
    			"type": "Edm.Boolean",
    			"filterable": true,
    			"sortable": true,
    			"facetable": true
    		},
    		{
    			"name": "LastRenovationDate",
    			"type": "Edm.DateTimeOffset",
    			"filterable": true,
    			"sortable": true,
    			"facetable": true
    		},
    		{
    			"name": "Rating",
    			"type": "Edm.Double",
    			"filterable": true,
    			"sortable": true,
    			"facetable": true
    		},
    		{
    			"name": "Address",
    			"type": "Edm.ComplexType",
    			"fields": [
    				{
    					"name": "StreetAddress",
    					"type": "Edm.String",
    					"filterable": false,
    					"sortable": false,
    					"facetable": false,
    					"searchable": true
    				},
    				{
    					"name": "City",
    					"type": "Edm.String",
    					"searchable": true,
    					"filterable": true,
    					"sortable": true,
    					"facetable": true
    				},
    				{
    					"name": "StateProvince",
    					"type": "Edm.String",
    					"searchable": true,
    					"filterable": true,
    					"sortable": true,
    					"facetable": true
    				},
    				{
    					"name": "PostalCode",
    					"type": "Edm.String",
    					"searchable": true,
    					"filterable": true,
    					"sortable": true,
    					"facetable": true
    				},
    				{
    					"name": "Country",
    					"type": "Edm.String",
    					"searchable": true,
    					"filterable": true,
    					"sortable": true,
    					"facetable": true
    				}
    			]
    		}
    	],
    	"suggesters": [
    		{
    			"name": "sg",
    			"searchMode": "analyzingInfixMatching",
    			"sourceFields": [
    				"HotelName"
    			]
    		}
    	]
    }
    
  4. Zaloguj się do platformy Azure przy użyciu następującego polecenia:

    az login
    
  5. Uruchom kod JavaScript za pomocą następującego polecenia:

    node index.js
    

Wyjaśnienie kodu

tworzenie indeksu

Plik hotels_quickstart_index.json definiuje sposób działania usługi Azure AI Search z dokumentami ładowanymi w następnym kroku. Każde pole jest identyfikowane przez element name i ma określony element type. Każde pole ma również szereg atrybutów indeksu, które określają, czy usługa Azure AI Search może wyszukiwać, filtrować, sortować i aspekty po polu. Większość pól to proste typy danych, ale niektóre, takie jak AddressType typy złożone, które umożliwiają tworzenie rozbudowanych struktur danych w indeksie. Więcej informacji na temat obsługiwanych typów danych i atrybutów indeksu opisano w artykule Create Index (REST) (Tworzenie indeksu (REST).

W naszej definicji indeksu chcemy zaimportować hotels_quickstart_index.json w górnej części index.js , aby funkcja główna mogła uzyskać dostęp do definicji indeksu.

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

W ramach funkcji main utworzymy element SearchIndexClient, który służy do tworzenia indeksów usługi Azure AI Search i zarządzania nimi.

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

Następnie chcemy usunąć indeks, jeśli już istnieje. Ta operacja jest powszechną praktyką w przypadku kodu testowego/demonstracyjnego.

Robimy to, definiując prostą funkcję, która próbuje usunąć indeks.

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

Aby uruchomić funkcję, wyodrębniamy nazwę indeksu z definicji indeksu i przekazujemy indexName element wraz z funkcją indexClientdeleteIndexIfExists() .

const indexName = indexDefinition["name"];

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

Następnie możemy utworzyć indeks za pomocą createIndex() metody .

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

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

Ładowanie dokumentów

W usłudze Azure AI Search dokumenty to struktury danych, które są danymi wejściowymi do indeksowania i danych wyjściowych z zapytań. Możesz wypchnąć takie dane do indeksu lub użyć indeksatora. W takim przypadku programowo wypchniemy dokumenty do indeksu.

Dane wejściowe dokumentu mogą być wierszami w bazie danych, obiektach blob w usłudze Blob Storage lub, jak w tym przykładzie, dokumentach JSON na dysku. Podobnie jak indexDefinitionw przypadku elementu , musimy również zaimportować hotels.json w górnej części index.js , aby można było uzyskać dostęp do danych w naszej funkcji głównej.

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

Aby zaindeksować dane do indeksu wyszukiwania, musimy teraz utworzyć element SearchClient. SearchIndexClient Element służy do tworzenia indeksu i zarządzania nim, SearchClient ale służy do przekazywania dokumentów i wykonywania zapytań względem indeksu.

Istnieją dwa sposoby tworzenia elementu SearchClient. Pierwszą opcją jest utworzenie od SearchClient podstaw:

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

Alternatywnie możesz użyć getSearchClient() metody , SearchIndexClient aby utworzyć element SearchClient:

const searchClient = indexClient.getSearchClient(indexName);

Teraz, gdy klient jest zdefiniowany, przekaż dokumenty do indeksu wyszukiwania. W takim przypadku używamy mergeOrUploadDocuments() metody , która przekazuje dokumenty lub scala je z istniejącym dokumentem, jeśli dokument o tym samym kluczu już istnieje.

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

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

Przeszukiwanie indeksu

Po przekazaniu indeksu i przekazaniu dokumentów możesz wysyłać zapytania do indeksu. W tej sekcji wysyłamy pięć różnych zapytań do indeksu wyszukiwania, aby zademonstrować różne dostępne funkcje zapytań.

Zapytania są zapisywane w sendQueries() funkcji, którą wywołujemy w funkcji main w następujący sposób:

await sendQueries(searchClient);

Zapytania są wysyłane przy użyciu search() metody searchClient. Pierwszy parametr to tekst wyszukiwania, a drugi parametr określa opcje wyszukiwania.

Przykład zapytania 1

Pierwsze zapytanie wyszukuje *element , który jest odpowiednikiem wyszukiwania wszystkiego i wybiera trzy pola w indeksie. Jest to najlepsze rozwiązanie tylko select dla potrzebnych pól, ponieważ ściąganie niepotrzebnych danych może powodować opóźnienie zapytań.

Dla searchOptions tego zapytania ustawiono includeTotalCount również wartość true, która zwraca liczbę znalezionych pasujących wyników.

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
}

Pozostałe zapytania opisane poniżej należy również dodać do sendQueries() funkcji. Są one tutaj oddzielone w celu czytelności.

Przykład zapytania 2

W następnym zapytaniu określamy termin "wifi" wyszukiwania, a także uwzględniamy filtr, aby zwracać wyniki tylko wtedy, gdy stan jest równy 'FL'. Wyniki są również uporządkowane przez hotel 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)}`);
}

Przykład zapytania 3

Następnie wyszukiwanie jest ograniczone do pojedynczego pola z możliwością wyszukiwania przy użyciu parametru searchFields . Takie podejście jest doskonałym rozwiązaniem, aby zwiększyć wydajność zapytania, jeśli wiesz, że interesuje Cię tylko dopasowanie w niektórych polach.

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

Przykład zapytania 4

Inną typową opcją uwzględnienia w zapytaniu jest facets. Aspekty umożliwiają tworzenie filtrów w interfejsie użytkownika, aby ułatwić użytkownikom poznanie wartości, do których mogą filtrować.

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

Przykład zapytania 5

Ostatnie zapytanie używa getDocument() metody searchClient. Dzięki temu można efektywnie pobierać dokument przy użyciu jego klucza.

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

Podsumowanie zapytań

Poprzednie zapytania pokazują wiele sposobów dopasowywania terminów w zapytaniu: wyszukiwanie pełnotekstowe, filtry i autouzupełnianie.

Wyszukiwanie pełnotekstowe i filtry są wykonywane przy użyciu searchClient.search metody . Zapytanie wyszukiwania można przekazać w searchText ciągu, podczas gdy wyrażenie filtru może zostać przekazane we filter właściwości SearchOptions klasy. Aby filtrować bez wyszukiwania, wystarczy przekazać wartość "*" dla searchText parametru search metody . Aby wyszukać bez filtrowania, pozostaw filter właściwość niezastawioną lub nie przekazuj SearchOptions w ogóle wystąpienia.

W tym szybkim starcie użyjesz programu PowerShell i interfejsów API REST usługi Azure AI Search do tworzenia, ładowania i wykonywania zapytań względem indeksu wyszukiwania do wyszukiwania pełnotekstowego. Wyszukiwanie pełnotekstowe używa platformy Apache Lucene do indeksowania i zapytań oraz algorytmu klasyfikacji BM25 na potrzeby oceniania wyników.

Ten przewodnik szybkiego startu używa fikcyjnych danych hotelowych z azure-search-sample-data do wypełnienia indeksu.

Napiwek

Możesz pobrać kod źródłowy , aby rozpocząć od ukończonego projektu lub wykonać następujące kroki, aby utworzyć własny.

Wymagania wstępne

Konfigurowanie dostępu

Można nawiązać połączenie z usługą Azure AI Search przy użyciu kluczy API lub Microsoft Entra ID wraz z przypisaniami ról. Klucze są łatwiejsze do rozpoczęcia od, ale role są bezpieczniejsze.

Aby skonfigurować zalecany dostęp oparty na rolach:

  1. Zaloguj się do witryny Azure Portal i wybierz usługę wyszukiwania.

  2. W okienku po lewej stronie wybierz Ustawienia>Klucze.

  3. W obszarze Kontrola dostępu do interfejsu API wybierz pozycję Oba.

    Ta opcja umożliwia zarówno uwierzytelnianie oparte na kluczach, jak i bez klucza. Po przypisaniu ról możesz wrócić do tego kroku i wybrać pozycję Kontrola dostępu oparta na rolach.

  4. W okienku po lewej stronie wybierz pozycję Kontrola dostępu (Zarządzanie dostępem i tożsamościami).

  5. Wybierz Dodaj>Dodaj przypisanie roli.

  6. Przypisz role Współautor usługi wyszukiwania i Współautor danych indeksu wyszukiwania do konta użytkownika.

Aby uzyskać więcej informacji, zobacz Nawiązywanie połączenia z usługą Azure AI Search przy użyciu ról.

Pobierz punkt końcowy

W następnej sekcji określisz następujący punkt końcowy, aby nawiązać połączenie z usługą Azure AI Search. W tych krokach przyjęto założenie, że skonfigurowano dostęp oparty na rolach.

Aby uzyskać punkt końcowy usługi:

  1. Zaloguj się do witryny Azure Portal i wybierz usługę wyszukiwania.

  2. W okienku po lewej stronie wybierz pozycję Przegląd.

  3. Zanotuj adres URL, który powinien być podobny do https://my-service.search.windows.net.

Aby móc wykonywać wywołania interfejsu API REST do usługi Azure AI Search, musisz uwierzytelnić się i nawiązać połączenie z usługą. W programie PowerShell wykonasz następujące kroki, które obsługują polecenia interfejsu wiersza polecenia platformy Azure używane w krokach dwóch i trzech.

Aby nawiązać połączenie z usługą wyszukiwania:

  1. W systemie lokalnym otwórz program PowerShell.

  2. Zaloguj się do subskrypcji platformy Azure. Jeśli masz wiele subskrypcji, wybierz tę, która zawiera usługę wyszukiwania.

    az login
    
  3. Utwórz $token obiekt do przechowywania tokenu dostępu.

    $token = az account get-access-token --resource https://search.azure.com/ --query accessToken --output tsv
    
  4. $headers Utwórz obiekt do przechowywania tokenu i typu zawartości.

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

    Musisz ustawić nagłówek tylko raz na sesję, ale musisz dodać go do każdego żądania.

  5. $url Utwórz obiekt przeznaczony dla kolekcji indeksów w usłudze wyszukiwania. Zastąp <YOUR-SEARCH-SERVICE> wartością uzyskaną w funkcji Uzyskiwanie punktu końcowego.

    $url = "<YOUR-SEARCH-SERVICE>/indexes?api-version=2024-07-01&`$select=name"
    
  6. Uruchom polecenie Invoke-RestMethod , aby wysłać żądanie GET do usługi wyszukiwania. Dołącz ConvertTo-Json, aby wyświetlić odpowiedzi z usługi.

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

    Jeśli usługa jest pusta i nie ma indeksów, odpowiedź jest podobna do poniższego przykładu. W przeciwnym razie zostanie wyświetlona reprezentacja definicji indeksu w formacie JSON.

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

Tworzenie indeksu wyszukiwania

Przed dodaniem zawartości do usługi Azure AI Search należy utworzyć indeks, aby zdefiniować sposób przechowywania i struktury zawartości. Indeks jest koncepcyjnie podobny do tabeli w relacyjnej bazie danych, ale został specjalnie zaprojektowany pod kątem operacji wyszukiwania, takich jak wyszukiwanie pełnotekstowe.

Uruchom następujące polecenia w tej samej sesji programu PowerShell, która została uruchomiona w poprzedniej sekcji.

Aby utworzyć indeks:

  1. Stwórz obiekt $body do zdefiniowania schematu indeksu.

    $body = @"
    {
        "name": "hotels-quickstart",  
        "fields": [
            {"name": "HotelId", "type": "Edm.String", "key": true, "filterable": true},
            {"name": "HotelName", "type": "Edm.String", "searchable": true, "filterable": false, "sortable": true, "facetable": false},
            {"name": "Description", "type": "Edm.String", "searchable": true, "filterable": false, "sortable": false, "facetable": false, "analyzer": "en.lucene"},
            {"name": "Category", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true},
            {"name": "Tags", "type": "Collection(Edm.String)", "searchable": true, "filterable": true, "sortable": false, "facetable": true},
            {"name": "ParkingIncluded", "type": "Edm.Boolean", "filterable": true, "sortable": true, "facetable": true},
            {"name": "LastRenovationDate", "type": "Edm.DateTimeOffset", "filterable": true, "sortable": true, "facetable": true},
            {"name": "Rating", "type": "Edm.Double", "filterable": true, "sortable": true, "facetable": true},
            {"name": "Address", "type": "Edm.ComplexType", 
                "fields": [
                {"name": "StreetAddress", "type": "Edm.String", "filterable": false, "sortable": false, "facetable": false, "searchable": true},
                {"name": "City", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true},
                {"name": "StateProvince", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true},
                {"name": "PostalCode", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true},
                {"name": "Country", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true}
            ]
         }
      ]
    }
    "@
    
  2. Zaktualizuj obiekt, $url aby był przeznaczony dla nowego indeksu. Zastąp <YOUR-SEARCH-SERVICE> wartością uzyskaną w funkcji Uzyskiwanie punktu końcowego.

    $url = "<YOUR-SEARCH-SERVICE>/indexes/hotels-quickstart?api-version=2024-07-01"
    
  3. Uruchom polecenie Invoke-RestMethod , aby utworzyć indeks w usłudze wyszukiwania.

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

    Odpowiedź powinna zawierać reprezentację JSON schematu indeksu.

Informacje o żądaniu tworzenia indeksu

Ten szybki start wywołuje Indeksy - Tworzenie (interfejs API REST) aby utworzyć indeks wyszukiwania o nazwie hotels-quickstart i jego fizycznych struktur danych w usłudze wyszukiwania.

W schemacie indeksu, kolekcja fields definiuje strukturę dokumentów hotelowych. Każde pole ma name, dane type i atrybuty, które określają jego zachowanie podczas indeksowania i zapytań. Pole HotelId jest oznaczone jako klucz, którego usługa Azure AI Search wymaga unikatowego identyfikowania każdego dokumentu w indeksie.

Kluczowe kwestie dotyczące schematu indeksu:

  • Użyj pól ciągu (Edm.String), aby umożliwić wyszukiwanie pełnotekstowe danych liczbowych. Inne obsługiwane typy danych, takie jak Edm.Int32, są filtrowalne, sortowalne, ustawialne jako facety i możliwe do pobrania, ale nie da się ich przeszukiwać.

  • Większość naszych pól to proste typy danych, ale można zdefiniować złożone typy reprezentujące zagnieżdżone dane, takie jak Address pole.

  • Atrybuty pól określają dozwolone akcje. Interfejsy API REST domyślnie zezwalają na wiele akcji. Na przykład wszystkie ciągi można wyszukiwać i pobierać. W przypadku interfejsów API REST można używać atrybutów tylko wtedy, gdy trzeba wyłączyć zachowanie.

Ładowanie indeksu

Nowo utworzone indeksy są puste. Aby wypełnić indeks i umożliwić wyszukiwanie, należy przekazać dokumenty JSON zgodne ze schematem indeksu.

W usłudze Azure AI Search dokumenty służą zarówno jako dane wejściowe do indeksowania, jak i danych wyjściowych zapytań. Dla uproszczenia ten przewodnik szybkiego startu zawiera przykładowe dokumenty hotelowe jako inline JSON. Jednak w scenariuszach produkcyjnych zawartość jest często pobierana z połączonych źródeł danych i przekształcana w format JSON przy użyciu indeksatorów.

Aby załadować dokumenty do swojego indeksu:

  1. $body Utwórz obiekt do przechowywania ładunku JSON czterech przykładowych dokumentów.

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

    $url = "<YOUR-SEARCH-SERVICE>/indexes/hotels-quickstart/docs/index?api-version=2024-07-01"
    
  3. Uruchom Invoke-RestMethod, aby wysłać żądanie przesłania do usługi wyszukiwania.

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

    Odpowiedź powinna zawierać klucz i stan każdego przekazanego dokumentu.

Informacje o żądaniu ładowania

W tym przewodniku Szybki start wywoływane są dokumenty — indeks (interfejs API REST), aby dodać do indeksu cztery przykładowe dokumenty hotelowe. W porównaniu z poprzednim żądaniem URI jest rozszerzony, aby uwzględniać kolekcję docs i operację index.

Każdy dokument w tablicy value reprezentuje hotel i zawiera pola zgodne ze schematem indeksu. Parametr @search.action określa operację do wykonania dla każdego dokumentu. W naszym przykładzie użyto elementu upload, który dodaje dokument, jeśli nie istnieje lub aktualizuje dokument, jeśli istnieje.

Wykonywanie zapytań względem indeksu

Teraz, gdy dokumenty są ładowane do indeksu, możesz użyć wyszukiwania pełnotekstowego, aby znaleźć określone terminy lub frazy w swoich polach.

Aby uruchomić zapytanie pełnotekstowe względem indeksu:

  1. Zaktualizuj obiekt, $url aby określić parametry wyszukiwania. Zastąp <YOUR-SEARCH-SERVICE> wartością uzyskaną w funkcji Uzyskiwanie punktu końcowego.

    $url = '<YOUR-SEARCH-SERVICE>/indexes/hotels-quickstart/docs?api-version=2024-07-01&search=attached restaurant&searchFields=Description,Tags&$select=HotelId,HotelName,Tags,Description&$count=true'
    
  2. Uruchom polecenie Invoke-RestMethod , aby wysłać żądanie zapytania do usługi wyszukiwania.

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

    Odpowiedź powinna być podobna do poniższego przykładu, która pokazuje jeden pasujący dokument hotelowy, jego wynik istotności i wybrane pola.

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

Informacje o żądaniu zapytania

Ta instrukcja szybkiego startu wywołuje metodę POST wyszukiwania w interfejsie API REST, aby znaleźć dokumenty hotelowe spełniające kryteria wyszukiwania. Identyfikator URI nadal jest przeznaczony dla docs kolekcji, ale już nie zawiera operacji index.

Żądania wyszukiwania pełnotekstowego search zawsze zawierają parametr zawierający tekst zapytania. Tekst zapytania może zawierać co najmniej jeden termin, frazy lub operatory. Oprócz search, można określić inne parametry, aby uściślić zachowanie wyszukiwania i wyniki.

Nasze zapytanie wyszukuje terminy "przyłączona restauracja" w polach Description i Tags każdego dokumentu hotelowego. Parametr $select ogranicza pola zwrócone w odpowiedzi do HotelId, HotelName, Tags i Description. Parametr $count żąda całkowitej liczby pasujących dokumentów.

Inne przykłady zapytań

Uruchom następujące polecenia, aby zapoznać się ze składnią zapytania. Możesz wykonywać wyszukiwania ciągów, używać $filter wyrażeń, ograniczać zestawy wyników, wybierać określone pola i nie tylko. Pamiętaj, aby zastąpić <YOUR-SEARCH-SERVICE> wartością uzyskaną w Pobierz punkt końcowy.

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

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

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

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

W tym przewodniku szybkiego startu użyjesz biblioteki klienta Azure.Search.Documents do tworzenia, ładowania i wykonywania zapytań względem indeksu wyszukiwania z przykładowymi danymi dla wyszukiwania pełnotekstowego. Wyszukiwanie pełnotekstowe używa platformy Apache Lucene do indeksowania i zapytań oraz algorytmu klasyfikacji BM25 na potrzeby oceniania wyników.

W tym przewodniku Quickstart używane są fikcyjne dane hotelowe z repozytorium azure-search-sample-data w celu zasilenia indeksu.

Napiwek

Możesz pobrać i uruchomić gotowy notes.

Wymagania wstępne

Wymagania wstępne dotyczące identyfikatora entra firmy Microsoft

W przypadku zalecanego uwierzytelniania bez klucza za pomocą identyfikatora Entra firmy Microsoft należy:

Pobieranie informacji o zasobie

Aby uwierzytelnić aplikację przy użyciu usługi Azure AI usługa wyszukiwania, należy pobrać następujące informacje:

Nazwa zmiennej Wartość
SEARCH_API_ENDPOINT Tę wartość można znaleźć w witrynie Azure Portal. Wybierz usługę wyszukiwania, a następnie z menu po lewej stronie wybierz pozycję Przegląd. Wartość adresu URL w obszarze Podstawy to potrzebny punkt końcowy. Przykładowy punkt końcowy może wyglądać podobnie jak https://mydemo.search.windows.net.

Dowiedz się więcej na temat uwierzytelniania bez klucza i ustawiania zmiennych środowiskowych.

Konfigurowanie środowiska

Przykładowy kod jest uruchamiany w notesie Jupyter. Dlatego należy skonfigurować środowisko do uruchamiania notesów Jupyter.

  1. Pobierz lub skopiuj przykładowy notes z usługi GitHub.

  2. Otwórz notes w programie Visual Studio Code.

  3. Utwórz nowe środowisko języka Python, które ma być używane do instalowania pakietów potrzebnych na potrzeby tego samouczka.

    Ważne

    Nie instaluj pakietów w globalnej instalacji języka Python. Zawsze należy używać środowiska wirtualnego lub conda podczas instalowania pakietów języka Python. W przeciwnym razie możesz przerwać globalną instalację języka Python.

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

    Skonfigurowanie może potrwać minutę. Jeśli wystąpią problemy, zobacz Środowiska języka Python w programie VS Code.

  4. Zainstaluj notesy Jupyter i jądro IPython dla notesów Jupyter, jeśli jeszcze ich nie masz.

    pip install jupyter
    pip install ipykernel
    python -m ipykernel install --user --name=.venv
    
  5. Wybierz jądro notesu.

    1. W prawym górnym rogu notesu wybierz pozycję Wybierz jądro.
    2. Jeśli widzisz .venv ją na liście, wybierz ją. Jeśli go nie widzisz, wybierz pozycję

Tworzenie, ładowanie i wykonywanie zapytań względem indeksu wyszukiwania

W tej sekcji dodasz kod, aby utworzyć indeks wyszukiwania, załadować go przy użyciu dokumentów i uruchomić zapytania. Uruchom program, aby wyświetlić wyniki w konsoli programu . Aby uzyskać szczegółowe wyjaśnienie kodu, zobacz sekcję wyjaśniającą kod .

  1. Upewnij się, że notes jest otwarty w .venv jądrze zgodnie z opisem w poprzedniej sekcji.

  2. Uruchom pierwszą komórkę kodu, aby zainstalować wymagane pakiety, w tym azure-search-documents.

    ! pip install azure-search-documents==11.6.0b1 --quiet
    ! pip install azure-identity --quiet
    ! pip install python-dotenv --quiet
    
  3. Zastąp zawartość drugiej komórki kodu następującym kodem w zależności od metody uwierzytelniania.

    Uwaga

    Przykładowy kod w tym przewodniku Szybki start używa identyfikatora Entra firmy Microsoft do zalecanego uwierzytelniania bez klucza. Jeśli wolisz użyć klucza interfejsu API, możesz zastąpić DefaultAzureCredential obiekt obiektem 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. Usuń następujące dwa wiersze z komórki Tworzenie kodu indeksu . Poświadczenia są już ustawione w poprzedniej komórce kodu.

    from azure.core.credentials import AzureKeyCredential
    credential = AzureKeyCredential(search_api_key)
    
  5. Uruchom komórkę Tworzenie kodu indeksu , aby utworzyć indeks wyszukiwania.

  6. Uruchom pozostałe komórki kodu sekwencyjnie, aby załadować dokumenty i uruchomić zapytania.

Wyjaśnienie kodu

Tworzenie indeksu

SearchIndexClient służy do tworzenia indeksów usługi Azure AI Search i zarządzania nimi. Każde pole jest identyfikowane przez element name i ma określony element type.

Każde pole ma również szereg atrybutów indeksu, które określają, czy usługa Azure AI Search może wyszukiwać, filtrować, sortować i aspekty po polu. Większość pól to proste typy danych, ale niektóre, takie jak AddressType typy złożone, które umożliwiają tworzenie rozbudowanych struktur danych w indeksie. Więcej informacji na temat obsługiwanych typów danych i atrybutów indeksu opisano w artykule Create Index (REST) (Tworzenie indeksu (REST).

Tworzenie ładunku dokumentów i przekazywanie dokumentów

Użyj akcji indeksu dla typu operacji, takiej jak przekazywanie lub scalanie i przekazywanie. Dokumenty pochodzą z przykładu HotelsData w usłudze GitHub.

Przeszukiwanie indeksu

Wyniki zapytania można uzyskać zaraz po indeksowanym pierwszym dokumencie, ale rzeczywiste testowanie indeksu powinno poczekać, aż wszystkie dokumenty zostaną zindeksowane.

Użyj metody wyszukiwania klasy search.client.

Przykładowe zapytania w notesie to:

  • Zapytanie podstawowe: wykonuje puste wyszukiwanie (search=*), zwracając nies rankingową listę (wynik wyszukiwania = 1,0) dowolnych dokumentów. Ponieważ nie ma żadnych kryteriów, wszystkie dokumenty są uwzględniane w wynikach.
  • Zapytanie terminu: dodaje całe terminy do wyrażenia wyszukiwania ("wifi"). To zapytanie określa, że wyniki zawierają tylko te pola w instrukcji select . Ograniczenie pól, które wracają, minimalizuje ilość danych wysyłanych z powrotem przez sieć i zmniejsza opóźnienie wyszukiwania.
  • Zapytanie filtrowane: dodaj wyrażenie filtru, zwracając tylko te hotele z oceną większą niż cztery posortowane w kolejności malejącej.
  • Określanie zakresu pól: dodaj search_fields do zakresu wykonywania zapytań do określonych pól.
  • Aspekty: Generuj aspekty dla pozytywnych dopasowań znalezionych w wynikach wyszukiwania. Brak dopasowań zerowych. Jeśli wyniki wyszukiwania nie zawierają terminu wifi, sieć Wi-Fi nie jest wyświetlana w strukturze nawigacji aspektowej.
  • Wyszukaj dokument: Zwróć dokument na podstawie jego klucza. Ta operacja jest przydatna, jeśli chcesz podać przeglądanie szczegółowe, gdy użytkownik wybierze element w wynikach wyszukiwania.
  • Autouzupełnianie: podaj potencjalne dopasowania jako typy użytkowników w polu wyszukiwania. Autouzupełnianie używa sugestora (sg), aby wiedzieć, które pola zawierają potencjalne dopasowania do żądań sugestora. W tym przewodniku Szybki start te pola to Tags: , Address/CityAddress/Country. Aby symulować autouzupełnianie, przekaż litery sa jako ciąg częściowy. Metoda autouzupełniania elementu SearchClient wysyła potencjalne dopasowania terminów.

Usuwanie indeksu

Jeśli skończysz z tym indeksem, możesz go usunąć, uruchamiając komórkę Wyczyść kod. Usunięcie niepotrzebnych indeksów zwalnia miejsce na przechodzenie przez kolejne przewodniki Szybki start i samouczki.

W tym szybkim przewodniku użyjesz interfejsów API REST usługi Azure AI Search do tworzenia indeksu wyszukiwania, jego ładowania i wykonywania zapytań na potrzeby wyszukiwania pełnotekstowego. Wyszukiwanie pełnotekstowe używa platformy Apache Lucene do indeksowania i zapytań oraz algorytmu klasyfikacji BM25 na potrzeby oceniania wyników.

Ten szybki przewodnik używa fikcyjnych danych hotelowych z repozytorium azure-search-sample-data do wypełnienia indeksu.

Napiwek

Możesz pobrać kod źródłowy , aby rozpocząć od ukończonego projektu lub wykonać następujące kroki, aby utworzyć własny.

Wymagania wstępne

Konfigurowanie dostępu

Możesz nawiązać połączenie z usługą Azure AI Search przy użyciu kluczy API lub Microsoft Entra ID z przypisanymi rolami. Klucze są łatwiejsze do rozpoczęcia od, ale role są bezpieczniejsze.

Aby skonfigurować zalecany dostęp oparty na rolach:

  1. Zaloguj się do witryny Azure Portal i wybierz usługę wyszukiwania.

  2. W okienku po lewej stronie wybierz Ustawienia>Klucze.

  3. W obszarze Kontrola dostępu do interfejsu API wybierz pozycję Oba.

    Ta opcja umożliwia zarówno uwierzytelnianie oparte na kluczach, jak i bez klucza. Po przypisaniu ról możesz wrócić do tego kroku i wybrać pozycję Kontrola dostępu oparta na rolach.

  4. W okienku po lewej stronie wybierz pozycję Kontrola dostępu (Zarządzanie dostępem i tożsamościami).

  5. Wybierz Dodaj>Dodaj przypisanie roli.

  6. Przypisz role Współautor usługi wyszukiwania i Współautor danych indeksu wyszukiwania do konta użytkownika.

Aby uzyskać więcej informacji, zobacz Nawiązywanie połączenia z usługą Azure AI Search przy użyciu ról.

Uzyskiwanie punktu końcowego i tokenu

W następnej sekcji określisz następujący punkt końcowy i token, aby nawiązać połączenie z usługą Azure AI Search. W tych krokach przyjęto założenie, że skonfigurowano dostęp oparty na rolach.

Aby uzyskać punkt końcowy i token usługi:

  1. Zaloguj się do witryny Azure Portal i wybierz usługę wyszukiwania.

  2. W okienku po lewej stronie wybierz pozycję Przegląd.

  3. Zanotuj adres URL, który powinien być podobny do https://my-service.search.windows.net.

  4. W systemie lokalnym otwórz terminal.

  5. Zaloguj się do subskrypcji platformy Azure. Jeśli masz wiele subskrypcji, wybierz tę, która zawiera usługę wyszukiwania.

    az login
    
  6. Zanotuj token Microsoft Entra.

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

Skonfiguruj swój plik

Aby móc wykonywać wywołania interfejsu API REST do usługi Azure AI Search, należy utworzyć plik do przechowywania punktu końcowego usługi, tokenu uwierzytelniania oraz przyszłych żądań. Rozszerzenie klienta REST w programie Visual Studio Code obsługuje to zadanie.

Aby skonfigurować plik żądania:

  1. W systemie lokalnym otwórz program Visual Studio Code.

  2. Utwórz plik .rest lub .http.

  3. Wklej następujące symbole zastępcze i żądanie do pliku.

    @baseUrl = PUT-YOUR-SEARCH-SERVICE-ENDPOINT-HERE
    @token = PUT-YOUR-PERSONAL-IDENTITY-TOKEN-HERE
    
    ### List existing indexes by name
    GET {{baseUrl}}/indexes?api-version=2024-07-01  HTTP/1.1
        Authorization: Bearer {{token}}
    
  4. Zastąp symbole zastępcze @baseUrl i @token wartościami uzyskanymi w sekcji Uzyskiwanie punktu końcowego i tokenu. Nie należy stosować znaków cudzysłowu.

  5. W obszarze ### List existing indexes by namewybierz pozycję Wyślij żądanie.

    Odpowiedź powinna pojawić się w sąsiednim okienku. Jeśli masz istniejące indeksy, są one wyświetlane. W przeciwnym razie lista jest pusta. Jeśli kod HTTP to 200 OK, możesz przystąpić do następnych kroków.

    Zrzut ekranu przedstawiający klienta REST skonfigurowanego pod kątem żądania usługi wyszukiwania.

Tworzenie indeksu wyszukiwania

Przed dodaniem zawartości do usługi Azure AI Search należy utworzyć indeks, aby zdefiniować sposób przechowywania i struktury zawartości. Indeks jest koncepcyjnie podobny do tabeli w relacyjnej bazie danych, ale został specjalnie zaprojektowany pod kątem operacji wyszukiwania, takich jak wyszukiwanie pełnotekstowe.

Aby utworzyć indeks:

  1. Wklej następujące żądanie do pliku.

    ### Create a new index
    POST {{baseUrl}}/indexes?api-version=2024-07-01  HTTP/1.1
        Content-Type: application/json
        Authorization: Bearer {{token}}
    
        {
            "name": "hotels-quickstart",  
            "fields": [
                {"name": "HotelId", "type": "Edm.String", "key": true, "filterable": true},
                {"name": "HotelName", "type": "Edm.String", "searchable": true, "filterable": false, "sortable": true, "facetable": false},
                {"name": "Description", "type": "Edm.String", "searchable": true, "filterable": false, "sortable": false, "facetable": false, "analyzer": "en.lucene"},
                {"name": "Category", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true},
                {"name": "Tags", "type": "Collection(Edm.String)", "searchable": true, "filterable": true, "sortable": false, "facetable": true},
                {"name": "ParkingIncluded", "type": "Edm.Boolean", "filterable": true, "sortable": true, "facetable": true},
                {"name": "LastRenovationDate", "type": "Edm.DateTimeOffset", "filterable": true, "sortable": true, "facetable": true},
                {"name": "Rating", "type": "Edm.Double", "filterable": true, "sortable": true, "facetable": true},
                {"name": "Address", "type": "Edm.ComplexType", 
                    "fields": [
                    {"name": "StreetAddress", "type": "Edm.String", "filterable": false, "sortable": false, "facetable": false, "searchable": true},
                    {"name": "City", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true},
                    {"name": "StateProvince", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true},
                    {"name": "PostalCode", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true},
                    {"name": "Country", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true}
                    ]
                }
            ]
        }
    
  2. W obszarze ### Create a new indexwybierz pozycję Wyślij żądanie.

    Powinieneś otrzymać odpowiedź HTTP/1.1 201 Created, której treść zawiera JSON-ową reprezentację schematu indeksu.

Informacje o żądaniu tworzenia indeksu

Ten szybki start wywołuje Indeksy - Tworzenie (interfejs API REST) aby utworzyć indeks wyszukiwania o nazwie hotels-quickstart i jego fizycznych struktur danych w usłudze wyszukiwania.

W schemacie indeksu, kolekcja fields definiuje strukturę dokumentów hotelowych. Każde pole ma name, dane type i atrybuty, które określają jego zachowanie podczas indeksowania i zapytań. Pole HotelId jest oznaczone jako klucz, którego usługa Azure AI Search wymaga unikatowego identyfikowania każdego dokumentu w indeksie.

Kluczowe kwestie dotyczące schematu indeksu:

  • Użyj pól ciągu (Edm.String), aby umożliwić wyszukiwanie pełnotekstowe danych liczbowych. Inne obsługiwane typy danych, takie jak Edm.Int32, są filtrowalne, sortowalne, ustawialne jako facety i możliwe do pobrania, ale nie da się ich przeszukiwać.

  • Większość naszych pól to proste typy danych, ale można zdefiniować złożone typy reprezentujące zagnieżdżone dane, takie jak Address pole.

  • Atrybuty pól określają dozwolone akcje. Interfejsy API REST domyślnie zezwalają na wiele akcji. Na przykład wszystkie ciągi można wyszukiwać i pobierać. W przypadku interfejsów API REST można używać atrybutów tylko wtedy, gdy trzeba wyłączyć zachowanie.

Ładowanie indeksu

Nowo utworzone indeksy są puste. Aby wypełnić indeks i umożliwić wyszukiwanie, należy przekazać dokumenty JSON zgodne ze schematem indeksu.

W usłudze Azure AI Search dokumenty służą zarówno jako dane wejściowe do indeksowania, jak i danych wyjściowych zapytań. Dla uproszczenia ten przewodnik szybkiego startu zawiera przykładowe dokumenty hotelowe jako inline JSON. Jednak w scenariuszach produkcyjnych zawartość jest często pobierana z połączonych źródeł danych i przekształcana w format JSON przy użyciu indeksatorów.

Aby załadować dokumenty do swojego indeksu:

  1. Wklej następujące żądanie do pliku.

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

    Powinna zostać otrzymana HTTP/1.1 200 OK odpowiedź, której treść zawiera klucz i stan każdego przekazanego dokumentu.

Informacje o żądaniu ładowania

W tym przewodniku Szybki start wywoływane są dokumenty — indeks (interfejs API REST), aby dodać do indeksu cztery przykładowe dokumenty hotelowe. W porównaniu z poprzednim żądaniem URI jest rozszerzony, aby uwzględniać kolekcję docs i operację index.

Każdy dokument w tablicy value reprezentuje hotel i zawiera pola zgodne ze schematem indeksu. Parametr @search.action określa operację do wykonania dla każdego dokumentu. W naszym przykładzie użyto elementu upload, który dodaje dokument, jeśli nie istnieje lub aktualizuje dokument, jeśli istnieje.

Wykonywanie zapytań względem indeksu

Teraz, gdy dokumenty są ładowane do indeksu, możesz użyć wyszukiwania pełnotekstowego, aby znaleźć określone terminy lub frazy w swoich polach.

Aby uruchomić zapytanie pełnotekstowe względem indeksu:

  1. Wklej następujące żądanie do pliku.

    ### Run a query
    POST {{baseUrl}}/indexes/hotels-quickstart/docs/search?api-version=2024-07-01  HTTP/1.1
      Content-Type: application/json
      Authorization: Bearer {{token}}
    
      {
          "search": "attached restaurant",
          "select": "HotelId, HotelName, Tags, Description",
          "searchFields": "Description, Tags",
          "count": true
      }
    
  2. W obszarze ### Run a querywybierz pozycję Wyślij żądanie.

    Powinieneś otrzymać odpowiedź HTTP/1.1 200 OK podobną do poniższego przykładu, która pokazuje jeden pasujący dokument hotelowy, jego wynik istotności i wybrane pola.

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

Informacje o żądaniu zapytania

Ta instrukcja szybkiego startu wywołuje metodę POST wyszukiwania w interfejsie API REST, aby znaleźć dokumenty hotelowe spełniające kryteria wyszukiwania. Identyfikator URI jest teraz przeznaczony dla /docs/search operacji.

Żądania wyszukiwania pełnotekstowego search zawsze zawierają parametr zawierający tekst zapytania. Tekst zapytania może zawierać co najmniej jeden termin, frazy lub operatory. Oprócz search możesz określić inne parametry, aby uściślić wyniki wyszukiwania i jego zachowanie.

Nasze zapytanie wyszukuje terminy "restauracja na miejscu" w polach Description i Tags każdego dokumentu hotelowego. Parametr select ogranicza pola zwrócone w odpowiedzi do HotelId, HotelName, Tags i Description. Parametr count żąda całkowitej liczby pasujących dokumentów.

W tym szybkim starcie użyjesz biblioteki klienta Azure.Search.Documents do tworzenia, ładowania i wykonywania zapytań do indeksu wyszukiwania z przykładowymi danymi na potrzeby wyszukiwania pełnotekstowego. Wyszukiwanie pełnotekstowe używa platformy Apache Lucene do indeksowania i zapytań oraz algorytmu klasyfikacji BM25 na potrzeby oceniania wyników.

Ten szybki start używa fikcyjnych danych hotelowych z repozytorium azure-search-sample-data w celu wypełnienia indeksu.

Napiwek

Możesz pobrać kod źródłowy , aby rozpocząć od ukończonego projektu lub wykonać następujące kroki, aby utworzyć własny.

Wymagania wstępne

  • Konto Azure z aktywną subskrypcją. Utwórz konto bezpłatnie.
  • Usługa wyszukiwania sztucznej inteligencji platformy Azure. Utwórz usługę , jeśli jej nie masz. Możesz skorzystać z bezpłatnej usługi w ramach szybkiego startu.

Wymagania wstępne dotyczące identyfikatora entra firmy Microsoft

W przypadku zalecanego uwierzytelniania bez klucza za pomocą identyfikatora Entra firmy Microsoft należy:

Pobieranie informacji o zasobie

Aby uwierzytelnić aplikację przy użyciu usługi Azure AI usługa wyszukiwania, należy pobrać następujące informacje:

Nazwa zmiennej Wartość
SEARCH_API_ENDPOINT Tę wartość można znaleźć w witrynie Azure Portal. Wybierz usługę wyszukiwania, a następnie z menu po lewej stronie wybierz pozycję Przegląd. Wartość adresu URL w obszarze Podstawy to potrzebny punkt końcowy. Przykładowy punkt końcowy może wyglądać podobnie jak https://mydemo.search.windows.net.

Dowiedz się więcej na temat uwierzytelniania bez klucza i ustawiania zmiennych środowiskowych.

Konfiguruj

  1. Utwórz nowy folder full-text-quickstart zawierający aplikację i otwórz program Visual Studio Code w tym folderze za pomocą następującego polecenia:

    mkdir full-text-quickstart && cd full-text-quickstart
    
  2. Utwórz element package.json za pomocą następującego polecenia:

    npm init -y
    
  3. Zaktualizuj element do ecMAScript package.json za pomocą następującego polecenia:

    npm pkg set type=module
    
  4. Zainstaluj bibliotekę klienta usługi Azure AI Search (Azure.Search.Documents) dla języka JavaScript za pomocą następujących elementów:

    npm install @azure/search-documents
    
  5. W przypadku zalecanego uwierzytelniania bez hasła zainstaluj bibliotekę klienta tożsamości platformy Azure za pomocą polecenia:

    npm install @azure/identity
    

Tworzenie, ładowanie i wykonywanie zapytań względem indeksu wyszukiwania

W poprzedniej sekcji konfiguracji zainstalowano bibliotekę klienta usługi Azure AI Search i inne zależności.

W tej sekcji dodasz kod, aby utworzyć indeks wyszukiwania, załadować go przy użyciu dokumentów i uruchomić zapytania. Uruchom program, aby wyświetlić wyniki w konsoli programu . Aby uzyskać szczegółowe wyjaśnienie kodu, zobacz sekcję wyjaśniającą kod .

Przykładowy kod w tym przewodniku Szybki start używa identyfikatora Entra firmy Microsoft do zalecanego uwierzytelniania bez klucza. Jeśli wolisz użyć klucza interfejsu API, możesz zastąpić DefaultAzureCredential obiekt obiektem AzureKeyCredential .

const searchServiceEndpoint = "https://<Put your search service NAME here>.search.windows.net/";
const credential = new DefaultAzureCredential();
  1. Utwórz nowy plik o nazwie index.ts i wklej następujący kod do index.ts:

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

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

    tsc
    
  5. Zaloguj się do platformy Azure przy użyciu następującego polecenia:

    az login
    
  6. Uruchom kod JavaScript za pomocą następującego polecenia:

    node index.js
    

Wyjaśnienie kodu

tworzenie indeksu

Utwórz plik hotels_quickstart_index.json. Ten plik definiuje sposób działania usługi Azure AI Search z dokumentami ładowanymi w następnym kroku. Każde pole jest identyfikowane przez element name i ma określony element type. Każde pole ma również szereg atrybutów indeksu, które określają, czy usługa Azure AI Search może wyszukiwać, filtrować, sortować i aspekty po polu. Większość pól to proste typy danych, ale niektóre, takie jak AddressType typy złożone, które umożliwiają tworzenie rozbudowanych struktur danych w indeksie. Więcej informacji na temat obsługiwanych typów danych i atrybutów indeksu opisano w artykule Create Index (REST) (Tworzenie indeksu (REST).

Chcemy zaimportować hotels_quickstart_index.json , aby funkcja main mogła uzyskać dostęp do definicji indeksu.

import indexDefinition from './hotels_quickstart_index.json';

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

W ramach funkcji main utworzymy element SearchIndexClient, który służy do tworzenia indeksów usługi Azure AI Search i zarządzania nimi.

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

Następnie chcemy usunąć indeks, jeśli już istnieje. Ta operacja jest powszechną praktyką w przypadku kodu testowego/demonstracyjnego.

Robimy to, definiując prostą funkcję, która próbuje usunąć indeks.

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.');
    }
}

Aby uruchomić funkcję, wyodrębniamy nazwę indeksu z definicji indeksu i przekazujemy indexName element wraz z funkcją indexClientdeleteIndexIfExists() .

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

Następnie możemy utworzyć indeks za pomocą createIndex() metody .

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

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

Ładowanie dokumentów

W usłudze Azure AI Search dokumenty to struktury danych, które są danymi wejściowymi do indeksowania i danych wyjściowych z zapytań. Możesz wypchnąć takie dane do indeksu lub użyć indeksatora. W takim przypadku programowo wypchniemy dokumenty do indeksu.

Dane wejściowe dokumentu mogą być wierszami w bazie danych, obiektach blob w usłudze Blob Storage lub, jak w tym przykładzie, dokumentach JSON na dysku. Możesz pobrać hotels.json lub utworzyć własny plik hotels.json z następującą zawartością:

Podobnie jak w przypadku elementu indexDefinition, musimy również zaimportować hotels.json w górnej części index.ts , aby można było uzyskać dostęp do danych w naszej funkcji main.

import hotelData from './hotels.json';

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

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

Aby zaindeksować dane do indeksu wyszukiwania, musimy teraz utworzyć element SearchClient. SearchIndexClient Element służy do tworzenia indeksu i zarządzania nim, SearchClient ale służy do przekazywania dokumentów i wykonywania zapytań względem indeksu.

Istnieją dwa sposoby tworzenia elementu SearchClient. Pierwszą opcją jest utworzenie od SearchClient podstaw:

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

Alternatywnie możesz użyć getSearchClient() metody , SearchIndexClient aby utworzyć element SearchClient:

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

Teraz, gdy klient jest zdefiniowany, przekaż dokumenty do indeksu wyszukiwania. W takim przypadku używamy mergeOrUploadDocuments() metody , która przekazuje dokumenty lub scala je z istniejącym dokumentem, jeśli dokument o tym samym kluczu już istnieje. Następnie sprawdź, czy operacja zakończyła się pomyślnie, ponieważ istnieje co najmniej pierwszy dokument.

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

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

Uruchom ponownie program za pomocą polecenia tsc && node index.ts. W kroku 1 powinien zostać wyświetlony nieco inny zestaw komunikatów. Tym razem indeks istnieje i powinien zostać wyświetlony komunikat o usunięciu go, zanim aplikacja utworzy nowy indeks i opublikuje do niego dane.

Przed uruchomieniem zapytań w następnym kroku zdefiniuj funkcję, aby program czekał na jedną sekundę. Odbywa się to tylko w celach testowych/demonstracyjnych, aby upewnić się, że indeksowanie zakończy się i że dokumenty są dostępne w indeksie dla naszych zapytań.

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

Aby program czekał na jedną sekundę, wywołaj sleep funkcję:

sleep(1000);

Przeszukiwanie indeksu

Po przekazaniu indeksu i przekazaniu dokumentów możesz wysyłać zapytania do indeksu. W tej sekcji wysyłamy pięć różnych zapytań do indeksu wyszukiwania, aby zademonstrować różne dostępne funkcje zapytań.

Zapytania są zapisywane w sendQueries() funkcji, którą wywołujemy w funkcji main w następujący sposób:

await sendQueries(searchClient);

Zapytania są wysyłane przy użyciu search() metody searchClient. Pierwszy parametr to tekst wyszukiwania, a drugi parametr określa opcje wyszukiwania.

Przykład zapytania 1

Pierwsze zapytanie wyszukuje *element , który jest odpowiednikiem wyszukiwania wszystkiego i wybiera trzy pola w indeksie. Jest to najlepsze rozwiązanie tylko select dla potrzebnych pól, ponieważ ściąganie niepotrzebnych danych może powodować opóźnienie zapytań.

Dla searchOptions tego zapytania ustawiono includeTotalCount również wartość true, która zwróci liczbę znalezionych pasujących wyników.

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
}

Pozostałe zapytania opisane poniżej należy również dodać do sendQueries() funkcji. Są one tutaj oddzielone w celu czytelności.

Przykład zapytania 2

W następnym zapytaniu określamy termin "wifi" wyszukiwania, a także uwzględniamy filtr, aby zwracać wyniki tylko wtedy, gdy stan jest równy 'FL'. Wyniki są również uporządkowane przez hotel 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)}`);
}

Przykład zapytania 3

Następnie wyszukiwanie jest ograniczone do pojedynczego pola z możliwością wyszukiwania przy użyciu parametru searchFields . Takie podejście jest doskonałym rozwiązaniem, aby zwiększyć wydajność zapytania, jeśli wiesz, że interesuje Cię tylko dopasowanie w niektórych polach.

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

Przykład zapytania 4

Inną typową opcją uwzględnienia w zapytaniu jest facets. Aspekty umożliwiają zapewnienie samodzielnego przechodzenia do szczegółów z wyników w interfejsie użytkownika. Wyniki aspektów można przekształcić w pola wyboru w okienku wyników.

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

Przykład zapytania 5

Ostatnie zapytanie używa getDocument() metody searchClient. Dzięki temu można efektywnie pobierać dokument przy użyciu jego klucza.

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

Podsumowanie zapytań

Poprzednie zapytania pokazują wiele sposobów dopasowywania terminów w zapytaniu: wyszukiwanie pełnotekstowe, filtry i autouzupełnianie.

Wyszukiwanie pełnotekstowe i filtry są wykonywane przy użyciu searchClient.search metody . Zapytanie wyszukiwania można przekazać w searchText ciągu, podczas gdy wyrażenie filtru może zostać przekazane we filter właściwości SearchOptions klasy. Aby filtrować bez wyszukiwania, wystarczy przekazać wartość "*" dla searchText parametru search metody . Aby wyszukać bez filtrowania, pozostaw filter właściwość niezastawioną lub nie przekazuj SearchOptions w ogóle wystąpienia.

Uprzątnij zasoby

Podczas pracy w ramach własnej subskrypcji warto ukończyć projekt, określając, czy nadal potrzebujesz utworzonych zasobów. Zasoby, które pozostają uruchomione, mogą kosztować pieniądze. Zasoby można usunąć pojedynczo lub usunąć grupę zasobów, aby usunąć cały zestaw zasobów.

W witrynie Azure Portal możesz znaleźć zasoby i zarządzać nimi, wybierając pozycję Wszystkie zasoby lub Grupy zasobów w okienku po lewej stronie.

Jeśli używasz bezpłatnej usługi, pamiętaj, że masz ograniczenie do trzech indeksów, indeksatorów i źródeł danych. Aby utrzymać limit, możesz usunąć poszczególne elementy w witrynie Azure Portal.