Schnellstart: Volltextsuche mithilfe der Azure SDKs
Erfahren Sie, wie Sie die Clientbibliothek Azure.Search.Documents verwenden, um einen Suchindex mithilfe von Beispieldaten für die Volltextsuche zu erstellen, zu laden und abzufragen. Die Volltextsuche verwendet Apache Lucene für die Indizierung und Abfragen sowie einen BM25-Bewertungsalgorithmus für die Bewertung von Ergebnissen.
In diesem Schnellstart wird der kleine Index „hotels-quickstart“, der Daten zu vier Hotels enthält, erstellt und abgefragt.
Tipp
Sie können den Quellcode herunterladen, um mit einem fertigen Projekt zu beginnen, oder diese Schritte ausführen, um ein eigenes zu erstellen.
Voraussetzungen
- Ein aktives Azure-Abonnement. (Kostenloses Abonnement erstellen)
- Ein Azure AI Search-Dienst. Erstellen Sie einen Dienst, sofern nicht bereits geschehen. Sie können einen Free-Tarif für diesen Schnellstart verwenden.
Voraussetzungen für Microsoft Entra ID
Für die empfohlene schlüssellose Authentifizierung mit Microsoft Entra ID müssen Sie:
- Die Azure CLI installieren, die für die schlüssellose Authentifizierung mit Microsoft Entra ID verwendet wird
- Weisen Sie Ihrem Benutzerkonto die beiden Rollen
Search Service Contributor
undSearch Index Data Contributor
zu. Sie können Rollen im Azure-Portal unter Zugriffssteuerung (IAM)>Rollenzuweisung hinzufügen zuweisen. Weitere Informationen finden Sie unter Herstellen einer Verbindung mit Azure KI-Suche mithilfe von Rollen.
Abrufen von Ressourceninformationen
Sie müssen die folgenden Informationen abrufen, um Ihre Anwendung bei Ihrem Azure KI-Suche-Dienst zu authentifizieren:
Variablenname | Wert |
---|---|
SEARCH_API_ENDPOINT |
Diesen Wert finden Sie im Azure-Portal. Wählen Sie Ihren Suchdienst und dann im linken Menü die Option Übersicht aus. Der URL-Wert unter Essentials ist der Endpunkt, den Sie benötigen. Ein Beispiel für einen Endpunkt ist https://mydemo.search.windows.net . |
Erfahren Sie mehr über schlüssellose Authentifizierung und das Festlegen von Umgebungsvariablen.
Einrichten
Erstellen Sie einen neuen Ordner
full-text-quickstart
für die Anwendung, und öffnen Sie Visual Studio Code in diesem Ordner mit dem folgenden Befehl:mkdir full-text-quickstart && cd full-text-quickstart
Erstellen Sie eine neue Konsolenanwendung mit dem folgenden Befehl:
dotnet new console
Installieren Sie die Clientbibliothek von Azure KI-Suche (Azure.Search.Documents) für .NET mit:
dotnet add package Azure.Search.Documents
Installieren Sie für die empfohlene schlüssellose Authentifizierung mit Microsoft Entra ID das Paket Azure.Identity mit:
dotnet add package Azure.Identity
Melden Sie sich für die empfohlene schlüssellose Authentifizierung mit Microsoft Entra ID mit dem folgenden Befehl bei Azure an:
az login
Erstellen, Laden und Abfragen eines Suchindexes
Im vorherigen Abschnitt Einrichten haben Sie eine neue Konsolenanwendung erstellt und die Clientbibliothek von Azure KI-Suche installiert.
In diesem Abschnitt fügen Sie Code hinzu, um einen Suchindex zu erstellen, ihn mit Dokumenten zu laden und Abfragen auszuführen. Sie führen das Programm aus, um die Ergebnisse in der Konsole anzuzeigen. Eine ausführliche Erläuterung des Codes finden Sie im Abschnitt Erläuterung des Codes.
Der Beispielcode in diesem Schnellstart verwendet Microsoft Entra ID für die empfohlene schlüssellose Authentifizierung. Wenn Sie einen API-Schlüssel verwenden möchten, können Sie das DefaultAzureCredential
-Objekt durch ein AzureKeyCredential
-Objekt ersetzen.
Uri serviceEndpoint = new Uri($"https://<Put your search service NAME here>.search.windows.net/");
DefaultAzureCredential credential = new();
Fügen Sie in Program.cs den folgenden Code ein. Bearbeiten Sie die Variablen
serviceName
undapiKey
mit dem Namen Ihres Suchdienstes und dem Administrator-API-Schlüssel.using System; using Azure; using Azure.Identity; using Azure.Search.Documents; using Azure.Search.Documents.Indexes; using Azure.Search.Documents.Indexes.Models; using Azure.Search.Documents.Models; namespace AzureSearch.Quickstart { class Program { static void Main(string[] args) { // Your search service endpoint Uri serviceEndpoint = new Uri($"https://<Put your search service NAME here>.search.windows.net/"); // Use the recommended keyless credential instead of the AzureKeyCredential credential. DefaultAzureCredential credential = new(); //AzureKeyCredential credential = new AzureKeyCredential("Your search service admin key"); // Create a SearchIndexClient to send create/delete index commands SearchIndexClient searchIndexClient = new SearchIndexClient(serviceEndpoint, credential); // Create a SearchClient to load and query documents string indexName = "hotels-quickstart"; SearchClient searchClient = new SearchClient(serviceEndpoint, indexName, credential); // Delete index if it exists Console.WriteLine("{0}", "Deleting index...\n"); DeleteIndexIfExists(indexName, searchIndexClient); // Create index Console.WriteLine("{0}", "Creating index...\n"); CreateIndex(indexName, searchIndexClient); SearchClient ingesterClient = searchIndexClient.GetSearchClient(indexName); // Load documents Console.WriteLine("{0}", "Uploading documents...\n"); UploadDocuments(ingesterClient); // Wait 2 secondsfor indexing to complete before starting queries (for demo and console-app purposes only) Console.WriteLine("Waiting for indexing...\n"); System.Threading.Thread.Sleep(2000); // Call the RunQueries method to invoke a series of queries Console.WriteLine("Starting queries...\n"); RunQueries(searchClient); // End the program Console.WriteLine("{0}", "Complete. Press any key to end this program...\n"); Console.ReadKey(); } // Delete the hotels-quickstart index to reuse its name private static void DeleteIndexIfExists(string indexName, SearchIndexClient searchIndexClient) { searchIndexClient.GetIndexNames(); { searchIndexClient.DeleteIndex(indexName); } } // Create hotels-quickstart index private static void CreateIndex(string indexName, SearchIndexClient searchIndexClient) { FieldBuilder fieldBuilder = new FieldBuilder(); var searchFields = fieldBuilder.Build(typeof(Hotel)); var definition = new SearchIndex(indexName, searchFields); var suggester = new SearchSuggester("sg", new[] { "HotelName", "Category", "Address/City", "Address/StateProvince" }); definition.Suggesters.Add(suggester); searchIndexClient.CreateOrUpdateIndex(definition); } // Upload documents in a single Upload request. private static void UploadDocuments(SearchClient searchClient) { IndexDocumentsBatch<Hotel> batch = IndexDocumentsBatch.Create( IndexDocumentsAction.Upload( new Hotel() { HotelId = "1", HotelName = "Secret Point Motel", Description = "The hotel is ideally located on the main commercial artery of the city in the heart of New York. A few minutes away is Time's Square and the historic centre of the city, as well as other places of interest that make New York one of America's most attractive and cosmopolitan cities.", DescriptionFr = "L'hôtel est idéalement situé sur la principale artère commerciale de la ville en plein cœur de New York. A quelques minutes se trouve la place du temps et le centre historique de la ville, ainsi que d'autres lieux d'intérêt qui font de New York l'une des villes les plus attractives et cosmopolites de l'Amérique.", Category = "Boutique", Tags = new[] { "pool", "air conditioning", "concierge" }, ParkingIncluded = false, LastRenovationDate = new DateTimeOffset(1970, 1, 18, 0, 0, 0, TimeSpan.Zero), Rating = 3.6, Address = new Address() { StreetAddress = "677 5th Ave", City = "New York", StateProvince = "NY", PostalCode = "10022", Country = "USA" } }), IndexDocumentsAction.Upload( new Hotel() { HotelId = "2", HotelName = "Twin Dome Motel", Description = "The hotel is situated in a nineteenth century plaza, which has been expanded and renovated to the highest architectural standards to create a modern, functional and first-class hotel in which art and unique historical elements coexist with the most modern comforts.", DescriptionFr = "L'hôtel est situé dans une place du XIXe siècle, qui a été agrandie et rénovée aux plus hautes normes architecturales pour créer un hôtel moderne, fonctionnel et de première classe dans lequel l'art et les éléments historiques uniques coexistent avec le confort le plus moderne.", Category = "Boutique", Tags = new[] { "pool", "free wifi", "concierge" }, ParkingIncluded = false, LastRenovationDate = new DateTimeOffset(1979, 2, 18, 0, 0, 0, TimeSpan.Zero), Rating = 3.60, Address = new Address() { StreetAddress = "140 University Town Center Dr", City = "Sarasota", StateProvince = "FL", PostalCode = "34243", Country = "USA" } }), IndexDocumentsAction.Upload( new Hotel() { HotelId = "3", HotelName = "Triple Landscape Hotel", Description = "The Hotel stands out for its gastronomic excellence under the management of William Dough, who advises on and oversees all of the Hotel’s restaurant services.", DescriptionFr = "L'hôtel est situé dans une place du XIXe siècle, qui a été agrandie et rénovée aux plus hautes normes architecturales pour créer un hôtel moderne, fonctionnel et de première classe dans lequel l'art et les éléments historiques uniques coexistent avec le confort le plus moderne.", Category = "Resort and Spa", Tags = new[] { "air conditioning", "bar", "continental breakfast" }, ParkingIncluded = true, LastRenovationDate = new DateTimeOffset(2015, 9, 20, 0, 0, 0, TimeSpan.Zero), Rating = 4.80, Address = new Address() { StreetAddress = "3393 Peachtree Rd", City = "Atlanta", StateProvince = "GA", PostalCode = "30326", Country = "USA" } }), IndexDocumentsAction.Upload( new Hotel() { HotelId = "4", HotelName = "Sublime Cliff Hotel", Description = "Sublime Cliff Hotel is located in the heart of the historic center of Sublime in an extremely vibrant and lively area within short walking distance to the sites and landmarks of the city and is surrounded by the extraordinary beauty of churches, buildings, shops and monuments. Sublime Cliff is part of a lovingly restored 1800 palace.", DescriptionFr = "Le sublime Cliff Hotel est situé au coeur du centre historique de sublime dans un quartier extrêmement animé et vivant, à courte distance de marche des sites et monuments de la ville et est entouré par l'extraordinaire beauté des églises, des bâtiments, des commerces et Monuments. Sublime Cliff fait partie d'un Palace 1800 restauré avec amour.", Category = "Boutique", Tags = new[] { "concierge", "view", "24-hour front desk service" }, ParkingIncluded = true, LastRenovationDate = new DateTimeOffset(1960, 2, 06, 0, 0, 0, TimeSpan.Zero), Rating = 4.60, Address = new Address() { StreetAddress = "7400 San Pedro Ave", City = "San Antonio", StateProvince = "TX", PostalCode = "78216", Country = "USA" } }) ); try { IndexDocumentsResult result = searchClient.IndexDocuments(batch); } catch (Exception) { // If for some reason any documents are dropped during indexing, you can compensate by delaying and // retrying. This simple demo just logs the failed document keys and continues. Console.WriteLine("Failed to index some of the documents: {0}"); } } // Run queries, use WriteDocuments to print output private static void RunQueries(SearchClient searchClient) { SearchOptions options; SearchResults<Hotel> response; // Query 1 Console.WriteLine("Query #1: Search on empty term '*' to return all documents, showing a subset of fields...\n"); options = new SearchOptions() { IncludeTotalCount = true, Filter = "", OrderBy = { "" } }; options.Select.Add("HotelId"); options.Select.Add("HotelName"); options.Select.Add("Rating"); response = searchClient.Search<Hotel>("*", options); WriteDocuments(response); // Query 2 Console.WriteLine("Query #2: Search on 'hotels', filter on 'Rating gt 4', sort by Rating in descending order...\n"); options = new SearchOptions() { Filter = "Rating gt 4", OrderBy = { "Rating desc" } }; options.Select.Add("HotelId"); options.Select.Add("HotelName"); options.Select.Add("Rating"); response = searchClient.Search<Hotel>("hotels", options); WriteDocuments(response); // Query 3 Console.WriteLine("Query #3: Limit search to specific fields (pool in Tags field)...\n"); options = new SearchOptions() { SearchFields = { "Tags" } }; options.Select.Add("HotelId"); options.Select.Add("HotelName"); options.Select.Add("Tags"); response = searchClient.Search<Hotel>("pool", options); WriteDocuments(response); // Query 4 - Use Facets to return a faceted navigation structure for a given query // Filters are typically used with facets to narrow results on OnClick events Console.WriteLine("Query #4: Facet on 'Category'...\n"); options = new SearchOptions() { Filter = "" }; options.Facets.Add("Category"); options.Select.Add("HotelId"); options.Select.Add("HotelName"); options.Select.Add("Category"); response = searchClient.Search<Hotel>("*", options); WriteDocuments(response); // Query 5 Console.WriteLine("Query #5: Look up a specific document...\n"); Response<Hotel> lookupResponse; lookupResponse = searchClient.GetDocument<Hotel>("3"); Console.WriteLine(lookupResponse.Value.HotelId); // Query 6 Console.WriteLine("Query #6: Call Autocomplete on HotelName...\n"); var autoresponse = searchClient.Autocomplete("sa", "sg"); WriteDocuments(autoresponse); } // Write search results to console private static void WriteDocuments(SearchResults<Hotel> searchResults) { foreach (SearchResult<Hotel> result in searchResults.GetResults()) { Console.WriteLine(result.Document); } Console.WriteLine(); } private static void WriteDocuments(AutocompleteResults autoResults) { foreach (AutocompleteItem result in autoResults.Results) { Console.WriteLine(result.Text); } Console.WriteLine(); } } }
Erstellen Sie im selben Ordner eine neue Datei mit dem Namen Hotel.cs, und fügen Sie den folgenden Code ein. Dieser Code definiert die Struktur eines Hoteldokuments.
using System; using System.Text.Json.Serialization; using Azure.Search.Documents.Indexes; using Azure.Search.Documents.Indexes.Models; namespace AzureSearch.Quickstart { public partial class Hotel { [SimpleField(IsKey = true, IsFilterable = true)] public string HotelId { get; set; } [SearchableField(IsSortable = true)] public string HotelName { get; set; } [SearchableField(AnalyzerName = LexicalAnalyzerName.Values.EnLucene)] public string Description { get; set; } [SearchableField(AnalyzerName = LexicalAnalyzerName.Values.FrLucene)] [JsonPropertyName("Description_fr")] public string DescriptionFr { get; set; } [SearchableField(IsFilterable = true, IsSortable = true, IsFacetable = true)] public string Category { get; set; } [SearchableField(IsFilterable = true, IsFacetable = true)] public string[] Tags { get; set; } [SimpleField(IsFilterable = true, IsSortable = true, IsFacetable = true)] public bool? ParkingIncluded { get; set; } [SimpleField(IsFilterable = true, IsSortable = true, IsFacetable = true)] public DateTimeOffset? LastRenovationDate { get; set; } [SimpleField(IsFilterable = true, IsSortable = true, IsFacetable = true)] public double? Rating { get; set; } [SearchableField] public Address Address { get; set; } } }
Erstellen Sie eine neue Datei mit dem Namen Hotel.cs, und fügen Sie den folgenden Code ein, um die Struktur eines Hoteldokuments zu definieren. Attribute für das Feld bestimmen die Verwendung in einer Anwendung. So muss beispielsweise jedem Feld, das einen Filterausdruck unterstützt, das Attribut
IsFilterable
zugewiesen werden.using System; using System.Text.Json.Serialization; using Azure.Search.Documents.Indexes; using Azure.Search.Documents.Indexes.Models; namespace AzureSearch.Quickstart { public partial class Hotel { [SimpleField(IsKey = true, IsFilterable = true)] public string HotelId { get; set; } [SearchableField(IsSortable = true)] public string HotelName { get; set; } [SearchableField(AnalyzerName = LexicalAnalyzerName.Values.EnLucene)] public string Description { get; set; } [SearchableField(AnalyzerName = LexicalAnalyzerName.Values.FrLucene)] [JsonPropertyName("Description_fr")] public string DescriptionFr { get; set; } [SearchableField(IsFilterable = true, IsSortable = true, IsFacetable = true)] public string Category { get; set; } [SearchableField(IsFilterable = true, IsFacetable = true)] public string[] Tags { get; set; } [SimpleField(IsFilterable = true, IsSortable = true, IsFacetable = true)] public bool? ParkingIncluded { get; set; } [SimpleField(IsFilterable = true, IsSortable = true, IsFacetable = true)] public DateTimeOffset? LastRenovationDate { get; set; } [SimpleField(IsFilterable = true, IsSortable = true, IsFacetable = true)] public double? Rating { get; set; } [SearchableField] public Address Address { get; set; } } }
Erstellen Sie eine neue Datei mit dem Namen Address.cs, und fügen Sie den folgenden Code ein, um die Struktur eines Adressdokuments zu definieren.
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; } } }
Erstellen Sie eine neue Datei mit dem Namen Hotel.Methods.cs, und fügen Sie den folgenden Code ein, um eine
ToString()
-Überschreibung für dieHotel
-Klasse zu definieren.using System; using System.Text; namespace AzureSearch.Quickstart { public partial class Hotel { public override string ToString() { var builder = new StringBuilder(); if (!String.IsNullOrEmpty(HotelId)) { builder.AppendFormat("HotelId: {0}\n", HotelId); } if (!String.IsNullOrEmpty(HotelName)) { builder.AppendFormat("Name: {0}\n", HotelName); } if (!String.IsNullOrEmpty(Description)) { builder.AppendFormat("Description: {0}\n", Description); } if (!String.IsNullOrEmpty(DescriptionFr)) { builder.AppendFormat("Description (French): {0}\n", DescriptionFr); } if (!String.IsNullOrEmpty(Category)) { builder.AppendFormat("Category: {0}\n", Category); } if (Tags != null && Tags.Length > 0) { builder.AppendFormat("Tags: [ {0} ]\n", String.Join(", ", Tags)); } if (ParkingIncluded.HasValue) { builder.AppendFormat("Parking included: {0}\n", ParkingIncluded.Value ? "yes" : "no"); } if (LastRenovationDate.HasValue) { builder.AppendFormat("Last renovated on: {0}\n", LastRenovationDate); } if (Rating.HasValue) { builder.AppendFormat("Rating: {0}\n", Rating); } if (Address != null && !Address.IsEmpty) { builder.AppendFormat("Address: \n{0}\n", Address.ToString()); } return builder.ToString(); } } }
Erstellen Sie eine neue Datei mit dem Namen Address.Methods.cs, und fügen Sie den folgenden Code ein, um eine
ToString()
-Überschreibung für dieAddress
-Klasse zu definieren.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); } }
Erstellen und führen Sie die Anwendung mit dem folgenden Befehl aus:
dotnet run
Die Ausgabe umfasst Nachrichten aus Console.WriteLine, wobei Abfrageinformationen und -ergebnisse hinzugefügt werden.
Erläutern des Codes
In den vorherigen Abschnitten haben Sie eine neue Konsolenanwendung erstellt und die Clientbibliothek von Azure KI-Suche installiert. Sie haben Code hinzugefügt, um einen Suchindex zu erstellen, ihn mit Dokumenten zu laden und Abfragen auszuführen. Sie haben das Programm ausgeführt, um die Ergebnisse in der Konsole anzuzeigen.
In diesem Abschnitt erläutern wir den Code, den Sie der Konsolenanwendung hinzugefügt haben.
Erstellen eines Suchclients
In Program.cs haben Sie zwei Clients erstellt:
- SearchIndexClient erstellt den Index.
- SearchClient lädt und fragt einen vorhandenen Index ab.
Beide Clients benötigen den Suchdienst-Endpunkt und die Anmeldeinformationen, die weiter oben im Abschnitt Ressourceninformationen beschrieben wurden.
Der Beispielcode in diesem Schnellstart verwendet Microsoft Entra ID für die empfohlene schlüssellose Authentifizierung. Wenn Sie einen API-Schlüssel verwenden möchten, können Sie das DefaultAzureCredential
-Objekt durch ein AzureKeyCredential
-Objekt ersetzen.
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 . . .
}
Erstellen eines Index
In dieser Schnellstartanleitung wird ein Hotelindex erstellt, in den Sie Hoteldaten laden und Abfragen dafür ausführen. In diesem Schritt definieren Sie die Felder im Index. Jede Felddefinition enthält einen Namen, einen Datentyp und Attribute, die bestimmen, wie das Feld verwendet wird.
In diesem Beispiel werden aus Gründen der Einfachheit und Lesbarkeit synchrone Methoden der Bibliothek Azure.Search.Documents verwendet. In Produktionsszenarien sollten Sie jedoch asynchrone Methoden verwenden, um Ihre App skalierbar und reaktionsfähig zu halten. So würden Sie beispielsweise CreateIndexAsync anstatt CreateIndex verwenden.
Definieren der Strukturen
Sie haben zwei Hilfsklassen erstellt, Hotel.cs und Address.cs, um die Struktur eines Hoteldokuments und seiner Adresse zu definieren. Die Hotel
-Klasse enthält Felder für Hotel-ID, Name, Beschreibung, Kategorie, Tags, Parkplätze, Renovierungsdatum, Bewertung und Adresse. Die Address
-Klasse enthält Felder für Straße und Hausnummer, Ort, Bundesland/Kanton, Postleitzahl und Land/Region.
In der Azure.Search.Documents-Clientbibliothek können Sie SearchableField und SimpleField verwenden, um Felddefinitionen zu optimieren. Beide sind Ableitungen von SearchField und können Ihren Code möglicherweise vereinfachen:
SimpleField
kann ein beliebiger Datentyp sein, ist nie durchsuchbar (wird bei Volltextsuchabfragen ignoriert) und ist abrufbar (nicht ausgeblendet). Andere Attribute sind standardmäßig deaktiviert, können jedoch aktiviert werden. Sie können einSimpleField
für Dokument-IDs oder Felder verwenden, die nur in Filtern, Facets oder Bewertungsprofilen verwendet werden. Sofern dies der Fall ist, stellen Sie sicher, dass Sie alle Attribute anwenden, die für das Szenario erforderlich sind, z. B.IsKey = true
für eine Dokument-ID. Weitere Informationen finden Sie unter SimpleFieldAttribute.cs im Quellcode.SearchableField
muss eine Zeichenfolge sein und ist immer „durchsuchbar“ und „abrufbar“. Andere Attribute sind standardmäßig deaktiviert, können jedoch aktiviert werden. Da dieser Feldtyp durchsuchbar ist, unterstützt er Synonyme und die gesamte Palette der Eigenschaften des Analysetools. Weitere Informationen finden Sie unter SearchableFieldAttribute.cs im Quellcode.
Ob Sie die grundlegende SearchField
-API oder eines der Hilfsmodelle verwenden, müssen Sie Filter-, Facet- und Sortierattribute explizit aktivieren. Beispielsweise müssen IsFilterable, IsSortable und IsFacetable explizit mit Attributen versehen werden, wie im vorherigen Beispiel gezeigt.
Erstellen des Suchindex
In Program.cs erstellen Sie ein SearchIndex-Objekt und rufen dann die CreateIndex-Methode auf, um den Index in Ihrem Suchdienst auszudrücken. Der Index enthält auch ein SearchSuggester-Element, um die automatische Vervollständigung für die angegebenen Felder zu ermöglichen.
// 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);
}
Laden von Dokumenten
Azure AI Search durchsucht im Dienst gespeicherte Inhalte. In diesem Schritt laden Sie JSON-Dokumente, die dem erstellten Hotelindex entsprechen.
Bei Azure AI Search sind die Suchdokumente Datenstrukturen, die sowohl Eingaben für die Indizierung als auch Ausgaben von Abfragen sind. Beispiele für Dokumenteingaben aus einer externen Datenquelle wären etwa Zeilen in einer Datenbank, Blobs in Blob Storage oder JSON-Dokumente auf dem Datenträger. In diesem Beispiel nehmen wir eine Abkürzung und betten JSON-Dokumente für vier Hotels direkt in den Code ein.
Beim Hochladen von Dokumenten muss ein IndexDocumentsBatch-Objekt verwendet werden. Ein IndexDocumentsBatch
-Objekt enthält eine Sammlung von Aktionen, und jede dieser Aktionen enthält wiederum ein Dokument und eine Eigenschaft, die Azure AI Search mitteilt, welche Aktion ausgeführt werden soll („upload“, „merge“, „delete“ oder „mergeOrUpload“).
In Program.cs erstellen Sie ein Array mit Dokumenten und Indexaktionen und übergeben es anschließend an IndexDocumentsBatch
. Die folgenden Dokumente entsprechen dem Index „hotels-quickstart“ (gemäß Definition durch die Klasse „hotel“).
// Upload documents in a single Upload request.
private static void UploadDocuments(SearchClient searchClient)
{
IndexDocumentsBatch<Hotel> batch = IndexDocumentsBatch.Create(
IndexDocumentsAction.Upload(
new Hotel()
{
HotelId = "1",
HotelName = "Stay-Kay City Hotel",
Description = "The hotel is ideally located on the main commercial artery of the city in the heart of New York. A few minutes away is Time's Square and the historic centre of the city, as well as other places of interest that make New York one of America's most attractive and cosmopolitan cities.",
DescriptionFr = "L'hôtel est idéalement situé sur la principale artère commerciale de la ville en plein cœur de New York. A quelques minutes se trouve la place du temps et le centre historique de la ville, ainsi que d'autres lieux d'intérêt qui font de New York l'une des villes les plus attractives et cosmopolites de l'Amérique.",
Category = "Boutique",
Tags = new[] { "pool", "air conditioning", "concierge" },
ParkingIncluded = false,
LastRenovationDate = new DateTimeOffset(1970, 1, 18, 0, 0, 0, TimeSpan.Zero),
Rating = 3.6,
Address = new Address()
{
StreetAddress = "677 5th Ave",
City = "New York",
StateProvince = "NY",
PostalCode = "10022",
Country = "USA"
}
}),
// REDACTED FOR BREVITY
}
Nachdem Sie das IndexDocumentsBatch-Objekt initialisiert haben, können Sie es an den Index senden, indem Sie IndexDocuments für Ihr SearchClient-Objekt aufrufen.
Sie laden Dokumente mithilfe von „SearchClient“ in Main()
, aber für den Vorgang werden auch Administratorrechte für den Dienst benötigt, der normalerweise „SearchIndexClient“ zugeordnet ist. Eine Möglichkeit zum Einrichten dieses Vorgangs ist das Abrufen von „SearchClient“ über SearchIndexClient
(in diesem Beispiel searchIndexClient
).
SearchClient ingesterClient = searchIndexClient.GetSearchClient(indexName);
// Load documents
Console.WriteLine("{0}", "Uploading documents...\n");
UploadDocuments(ingesterClient);
Da es sich hierbei um eine Konsolen-App handelt, die alle Befehle sequenziell ausführt, fügen wir eine Wartezeit von 2 Sekunden zwischen der Indizierung und Abfragen hinzu.
// 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);
Die Verzögerung von zwei Sekunden dient zur Kompensierung der Indizierung. Diese erfolgt asynchron, sodass alle Dokumente vor der Ausführung der Abfragen indiziert werden können. Die Programmierung einer solchen Verzögerung ist in der Regel nur in Demos, bei Tests und in Beispielanwendungen erforderlich.
Durchsuchen eines Index
Abfrageergebnisse können abgerufen werden, sobald das erste Dokument indiziert wurde. Mit dem Testen des Index sollte aber gewartet werden, bis alle Dokumente indiziert wurden.
In diesem Abschnitt werden zwei Funktionen hinzugefügt: Abfragelogik und Ergebnisse. Verwenden Sie für Abfragen die Search-Methode. Diese Methode akzeptiert Suchtext (die Abfragezeichenfolge) und andere Optionen.
Die SearchResults-Klasse stellt die Ergebnisse dar.
In Program.cs gibt die WriteDocuments
-Methode Suchergebnisse in der Konsole aus.
// 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();
}
Abfragebeispiel 1
Die RunQueries
-Methode führt Abfragen aus und gibt Ergebnisse zurück. Bei den Ergebnissen handelt es sich um Objekte vom Typ „Hotel“. In diesem Beispiel werden die Methodensignatur und die erste Abfrage veranschaulicht. Mit dieser Abfrage wird der Select
-Parameter veranschaulicht, mit dem Sie das Ergebnis erstellen können, indem Sie ausgewählte Felder aus dem Dokument verwenden.
// 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
}
Abfragebeispiel 2
Suchen Sie in der zweiten Abfrage nach einem Begriff, und fügen Sie einen Filter hinzu, mit dem Dokumente mit einer höheren Bewertung als 4 ausgewählt werden. Sortieren Sie dann nach Bewertung in absteigender Reihenfolge. Ein Filter ist ein boolescher Ausdruck, der für Felder vom Typ IsFilterable in einem Index ausgewertet wird. Filterabfragen schließen Werte ein oder aus. Daher ist einer Filterabfrage keine Relevanzbewertung zugeordnet.
// 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);
Abfragebeispiel 3
Mit der dritten Abfrage wird searchFields
veranschaulicht, um einen Volltextsuche-Vorgang auf bestimmte Felder festzulegen.
// 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);
Abfragebeispiel 4
Mit der vierten Abfrage werden facets
veranschaulicht, die zum Strukturieren einer Facettennavigationsstruktur verwendet werden können.
// 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);
Abfragebeispiel 5
Bei der fünften Abfrage wird ein bestimmtes Dokument zurückgegeben. Eine Dokumentsuche ist eine typische Antwort auf das OnClick
-Ereignis in einem Resultset.
// 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);
Abfragebeispiel 6
Mit der letzten Abfrage wird die Syntax für die automatische Vervollständigung veranschaulicht. Hierbei wird die Teileingabe sa eines Benutzers simuliert, für die sich zwei mögliche Übereinstimmungen in den „sourceFields“ ergeben, die der im Index definierten Vorschlagsfunktion zugeordnet sind.
// Query 6
Console.WriteLine("Query #6: Call Autocomplete on HotelName that starts with 'sa'...\n");
var autoresponse = searchClient.Autocomplete("sa", "sg");
WriteDocuments(autoresponse);
Zusammenfassung der Abfragen
Die obigen Abfragen verdeutlichen mehrere Möglichkeiten zum Abgleichen von Begriffen in einer Abfrage: Volltextsuche, Filter und AutoVervollständigen.
Für die Volltextsuche und Filter wird die SearchClient.Search-Methode verwendet. Eine Suchabfrage kann in der searchText
-Zeichenfolge und ein Filterausdruck kann in der Filter-Eigenschaft der SearchOptions-Klasse übergeben werden. Um ohne Suche zu filtern, übergeben Sie einfach "*"
für den Parameter searchText
der Search-Methode. Wenn Sie ohne Filter suchen möchten, legen Sie die Eigenschaft Filter
nicht fest, oder übergeben Sie einfach keine SearchOptions
-Instanz.
Erfahren Sie, wie Sie die Clientbibliothek Azure.Search.Documents verwenden, um einen Suchindex mithilfe von Beispieldaten für die Volltextsuche zu erstellen, zu laden und abzufragen. Die Volltextsuche verwendet Apache Lucene für die Indizierung und Abfragen sowie einen BM25-Bewertungsalgorithmus für die Bewertung von Ergebnissen.
In diesem Schnellstart wird der kleine Index „hotels-quickstart“, der Daten zu vier Hotels enthält, erstellt und abgefragt.
Tipp
Sie können den Quellcode herunterladen, um mit einem fertigen Projekt zu beginnen, oder diese Schritte ausführen, um ein eigenes zu erstellen.
Voraussetzungen
- Ein aktives Azure-Abonnement. (Kostenloses Abonnement erstellen)
- Ein Azure AI Search-Dienst. Erstellen Sie einen Dienst, sofern nicht bereits geschehen. Sie können einen Free-Tarif für diesen Schnellstart verwenden.
Voraussetzungen für Microsoft Entra ID
Für die empfohlene schlüssellose Authentifizierung mit Microsoft Entra ID müssen Sie:
- Die Azure CLI installieren, die für die schlüssellose Authentifizierung mit Microsoft Entra ID verwendet wird
- Weisen Sie Ihrem Benutzerkonto die beiden Rollen
Search Service Contributor
undSearch Index Data Contributor
zu. Sie können Rollen im Azure-Portal unter Zugriffssteuerung (IAM)>Rollenzuweisung hinzufügen zuweisen. Weitere Informationen finden Sie unter Herstellen einer Verbindung mit Azure KI-Suche mithilfe von Rollen.
Abrufen von Ressourceninformationen
Sie müssen die folgenden Informationen abrufen, um Ihre Anwendung bei Ihrem Azure KI-Suche-Dienst zu authentifizieren:
Variablenname | Wert |
---|---|
SEARCH_API_ENDPOINT |
Diesen Wert finden Sie im Azure-Portal. Wählen Sie Ihren Suchdienst und dann im linken Menü die Option Übersicht aus. Der URL-Wert unter Essentials ist der Endpunkt, den Sie benötigen. Ein Beispiel für einen Endpunkt ist https://mydemo.search.windows.net . |
Erfahren Sie mehr über schlüssellose Authentifizierung und das Festlegen von Umgebungsvariablen.
Einrichten
Das Beispiel in diesem Schnellstart funktioniert mit der Java-Runtime. Installieren Sie ein Java Development Kit wie z. B. Azul Zulu OpenJDK. Der Microsoft-Build von OpenJDK oder Ihr bevorzugtes JDK sollte ebenfalls funktionieren.
Installieren Sie Apache Maven. Führen Sie dann
mvn -v
aus, um die erfolgreiche Installation zu bestätigen.Erstellen Sie im Stammverzeichnis Ihres Projekts eine neue Datei
pom.xml
, und kopieren Sie folgende Code in diese Datei:<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>
Installieren Sie die Abhängigkeiten, einschließlich der Clientbibliothek von Azure KI-Suche (Azure.Search.Documents) für Java und der Azure Identity-Clientbibliothek für Java mit:
mvn clean dependency:copy-dependencies
Melden Sie sich für die empfohlene schlüssellose Authentifizierung mit Microsoft Entra ID mit dem folgenden Befehl bei Azure an:
az login
Erstellen, Laden und Abfragen eines Suchindexes
Im vorherigen Abschnitt Einrichten haben Sie die Clientbibliothek von Azure KI-Suche und andere Abhängigkeiten installiert.
In diesem Abschnitt fügen Sie Code hinzu, um einen Suchindex zu erstellen, ihn mit Dokumenten zu laden und Abfragen auszuführen. Sie führen das Programm aus, um die Ergebnisse in der Konsole anzuzeigen. Eine ausführliche Erläuterung des Codes finden Sie im Abschnitt Erläuterung des Codes.
Der Beispielcode in diesem Schnellstart verwendet Microsoft Entra ID für die empfohlene schlüssellose Authentifizierung. Wenn Sie einen API-Schlüssel verwenden möchten, können Sie das DefaultAzureCredential
-Objekt durch ein AzureKeyCredential
-Objekt ersetzen.
String searchServiceEndpoint = "https://<Put your search service NAME here>.search.windows.net/";
DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();
Erstellen Sie eine neue Datei mit dem Namen App.java, und fügen Sie den folgenden Code in App.java ein:
import java.util.Arrays; import java.util.ArrayList; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.time.LocalDateTime; import java.time.LocalDate; import java.time.LocalTime; import com.azure.core.util.Configuration; import com.azure.core.util.Context; import com.azure.identity.DefaultAzureCredential; import com.azure.identity.DefaultAzureCredentialBuilder; import com.azure.search.documents.SearchClient; import com.azure.search.documents.SearchClientBuilder; import com.azure.search.documents.indexes.SearchIndexClient; import com.azure.search.documents.indexes.SearchIndexClientBuilder; import com.azure.search.documents.indexes.models.IndexDocumentsBatch; import com.azure.search.documents.models.SearchOptions; import com.azure.search.documents.indexes.models.SearchIndex; import com.azure.search.documents.indexes.models.SearchSuggester; import com.azure.search.documents.util.AutocompletePagedIterable; import com.azure.search.documents.util.SearchPagedIterable; public class App { public static void main(String[] args) { // Your search service endpoint "https://<Put your search service NAME here>.search.windows.net/"; // Use the recommended keyless credential instead of the AzureKeyCredential credential. DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build(); //AzureKeyCredential credential = new AzureKeyCredential("<Your search service admin key>"); // Create a SearchIndexClient to send create/delete index commands SearchIndexClient searchIndexClient = new SearchIndexClientBuilder() .endpoint(searchServiceEndpoint) .credential(credential) .buildClient(); // Create a SearchClient to load and query documents String indexName = "hotels-quickstart-java"; SearchClient searchClient = new SearchClientBuilder() .endpoint(searchServiceEndpoint) .credential(credential) .indexName(indexName) .buildClient(); // Create Search Index for Hotel model searchIndexClient.createOrUpdateIndex( new SearchIndex(indexName, SearchIndexClient.buildSearchFields(Hotel.class, null)) .setSuggesters(new SearchSuggester("sg", Arrays.asList("HotelName")))); // Upload sample hotel documents to the Search Index uploadDocuments(searchClient); // Wait 2 seconds for indexing to complete before starting queries (for demo and console-app purposes only) System.out.println("Waiting for indexing...\n"); try { Thread.sleep(2000); } catch (InterruptedException e) { } // Call the RunQueries method to invoke a series of queries System.out.println("Starting queries...\n"); RunQueries(searchClient); // End the program System.out.println("Complete.\n"); } // Upload documents in a single Upload request. private static void uploadDocuments(SearchClient searchClient) { var hotelList = new ArrayList<Hotel>(); var hotel = new Hotel(); hotel.hotelId = "1"; hotel.hotelName = "Stay-Kay City Hotel"; hotel.description = "The hotel is ideally located on the main commercial artery of the city in the heart of New York. A few minutes away is Time's Square and the historic centre of the city, as well as other places of interest that make New York one of America's most attractive and cosmopolitan cities."; hotel.descriptionFr = "L'hôtel est idéalement situé sur la principale artère commerciale de la ville en plein cœur de New York. A quelques minutes se trouve la place du temps et le centre historique de la ville, ainsi que d'autres lieux d'intérêt qui font de New York l'une des villes les plus attractives et cosmopolites de l'Amérique."; hotel.category = "Boutique"; hotel.tags = new String[] { "pool", "air conditioning", "concierge" }; hotel.parkingIncluded = false; hotel.lastRenovationDate = OffsetDateTime.of(LocalDateTime.of(LocalDate.of(1970, 1, 18), LocalTime.of(0, 0)), ZoneOffset.UTC); hotel.rating = 3.6; hotel.address = new Address(); hotel.address.streetAddress = "677 5th Ave"; hotel.address.city = "New York"; hotel.address.stateProvince = "NY"; hotel.address.postalCode = "10022"; hotel.address.country = "USA"; hotelList.add(hotel); hotel = new Hotel(); hotel.hotelId = "2"; hotel.hotelName = "Old Century Hotel"; hotel.description = "The hotel is situated in a nineteenth century plaza, which has been expanded and renovated to the highest architectural standards to create a modern, functional and first-class hotel in which art and unique historical elements coexist with the most modern comforts."; hotel.descriptionFr = "L'hôtel est situé dans une place du XIXe siècle, qui a été agrandie et rénovée aux plus hautes normes architecturales pour créer un hôtel moderne, fonctionnel et de première classe dans lequel l'art et les éléments historiques uniques coexistent avec le confort le plus moderne."; hotel.category = "Boutique"; hotel.tags = new String[] { "pool", "free wifi", "concierge" }; hotel.parkingIncluded = false; hotel.lastRenovationDate = OffsetDateTime.of(LocalDateTime.of(LocalDate.of(1979, 2, 18), LocalTime.of(0, 0)), ZoneOffset.UTC); hotel.rating = 3.60; hotel.address = new Address(); hotel.address.streetAddress = "140 University Town Center Dr"; hotel.address.city = "Sarasota"; hotel.address.stateProvince = "FL"; hotel.address.postalCode = "34243"; hotel.address.country = "USA"; hotelList.add(hotel); hotel = new Hotel(); hotel.hotelId = "3"; hotel.hotelName = "Gastronomic Landscape Hotel"; hotel.description = "The Hotel stands out for its gastronomic excellence under the management of William Dough, who advises on and oversees all of the Hotel’s restaurant services."; hotel.descriptionFr = "L'hôtel est situé dans une place du XIXe siècle, qui a été agrandie et rénovée aux plus hautes normes architecturales pour créer un hôtel moderne, fonctionnel et de première classe dans lequel l'art et les éléments historiques uniques coexistent avec le confort le plus moderne."; hotel.category = "Resort and Spa"; hotel.tags = new String[] { "air conditioning", "bar", "continental breakfast" }; hotel.parkingIncluded = true; hotel.lastRenovationDate = OffsetDateTime.of(LocalDateTime.of(LocalDate.of(2015, 9, 20), LocalTime.of(0, 0)), ZoneOffset.UTC); hotel.rating = 4.80; hotel.address = new Address(); hotel.address.streetAddress = "3393 Peachtree Rd"; hotel.address.city = "Atlanta"; hotel.address.stateProvince = "GA"; hotel.address.postalCode = "30326"; hotel.address.country = "USA"; hotelList.add(hotel); hotel = new Hotel(); hotel.hotelId = "4"; hotel.hotelName = "Sublime Palace Hotel"; hotel.description = "Sublime Palace Hotel is located in the heart of the historic center of Sublime in an extremely vibrant and lively area within short walking distance to the sites and landmarks of the city and is surrounded by the extraordinary beauty of churches, buildings, shops and monuments. Sublime Palace is part of a lovingly restored 1800 palace."; hotel.descriptionFr = "Le Sublime Palace Hotel est situé au coeur du centre historique de sublime dans un quartier extrêmement animé et vivant, à courte distance de marche des sites et monuments de la ville et est entouré par l'extraordinaire beauté des églises, des bâtiments, des commerces et Monuments. Sublime Palace fait partie d'un Palace 1800 restauré avec amour."; hotel.category = "Boutique"; hotel.tags = new String[] { "concierge", "view", "24-hour front desk service" }; hotel.parkingIncluded = true; hotel.lastRenovationDate = OffsetDateTime.of(LocalDateTime.of(LocalDate.of(1960, 2, 06), LocalTime.of(0, 0)), ZoneOffset.UTC); hotel.rating = 4.60; hotel.address = new Address(); hotel.address.streetAddress = "7400 San Pedro Ave"; hotel.address.city = "San Antonio"; hotel.address.stateProvince = "TX"; hotel.address.postalCode = "78216"; hotel.address.country = "USA"; hotelList.add(hotel); var batch = new IndexDocumentsBatch<Hotel>(); batch.addMergeOrUploadActions(hotelList); try { searchClient.indexDocuments(batch); } catch (Exception e) { e.printStackTrace(); // If for some reason any documents are dropped during indexing, you can compensate by delaying and // retrying. This simple demo just logs failure and continues System.err.println("Failed to index some of the documents"); } } // Write search results to console private static void WriteSearchResults(SearchPagedIterable searchResults) { searchResults.iterator().forEachRemaining(result -> { Hotel hotel = result.getDocument(Hotel.class); System.out.println(hotel); }); System.out.println(); } // Write autocomplete results to console private static void WriteAutocompleteResults(AutocompletePagedIterable autocompleteResults) { autocompleteResults.iterator().forEachRemaining(result -> { String text = result.getText(); System.out.println(text); }); System.out.println(); } // Run queries, use WriteDocuments to print output private static void RunQueries(SearchClient searchClient) { // Query 1 System.out.println("Query #1: Search on empty term '*' to return all documents, showing a subset of fields...\n"); SearchOptions options = new SearchOptions(); options.setIncludeTotalCount(true); options.setFilter(""); options.setOrderBy(""); options.setSelect("HotelId", "HotelName", "Address/City"); WriteSearchResults(searchClient.search("*", options, Context.NONE)); // Query 2 System.out.println("Query #2: Search on 'hotels', filter on 'Rating gt 4', sort by Rating in descending order...\n"); options = new SearchOptions(); options.setFilter("Rating gt 4"); options.setOrderBy("Rating desc"); options.setSelect("HotelId", "HotelName", "Rating"); WriteSearchResults(searchClient.search("hotels", options, Context.NONE)); // Query 3 System.out.println("Query #3: Limit search to specific fields (pool in Tags field)...\n"); options = new SearchOptions(); options.setSearchFields("Tags"); options.setSelect("HotelId", "HotelName", "Tags"); WriteSearchResults(searchClient.search("pool", options, Context.NONE)); // Query 4 System.out.println("Query #4: Facet on 'Category'...\n"); options = new SearchOptions(); options.setFilter(""); options.setFacets("Category"); options.setSelect("HotelId", "HotelName", "Category"); WriteSearchResults(searchClient.search("*", options, Context.NONE)); // Query 5 System.out.println("Query #5: Look up a specific document...\n"); Hotel lookupResponse = searchClient.getDocument("3", Hotel.class); System.out.println(lookupResponse.hotelId); System.out.println(); // Query 6 System.out.println("Query #6: Call Autocomplete on HotelName that starts with 's'...\n"); WriteAutocompleteResults(searchClient.autocomplete("s", "sg")); } }
Erstellen Sie eine neue Datei mit dem Namen Hotel.java, und fügen Sie den folgenden Code in Hotel.java ein:
import com.azure.search.documents.indexes.SearchableField; import com.azure.search.documents.indexes.SimpleField; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.annotation.JsonInclude.Include; import java.time.OffsetDateTime; /** * Model class representing a hotel. */ @JsonInclude(Include.NON_NULL) public class Hotel { /** * Hotel ID */ @JsonProperty("HotelId") @SimpleField(isKey = true) public String hotelId; /** * Hotel name */ @JsonProperty("HotelName") @SearchableField(isSortable = true) public String hotelName; /** * Description */ @JsonProperty("Description") @SearchableField(analyzerName = "en.microsoft") public String description; /** * French description */ @JsonProperty("DescriptionFr") @SearchableField(analyzerName = "fr.lucene") public String descriptionFr; /** * Category */ @JsonProperty("Category") @SearchableField(isFilterable = true, isSortable = true, isFacetable = true) public String category; /** * Tags */ @JsonProperty("Tags") @SearchableField(isFilterable = true, isFacetable = true) public String[] tags; /** * Whether parking is included */ @JsonProperty("ParkingIncluded") @SimpleField(isFilterable = true, isSortable = true, isFacetable = true) public Boolean parkingIncluded; /** * Last renovation time */ @JsonProperty("LastRenovationDate") @SimpleField(isFilterable = true, isSortable = true, isFacetable = true) public OffsetDateTime lastRenovationDate; /** * Rating */ @JsonProperty("Rating") @SimpleField(isFilterable = true, isSortable = true, isFacetable = true) public Double rating; /** * Address */ @JsonProperty("Address") public Address address; @Override public String toString() { try { return new ObjectMapper().writeValueAsString(this); } catch (JsonProcessingException e) { e.printStackTrace(); return ""; } } }
Erstellen Sie eine neue Datei mit dem Namen Address.java, und fügen Sie den folgenden Code in Address.java ein:
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; }
Führen Sie Ihre neue Konsolenanwendung aus:
javac Address.java App.java Hotel.java -cp ".;target\dependency\*" java -cp ".;target\dependency\*" App
Erläutern des Codes
In den vorherigen Abschnitten haben Sie eine neue Konsolenanwendung erstellt und die Clientbibliothek von Azure KI-Suche installiert. Sie haben Code hinzugefügt, um einen Suchindex zu erstellen, ihn mit Dokumenten zu laden und Abfragen auszuführen. Sie haben das Programm ausgeführt, um die Ergebnisse in der Konsole anzuzeigen.
In diesem Abschnitt erläutern wir den Code, den Sie der Konsolenanwendung hinzugefügt haben.
Erstellen eines Suchclients
In App.java haben Sie zwei Clients erstellt:
- SearchIndexClient erstellt den Index.
- SearchClient lädt und fragt einen vorhandenen Index ab.
Beide Clients benötigen den Suchdienst-Endpunkt und die Anmeldeinformationen, die weiter oben im Abschnitt „Ressourceninformationen“ beschrieben wurden.
Der Beispielcode in diesem Schnellstart verwendet Microsoft Entra ID für die empfohlene schlüssellose Authentifizierung. Wenn Sie einen API-Schlüssel verwenden möchten, können Sie das DefaultAzureCredential
-Objekt durch ein AzureKeyCredential
-Objekt ersetzen.
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 . . .
}
Erstellen eines Index
In dieser Schnellstartanleitung wird ein Hotelindex erstellt, in den Sie Hoteldaten laden und Abfragen dafür ausführen. In diesem Schritt definieren Sie die Felder im Index. Jede Felddefinition enthält einen Namen, einen Datentyp und Attribute, die bestimmen, wie das Feld verwendet wird.
In diesem Beispiel werden aus Gründen der Einfachheit und Lesbarkeit synchrone Methoden der Bibliothek Azure.Search.Documents verwendet. In Produktionsszenarien sollten Sie jedoch asynchrone Methoden verwenden, um Ihre App skalierbar und reaktionsfähig zu halten. So würden Sie beispielsweise CreateIndexAsync anstatt CreateIndex verwenden.
Definieren der Strukturen
Sie haben zwei Hilfsklassen erstellt, Hotel.java und Address.java, um die Struktur eines Hoteldokuments und seiner Adresse zu definieren. Die Klasse „Hotel“ enthält Felder für Hotel-ID, Name, Beschreibung, Kategorie, Tags, Parkplätze, Renovierungsdatum, Bewertung und Adresse. Die Klasse „Address“ enthält Felder für Straße und Hausnummer, Ort, Bundesland/Kanton, Postleitzahl und Land/Region.
In der Azure.Search.Documents-Clientbibliothek können Sie SearchableField und SimpleField verwenden, um Felddefinitionen zu optimieren.
-
SimpleField
kann ein beliebiger Datentyp sein, ist nie durchsuchbar (wird bei Volltextsuchabfragen ignoriert) und ist abrufbar (nicht ausgeblendet). Andere Attribute sind standardmäßig deaktiviert, können jedoch aktiviert werden. Sie können ein SimpleField-Objekt für Dokument-IDs oder Felder verwenden, die nur in Filtern, Facets oder Bewertungsprofilen verwendet werden. Sofern dies der Fall ist, stellen Sie sicher, dass Sie alle Attribute anwenden, die für das Szenario erforderlich sind, z. B. „IsKey = true“ für eine Dokument-ID. -
SearchableField
muss eine Zeichenfolge sein und ist immer „durchsuchbar“ und „abrufbar“. Andere Attribute sind standardmäßig deaktiviert, können jedoch aktiviert werden. Da dieser Feldtyp durchsuchbar ist, unterstützt er Synonyme und die gesamte Palette der Eigenschaften des Analysetools.
Ob Sie die grundlegende SearchField
-API oder eines der Hilfsmodelle verwenden, müssen Sie Filter-, Facet- und Sortierattribute explizit aktivieren. Beispielsweise müssen isFilterable
, isSortable
und isFacetable
explizit mit Attributen versehen werden, wie im vorherigen Beispiel gezeigt.
Erstellen des Suchindex
In App.java
erstellen Sie ein SearchIndex
-Objekt in der main
-Methode und rufen dann die createOrUpdateIndex
-Methode auf, um den Index in Ihrem Suchdienst zu erstellen. Der Index enthält auch ein SearchSuggester
-Element, um die automatische Vervollständigung für die angegebenen Felder zu ermöglichen.
// Create Search Index for Hotel model
searchIndexClient.createOrUpdateIndex(
new SearchIndex(indexName, SearchIndexClient.buildSearchFields(Hotel.class, null))
.setSuggesters(new SearchSuggester("sg", Arrays.asList("HotelName"))));
Laden von Dokumenten
Azure AI Search durchsucht im Dienst gespeicherte Inhalte. In diesem Schritt laden Sie JSON-Dokumente, die dem erstellten Hotelindex entsprechen.
Bei Azure AI Search sind die Suchdokumente Datenstrukturen, die sowohl Eingaben für die Indizierung als auch Ausgaben von Abfragen sind. Beispiele für Dokumenteingaben aus einer externen Datenquelle wären etwa Zeilen in einer Datenbank, Blobs in Blob Storage oder JSON-Dokumente auf dem Datenträger. In diesem Beispiel nehmen wir eine Abkürzung und betten JSON-Dokumente für vier Hotels direkt in den Code ein.
Beim Hochladen von Dokumenten muss ein IndexDocumentsBatch-Objekt verwendet werden. Ein IndexDocumentsBatch
-Objekt enthält eine Sammlung von IndexActions, und jede dieser Aktionen enthält wiederum ein Dokument und eine Eigenschaft, die Azure AI Search mitteilt, welche Aktion ausgeführt werden soll („upload“, „merge“, „delete“ oder „mergeOrUpload“).
In App.java
erstellen Dokumente und Indexaktionen und übergeben diese dann an IndexDocumentsBatch
. Die folgenden Dokumente entsprechen dem Index „hotels-quickstart“ (gemäß Definition durch die Klasse „hotel“).
private static void uploadDocuments(SearchClient searchClient)
{
var hotelList = new ArrayList<Hotel>();
var hotel = new Hotel();
hotel.hotelId = "1";
hotel.hotelName = "Stay-Kay City Hotel";
hotel.description = "The hotel is ideally located on the main commercial artery of the city in the heart of New York. A few minutes away is Time's Square and the historic centre of the city, as well as other places of interest that make New York one of America's most attractive and cosmopolitan cities.";
hotel.descriptionFr = "L'hôtel est idéalement situé sur la principale artère commerciale de la ville en plein cœur de New York. A quelques minutes se trouve la place du temps et le centre historique de la ville, ainsi que d'autres lieux d'intérêt qui font de New York l'une des villes les plus attractives et cosmopolites de l'Amérique.";
hotel.category = "Boutique";
hotel.tags = new String[] { "pool", "air conditioning", "concierge" };
hotel.parkingIncluded = false;
hotel.lastRenovationDate = OffsetDateTime.of(LocalDateTime.of(LocalDate.of(1970, 1, 18), LocalTime.of(0, 0)), ZoneOffset.UTC);
hotel.rating = 3.6;
hotel.address = new Address();
hotel.address.streetAddress = "677 5th Ave";
hotel.address.city = "New York";
hotel.address.stateProvince = "NY";
hotel.address.postalCode = "10022";
hotel.address.country = "USA";
hotelList.add(hotel);
// REDACTED FOR BREVITY
var batch = new IndexDocumentsBatch<Hotel>();
batch.addMergeOrUploadActions(hotelList);
try
{
searchClient.indexDocuments(batch);
}
catch (Exception e)
{
e.printStackTrace();
// If for some reason any documents are dropped during indexing, you can compensate by delaying and
// retrying. This simple demo just logs failure and continues
System.err.println("Failed to index some of the documents");
}
}
Nachdem Sie das Objekt IndexDocumentsBatch
initialisiert haben, können Sie es an den Index senden, indem Sie indexDocuments für Ihr SearchClient
-Objekt aufrufen.
Sie laden Dokumente mithilfe von „SearchClient“ in main()
, aber für den Vorgang werden auch Administratorrechte für den Dienst benötigt, der normalerweise „SearchIndexClient“ zugeordnet ist. Eine Möglichkeit zum Einrichten dieses Vorgangs ist das Abrufen von „SearchClient“ über SearchIndexClient
(in diesem Beispiel searchIndexClient
).
uploadDocuments(searchClient);
Da es sich hierbei um eine Konsolen-App handelt, die alle Befehle sequenziell ausführt, fügen wir eine Wartezeit von 2 Sekunden zwischen der Indizierung und Abfragen hinzu.
// 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)
{
}
Die Verzögerung von zwei Sekunden dient zur Kompensierung der Indizierung. Diese erfolgt asynchron, sodass alle Dokumente vor der Ausführung der Abfragen indiziert werden können. Die Programmierung einer solchen Verzögerung ist in der Regel nur in Demos, bei Tests und in Beispielanwendungen erforderlich.
Durchsuchen eines Index
Abfrageergebnisse können abgerufen werden, sobald das erste Dokument indiziert wurde. Mit dem Testen des Index sollte aber gewartet werden, bis alle Dokumente indiziert wurden.
In diesem Abschnitt werden zwei Funktionen hinzugefügt: Abfragelogik und Ergebnisse. Verwenden Sie für Abfragen die Search-Methode. Diese Methode akzeptiert Suchtext (die Abfragezeichenfolge) und andere Optionen.
In App.java
gibt die WriteDocuments
-Methode Suchergebnisse in der Konsole aus.
// 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();
}
Abfragebeispiel 1
Die RunQueries
-Methode führt Abfragen aus und gibt Ergebnisse zurück. Bei den Ergebnissen handelt es sich um Objekte vom Typ „Hotel“. In diesem Beispiel werden die Methodensignatur und die erste Abfrage veranschaulicht. Mit dieser Abfrage wird der Select
-Parameter veranschaulicht, mit dem Sie das Ergebnis erstellen können, indem Sie ausgewählte Felder aus dem Dokument verwenden.
// 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));
}
Abfragebeispiel 2
Suchen Sie in der zweiten Abfrage nach einem Begriff, und fügen Sie einen Filter hinzu, mit dem Dokumente mit einer höheren Bewertung als 4 ausgewählt werden. Sortieren Sie dann nach Bewertung in absteigender Reihenfolge. Ein Filter ist ein boolescher Ausdruck, der für Felder vom Typ isFilterable
in einem Index ausgewertet wird. Filterabfragen schließen Werte ein oder aus. Daher ist einer Filterabfrage keine Relevanzbewertung zugeordnet.
// 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));
Abfragebeispiel 3
Mit der dritten Abfrage wird searchFields
veranschaulicht, um einen Volltextsuche-Vorgang auf bestimmte Felder festzulegen.
// 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));
Abfragebeispiel 4
Mit der vierten Abfrage werden facets
veranschaulicht, die zum Strukturieren einer Facettennavigationsstruktur verwendet werden können.
// 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));
Abfragebeispiel 5
Bei der fünften Abfrage wird ein bestimmtes Dokument zurückgegeben.
// 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();
Abfragebeispiel 6
Mit der letzten Abfrage wird die Syntax für die automatische Vervollständigung veranschaulicht. Hierbei wird die Teileingabe s eines Benutzers simuliert, für die sich zwei mögliche Übereinstimmungen in den sourceFields
ergeben, die der im Index definierten Vorschlagsfunktion zugeordnet sind.
// Query 6
System.out.println("Query #6: Call Autocomplete on HotelName that starts with 's'...\n");
WriteAutocompleteResults(searchClient.autocomplete("s", "sg"));
Zusammenfassung der Abfragen
Die obigen Abfragen verdeutlichen mehrere Möglichkeiten zum Abgleichen von Begriffen in einer Abfrage: Volltextsuche, Filter und AutoVervollständigen.
Für die Volltextsuche und Filter wird die SearchClient.search-Methode verwendet. Eine Suchabfrage kann in der searchText
-Zeichenfolge und ein Filterausdruck kann in der filter
-Eigenschaft der SearchOptions-Klasse übergeben werden. Um ohne Suche zu filtern, übergeben Sie einfach „*“ für den Parameter searchText
der search
-Methode. Wenn Sie ohne Filter suchen möchten, legen Sie die Eigenschaft filter
nicht fest, oder übergeben Sie einfach keine SearchOptions
-Instanz.
Erfahren Sie, wie Sie die Clientbibliothek Azure.Search.Documents verwenden, um einen Suchindex mithilfe von Beispieldaten für die Volltextsuche zu erstellen, zu laden und abzufragen. Die Volltextsuche verwendet Apache Lucene für die Indizierung und Abfragen sowie einen BM25-Bewertungsalgorithmus für die Bewertung von Ergebnissen.
In diesem Schnellstart wird der kleine Index „hotels-quickstart“, der Daten zu vier Hotels enthält, erstellt und abgefragt.
Tipp
Sie können den Quellcode herunterladen, um mit einem fertigen Projekt zu beginnen, oder diese Schritte ausführen, um ein eigenes zu erstellen.
Voraussetzungen
- Ein aktives Azure-Abonnement. (Kostenloses Abonnement erstellen)
- Ein Azure AI Search-Dienst. Erstellen Sie einen Dienst, sofern nicht bereits geschehen. Sie können einen Free-Tarif für diesen Schnellstart verwenden.
Voraussetzungen für Microsoft Entra ID
Für die empfohlene schlüssellose Authentifizierung mit Microsoft Entra ID müssen Sie:
- Die Azure CLI installieren, die für die schlüssellose Authentifizierung mit Microsoft Entra ID verwendet wird
- Weisen Sie Ihrem Benutzerkonto die beiden Rollen
Search Service Contributor
undSearch Index Data Contributor
zu. Sie können Rollen im Azure-Portal unter Zugriffssteuerung (IAM)>Rollenzuweisung hinzufügen zuweisen. Weitere Informationen finden Sie unter Herstellen einer Verbindung mit Azure KI-Suche mithilfe von Rollen.
Abrufen von Ressourceninformationen
Sie müssen die folgenden Informationen abrufen, um Ihre Anwendung bei Ihrem Azure KI-Suche-Dienst zu authentifizieren:
Variablenname | Wert |
---|---|
SEARCH_API_ENDPOINT |
Diesen Wert finden Sie im Azure-Portal. Wählen Sie Ihren Suchdienst und dann im linken Menü die Option Übersicht aus. Der URL-Wert unter Essentials ist der Endpunkt, den Sie benötigen. Ein Beispiel für einen Endpunkt ist https://mydemo.search.windows.net . |
Erfahren Sie mehr über schlüssellose Authentifizierung und das Festlegen von Umgebungsvariablen.
Einrichten
Erstellen Sie einen neuen Ordner
full-text-quickstart
für die Anwendung, und öffnen Sie Visual Studio Code in diesem Ordner mit dem folgenden Befehl:mkdir full-text-quickstart && cd full-text-quickstart
Erstellen Sie
package.json
mit dem folgenden Befehl:npm init -y
Installieren Sie die Clientbibliothek von Azure KI-Suche (Azure.Search.Documents) für JavaScript mit:
npm install @azure/search-documents
Installieren Sie für die empfohlene kennwortlose Authentifizierung die Azure Identity-Clientbibliothek mit:
npm install @azure/identity
Erstellen, Laden und Abfragen eines Suchindexes
Im vorherigen Abschnitt Einrichten haben Sie die Clientbibliothek von Azure KI-Suche und andere Abhängigkeiten installiert.
In diesem Abschnitt fügen Sie Code hinzu, um einen Suchindex zu erstellen, ihn mit Dokumenten zu laden und Abfragen auszuführen. Sie führen das Programm aus, um die Ergebnisse in der Konsole anzuzeigen. Eine ausführliche Erläuterung des Codes finden Sie im Abschnitt Erläuterung des Codes.
Der Beispielcode in diesem Schnellstart verwendet Microsoft Entra ID für die empfohlene schlüssellose Authentifizierung. Wenn Sie einen API-Schlüssel verwenden möchten, können Sie das DefaultAzureCredential
-Objekt durch ein AzureKeyCredential
-Objekt ersetzen.
String searchServiceEndpoint = "https://<Put your search service NAME here>.search.windows.net/";
DefaultAzureCredential credential = new DefaultAzureCredentialBuilder().build();
Erstellen Sie eine neue Datei mit dem Namen index.js, und fügen Sie den folgenden Code in index.js ein:
// Import from the @azure/search-documents library import { SearchIndexClient, odata } from "@azure/search-documents"; // Import from the Azure Identity library import { DefaultAzureCredential } from "@azure/identity"; // Importing the hotels sample data import hotelData from './hotels.json' assert { type: "json" }; // Load the .env file if it exists import * as dotenv from "dotenv"; dotenv.config(); // Defining the index definition const indexDefinition = { "name": "hotels-quickstart", "fields": [ { "name": "HotelId", "type": "Edm.String", "key": true, "filterable": true }, { "name": "HotelName", "type": "Edm.String", "searchable": true, "filterable": false, "sortable": true, "facetable": false }, { "name": "Description", "type": "Edm.String", "searchable": true, "filterable": false, "sortable": false, "facetable": false, "analyzerName": "en.lucene" }, { "name": "Description_fr", "type": "Edm.String", "searchable": true, "filterable": false, "sortable": false, "facetable": false, "analyzerName": "fr.lucene" }, { "name": "Category", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true }, { "name": "Tags", "type": "Collection(Edm.String)", "searchable": true, "filterable": true, "sortable": false, "facetable": true }, { "name": "ParkingIncluded", "type": "Edm.Boolean", "filterable": true, "sortable": true, "facetable": true }, { "name": "LastRenovationDate", "type": "Edm.DateTimeOffset", "filterable": true, "sortable": true, "facetable": true }, { "name": "Rating", "type": "Edm.Double", "filterable": true, "sortable": true, "facetable": true }, { "name": "Address", "type": "Edm.ComplexType", "fields": [ { "name": "StreetAddress", "type": "Edm.String", "filterable": false, "sortable": false, "facetable": false, "searchable": true }, { "name": "City", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true }, { "name": "StateProvince", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true }, { "name": "PostalCode", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true }, { "name": "Country", "type": "Edm.String", "searchable": true, "filterable": true, "sortable": true, "facetable": true } ] } ], "suggesters": [ { "name": "sg", "searchMode": "analyzingInfixMatching", "sourceFields": [ "HotelName" ] } ] }; async function main() { // Your search service endpoint const searchServiceEndpoint = "https://<Put your search service NAME here>.search.windows.net/"; // Use the recommended keyless credential instead of the AzureKeyCredential credential. const credential = new DefaultAzureCredential(); //const credential = new AzureKeyCredential(Your search service admin key); // Create a SearchIndexClient to send create/delete index commands const searchIndexClient = new SearchIndexClient(searchServiceEndpoint, credential); // Creating a search client to upload documents and issue queries const indexName = "hotels-quickstart"; const searchClient = searchIndexClient.getSearchClient(indexName); console.log('Checking if index exists...'); await deleteIndexIfExists(searchIndexClient, indexName); console.log('Creating index...'); let index = await searchIndexClient.createIndex(indexDefinition); console.log(`Index named ${index.name} has been created.`); console.log('Uploading documents...'); let indexDocumentsResult = await searchClient.mergeOrUploadDocuments(hotelData['value']); console.log(`Index operations succeeded: ${JSON.stringify(indexDocumentsResult.results[0].succeeded)} `); // waiting one second for indexing to complete (for demo purposes only) sleep(1000); console.log('Querying the index...'); console.log(); await sendQueries(searchClient); } async function deleteIndexIfExists(searchIndexClient, indexName) { try { await searchIndexClient.deleteIndex(indexName); console.log('Deleting index...'); } catch { console.log('Index does not exist yet.'); } } async function sendQueries(searchClient) { // Query 1 console.log('Query #1 - search everything:'); let searchOptions = { includeTotalCount: true, select: ["HotelId", "HotelName", "Rating"] }; let searchResults = await searchClient.search("*", searchOptions); for await (const result of searchResults.results) { console.log(`${JSON.stringify(result.document)}`); } console.log(`Result count: ${searchResults.count}`); console.log(); // Query 2 console.log('Query #2 - search with filter, orderBy, and select:'); let state = 'FL'; searchOptions = { filter: odata `Address/StateProvince eq ${state}`, orderBy: ["Rating desc"], select: ["HotelId", "HotelName", "Rating"] }; searchResults = await searchClient.search("wifi", searchOptions); for await (const result of searchResults.results) { console.log(`${JSON.stringify(result.document)}`); } console.log(); // Query 3 console.log('Query #3 - limit searchFields:'); searchOptions = { select: ["HotelId", "HotelName", "Rating"], searchFields: ["HotelName"] }; searchResults = await searchClient.search("sublime cliff", searchOptions); for await (const result of searchResults.results) { console.log(`${JSON.stringify(result.document)}`); } console.log(); // Query 4 console.log('Query #4 - limit searchFields and use facets:'); searchOptions = { facets: ["Category"], select: ["HotelId", "HotelName", "Rating"], searchFields: ["HotelName"] }; searchResults = await searchClient.search("*", searchOptions); for await (const result of searchResults.results) { console.log(`${JSON.stringify(result.document)}`); } console.log(); // Query 5 console.log('Query #5 - Lookup document:'); let documentResult = await searchClient.getDocument('3'); console.log(`HotelId: ${documentResult.HotelId}; HotelName: ${documentResult.HotelName}`); console.log(); } function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } main().catch((err) => { console.error("The sample encountered an error:", err); });
Erstellen Sie eine Datei mit dem Namen hotels.json, und fügen Sie den folgenden Code in hotels.json ein:
{ "value": [ { "HotelId": "1", "HotelName": "Secret Point Motel", "Description": "The hotel is ideally located on the main commercial artery of the city in the heart of New York. A few minutes away is Time's Square and the historic centre of the city, as well as other places of interest that make New York one of America's most attractive and cosmopolitan cities.", "Description_fr": "L'hôtel est idéalement situé sur la principale artère commerciale de la ville en plein cœur de New York. A quelques minutes se trouve la place du temps et le centre historique de la ville, ainsi que d'autres lieux d'intérêt qui font de New York l'une des villes les plus attractives et cosmopolites de l'Amérique.", "Category": "Boutique", "Tags": ["pool", "air conditioning", "concierge"], "ParkingIncluded": false, "LastRenovationDate": "1970-01-18T00:00:00Z", "Rating": 3.6, "Address": { "StreetAddress": "677 5th Ave", "City": "New York", "StateProvince": "NY", "PostalCode": "10022" } }, { "HotelId": "2", "HotelName": "Twin Dome Motel", "Description": "The hotel is situated in a nineteenth century plaza, which has been expanded and renovated to the highest architectural standards to create a modern, functional and first-class hotel in which art and unique historical elements coexist with the most modern comforts.", "Description_fr": "L'hôtel est situé dans une place du XIXe siècle, qui a été agrandie et rénovée aux plus hautes normes architecturales pour créer un hôtel moderne, fonctionnel et de première classe dans lequel l'art et les éléments historiques uniques coexistent avec le confort le plus moderne.", "Category": "Boutique", "Tags": ["pool", "free wifi", "concierge"], "ParkingIncluded": "false", "LastRenovationDate": "1979-02-18T00:00:00Z", "Rating": 3.6, "Address": { "StreetAddress": "140 University Town Center Dr", "City": "Sarasota", "StateProvince": "FL", "PostalCode": "34243" } }, { "HotelId": "3", "HotelName": "Triple Landscape Hotel", "Description": "The Hotel stands out for its gastronomic excellence under the management of William Dough, who advises on and oversees all of the Hotel’s restaurant services.", "Description_fr": "L'hôtel est situé dans une place du XIXe siècle, qui a été agrandie et rénovée aux plus hautes normes architecturales pour créer un hôtel moderne, fonctionnel et de première classe dans lequel l'art et les éléments historiques uniques coexistent avec le confort le plus moderne.", "Category": "Resort and Spa", "Tags": ["air conditioning", "bar", "continental breakfast"], "ParkingIncluded": "true", "LastRenovationDate": "2015-09-20T00:00:00Z", "Rating": 4.8, "Address": { "StreetAddress": "3393 Peachtree Rd", "City": "Atlanta", "StateProvince": "GA", "PostalCode": "30326" } }, { "HotelId": "4", "HotelName": "Sublime Cliff Hotel", "Description": "Sublime Cliff Hotel is located in the heart of the historic center of Sublime in an extremely vibrant and lively area within short walking distance to the sites and landmarks of the city and is surrounded by the extraordinary beauty of churches, buildings, shops and monuments. Sublime Cliff is part of a lovingly restored 1800 palace.", "Description_fr": "Le sublime Cliff Hotel est situé au coeur du centre historique de sublime dans un quartier extrêmement animé et vivant, à courte distance de marche des sites et monuments de la ville et est entouré par l'extraordinaire beauté des églises, des bâtiments, des commerces et Monuments. Sublime Cliff fait partie d'un Palace 1800 restauré avec amour.", "Category": "Boutique", "Tags": ["concierge", "view", "24-hour front desk service"], "ParkingIncluded": true, "LastRenovationDate": "1960-02-06T00:00:00Z", "Rating": 4.6, "Address": { "StreetAddress": "7400 San Pedro Ave", "City": "San Antonio", "StateProvince": "TX", "PostalCode": "78216" } } ] }
Erstellen Sie eine Datei mit dem Namen hotels_quickstart_index.json, und fügen Sie den folgenden Code in hotels_quickstart_index.json ein:
{ "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" ] } ] }
Melden Sie sich mithilfe des folgenden Befehls bei Azure an:
az login
Führen Sie den JavaScript-Code mit dem folgenden Befehl aus:
node index.js
Erläutern des Codes
Erstellen eines Index
Die Datei hotels_quickstart_index.json definiert, wie Azure KI-Suche mit den Dokumenten verfährt, die Sie im nächsten Schritt laden. Jedes Feld wird durch einen name
identifiziert und hat einen bestimmten type
. Jedes Feld verfügt zudem über eine Reihe von Indexattributen, die angeben, ob Azure AI Search das Feld durchsuchen, filtern, sortieren und facettieren kann. Bei den meisten Feldern handelt es sich um einfache Datentypen, einige wie z.B. AddressType
sind aber komplexe Typen, die es Ihnen ermöglichen, umfangreiche Datenstrukturen in Ihrem Index zu erstellen. Informieren Sie sich weiter über die unterstützten Datentypen und die Indexattribute, die unter Erstellen eines Index (REST) beschrieben sind.
Wenn die Indexdefinition eingerichtet ist, importieren Sie hotels_quickstart_index.json am Anfang von index.js, damit die main-Funktion auf die Indexdefinition zugreifen kann.
const indexDefinition = require('./hotels_quickstart_index.json');
In der main-Funktion erstellen Sie ein SearchIndexClient
-Objekt, das zum Erstellen und Verwalten von Indizes für Azure AI Search verwendet wird.
const indexClient = new SearchIndexClient(endpoint, new AzureKeyCredential(apiKey));
Als nächstes löschen Sie den Index, falls er bereits existiert. Dies ist eine gängige Vorgehensweise für Test-/Democode.
Dazu wird eine einfache Funktion definiert, die versucht, den Index zu löschen.
async function deleteIndexIfExists(indexClient, indexName) {
try {
await indexClient.deleteIndex(indexName);
console.log('Deleting index...');
} catch {
console.log('Index does not exist yet.');
}
}
Um die Funktion auszuführen, wird der Indexname aus der Indexdefinition extrahiert und das indexName
-Objekt zusammen mit dem indexClient
-Objekt an die deleteIndexIfExists()
-Funktion übergeben.
const indexName = indexDefinition["name"];
console.log('Checking if index exists...');
await deleteIndexIfExists(indexClient, indexName);
Danach sind Sie bereit, den Index mit der createIndex()
-Methode zu erstellen.
console.log('Creating index...');
let index = await indexClient.createIndex(indexDefinition);
console.log(`Index named ${index.name} has been created.`);
Laden von Dokumenten
In Azure AI Search sind die Dokumente Datenstrukturen, bei denen es sich sowohl um Eingaben für die Indizierung als auch um Ausgaben von Abfragen handeln kann. Sie können diese Daten per Push an den Index senden oder einen Indexer verwenden. In diesem Fall werden die Dokumente programmseitig per Push an den Index gesendet.
Dokumenteingaben können Zeilen in einer Datenbank, Blobs in einem Blobspeicher oder JSON-Dokumente auf einem Datenträger sein. Ähnlich wie bei der indexDefinition
müssen Sie auch hierbei hotels.json
am Anfang von index.js importieren, damit in der main-Funktion auf die Daten zugegriffen werden kann.
const hotelData = require('./hotels.json');
Um Daten in den Suchindex zu indizieren, müssen Sie nun ein SearchClient
-Objekt erstellen. Während das SearchIndexClient
-Objekt zum Erstellen und Verwalten eines Index verwendet wird, dient das SearchClient
-Objekt zum Hochladen von Dokumenten und Abfragen des Index.
Es gibt zwei Möglichkeiten zum Erstellen einer SearchClient
: Die erste Option besteht darin, ein SearchClient
-Objekt von Grund auf neu zu erstellen:
const searchClient = new SearchClient(endpoint, indexName, new AzureKeyCredential(apiKey));
Alternativ können Sie die getSearchClient()
-Methode des SearchIndexClient
-Objekts verwenden, um das SearchClient
-Objekt zu erstellen:
const searchClient = indexClient.getSearchClient(indexName);
Nachdem der Client definiert wurde, laden Sie die Dokumente in den Suchindex hoch. In diesem Fall verwenden Sie die mergeOrUploadDocuments()
-Methode zum Hochladen der Dokumente, oder Sie führen sie mit einem bestehenden Dokument zusammen, wenn bereits ein Dokument mit demselben Schlüssel existiert.
console.log('Uploading documents...');
let indexDocumentsResult = await searchClient.mergeOrUploadDocuments(hotelData['value']);
console.log(`Index operations succeeded: ${JSON.stringify(indexDocumentsResult.results[0].succeeded)}`);
Durchsuchen eines Index
Nachdem Sie einen Index erstellt und Dokumente hochgeladen haben, können Sie nun Abfragen an den Index senden. In diesem Abschnitt werden fünf verschiedene Abfragen an den Suchindex gesendet, um verschiedene verfügbare Abfragefunktionen zu veranschaulichen.
Die Abfragen werden in einer sendQueries()
-Funktion geschrieben, die in der main-Funktion wie folgt aufgerufen wird:
await sendQueries(searchClient);
Abfragen werden mithilfe der search()
-Methode von searchClient
gesendet. Der erste Parameter ist der Suchtext, und der zweite Parameter gibt die Suchoptionen an.
Abfragebeispiel 1
Die erste Abfrage durchsucht *
, was dem Durchsuchen aller Elemente entspricht, und wählt drei der Felder im Index aus. Es ist ein bewährtes Verfahren, nur die Felder per select
auszuwählen, die Sie benötigen, da das Pullen unnötiger Daten die Latenz Ihrer Abfragen erhöhen kann.
Beim searchOptions
-Objekt für diese Abfrage ist zudem includeTotalCount
auf true
festgelegt, wodurch die Anzahl der gefundenen Treffer zurückgegeben wird.
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
}
Die übrigen unten beschriebenen Abfragen sollten auch der sendQueries()
-Funktion hinzugefügt werden. Sie sind hier aus Gründen der Lesbarkeit getrennt.
Abfragebeispiel 2
In der nächsten Abfrage geben Sie den Suchbegriff "wifi"
an und fügen zudem einen Filter hinzu, um nur Ergebnisse zurückzugeben, deren Zustand gleich 'FL'
ist. Die Ergebnisse werden außerdem nach dem Rating
-Objekt des Hotels sortiert.
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)}`);
}
Abfragebeispiel 3
Anschließend wird die Suche mit dem Parameter searchFields
auf ein einzelnes durchsuchbares Feld beschränkt. Dieser Ansatz ist eine großartige Möglichkeit, Ihre Abfrage effizienter zu gestalten, wenn Sie wissen, dass Sie nur an Übereinstimmungen in bestimmten Feldern interessiert sind.
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();
Abfragebeispiel 4
Eine weitere gängige Option, die in eine Abfrage einbezogen werden kann, ist facets
. Mithilfe von Facetten können Sie Filter auf Ihrer Benutzeroberfläche erstellen, durch die Ihre Benutzern leichter erkennen, nach welchen Werten sie filtern können.
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)}`);
}
Abfragebeispiel 5
Die abschließende Abfrage verwendet die getDocument()
-Methode des searchClient
-Objekts. Auf diese Weise können Sie ein Dokument effizient anhand seines Schlüssels abrufen.
console.log('Query #5 - Lookup document:');
let documentResult = await searchClient.getDocument(key='3')
console.log(`HotelId: ${documentResult.HotelId}; HotelName: ${documentResult.HotelName}`)
Zusammenfassung der Abfragen
Die obigen Abfragen verdeutlichen mehrere Möglichkeiten zum Abgleichen von Begriffen in einer Abfrage: Volltextsuche, Filter und AutoVervollständigen.
Volltextsuche und Filtervorgänge werden mit der searchClient.search
-Methode durchgeführt. Eine Suchanfrage kann in der searchText
-Zeichenfolge übergeben werden, während ein Filterausdruck in der filter
-Eigenschaft der SearchOptions
-Klasse übergeben werden kann. Um ohne Suche zu filtern, übergeben Sie einfach „*“ für den Parameter searchText
der search
-Methode. Wenn Sie ohne Filter suchen möchten, legen Sie die Eigenschaft filter
nicht fest, oder übergeben Sie einfach keine SearchOptions
-Instanz.
Erfahren Sie, wie Sie die Clientbibliothek Azure.Search.Documents verwenden, um einen Suchindex mithilfe von Beispieldaten für die Volltextsuche zu erstellen, zu laden und abzufragen. Die Volltextsuche verwendet Apache Lucene für die Indizierung und Abfragen sowie einen BM25-Bewertungsalgorithmus für die Bewertung von Ergebnissen.
In diesem Schnellstart wird der kleine Index „hotels-quickstart“, der Daten zu vier Hotels enthält, erstellt und abgefragt.
Tipp
Sie können ein fertiges Notebook herunterladen und ausführen.
Voraussetzungen
- Ein aktives Azure-Abonnement. (Kostenloses Abonnement erstellen)
- Ein Azure AI Search-Dienst. Erstellen Sie einen Dienst, sofern nicht bereits geschehen. Sie können einen Free-Tarif für diesen Schnellstart verwenden.
- Visual Studio Code mit der Python-Erweiterung (oder einer entsprechenden IDE), mit Python 3.10 oder höher. Wenn Sie keine geeignete Version von Python installiert haben, können Sie die Anweisungen im VS Code-Tutorial für Python befolgen.
Voraussetzungen für Microsoft Entra ID
Für die empfohlene schlüssellose Authentifizierung mit Microsoft Entra ID müssen Sie:
- Die Azure CLI installieren, die für die schlüssellose Authentifizierung mit Microsoft Entra ID verwendet wird
- Weisen Sie Ihrem Benutzerkonto die beiden Rollen
Search Service Contributor
undSearch Index Data Contributor
zu. Sie können Rollen im Azure-Portal unter Zugriffssteuerung (IAM)>Rollenzuweisung hinzufügen zuweisen. Weitere Informationen finden Sie unter Herstellen einer Verbindung mit Azure KI-Suche mithilfe von Rollen.
Abrufen von Ressourceninformationen
Sie müssen die folgenden Informationen abrufen, um Ihre Anwendung bei Ihrem Azure KI-Suche-Dienst zu authentifizieren:
Variablenname | Wert |
---|---|
SEARCH_API_ENDPOINT |
Diesen Wert finden Sie im Azure-Portal. Wählen Sie Ihren Suchdienst und dann im linken Menü die Option Übersicht aus. Der URL-Wert unter Essentials ist der Endpunkt, den Sie benötigen. Ein Beispiel für einen Endpunkt ist https://mydemo.search.windows.net . |
Erfahren Sie mehr über schlüssellose Authentifizierung und das Festlegen von Umgebungsvariablen.
Erstellen Ihrer Umgebung
Sie führen den Beispielcode in einem Jupyter Notebook aus. Sie müssen also Ihre Umgebung für die Ausführung von Jupyter Notebooks einrichten.
Laden Sie das Beispielnotebook von GitHub herunter, oder kopieren Sie es.
Öffnen Sie das Notebook in Visual Studio Code.
Erstellen Sie eine neue Python-Umgebung, um die für dieses Tutorial erforderlichen Pakete zu installieren.
Wichtig
Installieren Sie keine Pakete in Ihrer globalen Python-Installation. Sie sollten beim Installieren von Python-Paketen immer eine virtuelle oder Conda-Umgebung verwenden, andernfalls können Sie die globale Python-Installation beschädigen.
Die Einrichtung kann eine Minute dauern. Wenn Probleme auftreten, sehen Sie unter Python-Umgebungen in VS Code nach.
Installieren Sie Jupyter Notebooks und den IPython-Kernel für Jupyter Notebooks, falls Sie diese noch nicht haben.
pip install jupyter pip install ipykernel python -m ipykernel install --user --name=.venv
Wählen Sie den Notebook-Kernel aus.
- Klicken Sie im Notebook rechts oben auf Kernel auswählen.
- Wenn
.venv
in der Liste angezeigt wird, wählen Sie es aus. Wenn es nicht angezeigt wird, wählen Sie Anderen Kernel auswählen>Python-Umgebungen>.venv
.
Erstellen, Laden und Abfragen eines Suchindexes
In diesem Abschnitt fügen Sie Code hinzu, um einen Suchindex zu erstellen, ihn mit Dokumenten zu laden und Abfragen auszuführen. Sie führen das Programm aus, um die Ergebnisse in der Konsole anzuzeigen. Eine ausführliche Erläuterung des Codes finden Sie im Abschnitt Erläuterung des Codes.
Stellen Sie sicher, dass das Notebook im
.venv
-Kernel geöffnet ist, wie im vorherigen Abschnitt beschrieben.Führen Sie die erste Codezelle aus, um die erforderlichen Pakete zu installieren, einschließlich azure-search-documents.
! pip install azure-search-documents==11.6.0b1 --quiet ! pip install azure-identity --quiet ! pip install python-dotenv --quiet
Ersetzen Sie den Inhalt der zweiten Codezelle je nach Ihrer Authentifizierungsmethode durch den folgenden Code.
Hinweis
Der Beispielcode in diesem Schnellstart verwendet Microsoft Entra ID für die empfohlene schlüssellose Authentifizierung. Wenn Sie einen API-Schlüssel verwenden möchten, können Sie das
DefaultAzureCredential
-Objekt durch einAzureKeyCredential
-Objekt ersetzen.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"
Entfernen Sie die folgenden beiden Zeilen aus der Codezelle Index erstellen. Anmeldeinformationen werden bereits in der vorherigen Codezelle festgelegt.
from azure.core.credentials import AzureKeyCredential credential = AzureKeyCredential(search_api_key)
Führen Sie die Codezelle Index erstellen aus, um einen Suchindex zu erstellen.
Führen Sie die verbleibenden Codezellen nacheinander aus, um Dokumente zu laden und Abfragen auszuführen.
Erläutern des Codes
Erstellen eines Index
SearchIndexClient
wird zum Erstellen und Verwalten von Indizes für Azure KI-Suche verwendet. Jedes Feld wird durch einen name
identifiziert und hat einen bestimmten type
.
Jedes Feld verfügt zudem über eine Reihe von Indexattributen, die angeben, ob Azure AI Search das Feld durchsuchen, filtern, sortieren und facettieren kann. Bei den meisten Feldern handelt es sich um einfache Datentypen, einige wie z.B. AddressType
sind aber komplexe Typen, die es Ihnen ermöglichen, umfangreiche Datenstrukturen in Ihrem Index zu erstellen. Informieren Sie sich weiter über die unterstützten Datentypen und die Indexattribute, die unter Erstellen eines Index (REST) beschrieben sind.
Erstellen von Dokumentnutzdaten und Hochladen von Dokumenten
Verwenden Sie eine Indexaktion als Vorgangstyp, wie z.B. Hochladen oder Zusammenführen und Hochladen. Die Dokumente stammen von dem Beispiel HotelsData auf GitHub.
Durchsuchen eines Index
Abfrageergebnisse können abgerufen werden, sobald das erste Dokument indiziert wurde. Mit dem Testen des Index sollte aber gewartet werden, bis alle Dokumente indiziert wurden.
Verwenden Sie die Suchmethode von search.client class.
Die Beispielabfragen im Notebook sind:
- Einfache Abfrage: Führt eine leere Suche aus (
search=*
) und gibt eine ungeordnete Liste (search score = 1,0) beliebiger Dokumente zurück. Da keine einschränkenden Kriterien vorhanden sind, umfasst das Ergebnis alle Dokumente. - Begriffsabfrage: Fügt ganze Begriffe zum Suchausdruck hinzu („WLAN“). Bei dieser Abfrage wird angegeben, dass das Ergebnis nur die Felder in der
select
-Anweisung umfasst. Durch die Einschränkung der zurückgegebenen Felder wird die Menge der Daten für die Rückübertragung verringert und die Latenz der Suche reduziert. - Gefilterte Abfrage: Fügt einen Filterausdruck hinzu, der nur Hotels mit einer Bewertung von mehr als vier zurückgibt, sortiert in absteigender Reihenfolge.
- Feldbasierte Eingrenzung: Fügt
search_fields
hinzu, um die Ausführung der Abfrage auf bestimmte Felder zu beschränken. - Facetten: Generiert Facetten für positive Übereinstimmungen, die in den Suchergebnissen gefunden wurden. Es gibt keine Nulltreffer. Wenn die Suchergebnisse den Begriff wifi nicht enthalten, wird wifi auch nicht in der Struktur der Facettennavigation angezeigt.
- Nachschlagen eines Dokuments: Gibt ein Dokument basierend auf seinem Schlüssel zurück. Dieser Vorgang ist nützlich, wenn Sie Drillthrough bereitstellen möchten, wenn Benutzer ein Element in einem Suchergebnis auswählen.
- AutoVervollständigen: Gibt potenzielle Übereinstimmungen an, während Benutzende in das Suchfeld tippen. AutoVervollständigen verwendet eine Vorschlagsfunktion (
sg
), um zu bestimmen, welche Felder potenzielle Übereinstimmungen mit Anforderungen der Vorschlagsfunktion enthalten. In diesem Schnellstart sind diese FelderTags
,Address/City
,Address/Country
. Übergeben Sie die Buchstaben sa als Teilzeichenfolge, um AutoVervollständigen zu simulieren. Mit der autocomplete-Methode von SearchClient werden potenzielle Übereinstimmungen mit Begriffen zurückgesendet.
Entfernen des Indexes
Wenn Sie mit diesem Index fertig sind, können Sie ihn löschen, indem Sie die Codezelle Aufräumen ausführen. Durch das Löschen unnötiger Indizes wird Speicherplatz für weitere Schnellstarts und Tutorials freigegeben.
Erfahren Sie, wie Sie die Clientbibliothek Azure.Search.Documents verwenden, um einen Suchindex mithilfe von Beispieldaten für die Volltextsuche zu erstellen, zu laden und abzufragen. Die Volltextsuche verwendet Apache Lucene für die Indizierung und Abfragen sowie einen BM25-Bewertungsalgorithmus für die Bewertung von Ergebnissen.
In diesem Schnellstart wird der kleine Index „hotels-quickstart“, der Daten zu vier Hotels enthält, erstellt und abgefragt.
Tipp
Sie können den Quellcode herunterladen, um mit einem fertigen Projekt zu beginnen, oder diese Schritte ausführen, um ein eigenes zu erstellen.
Voraussetzungen
- Ein aktives Azure-Abonnement. (Kostenloses Abonnement erstellen)
- Ein Azure AI Search-Dienst. Erstellen Sie einen Dienst, sofern nicht bereits geschehen. Sie können einen Free-Tarif für diesen Schnellstart verwenden.
Voraussetzungen für Microsoft Entra ID
Für die empfohlene schlüssellose Authentifizierung mit Microsoft Entra ID müssen Sie:
- Die Azure CLI installieren, die für die schlüssellose Authentifizierung mit Microsoft Entra ID verwendet wird
- Weisen Sie Ihrem Benutzerkonto die beiden Rollen
Search Service Contributor
undSearch Index Data Contributor
zu. Sie können Rollen im Azure-Portal unter Zugriffssteuerung (IAM)>Rollenzuweisung hinzufügen zuweisen. Weitere Informationen finden Sie unter Herstellen einer Verbindung mit Azure KI-Suche mithilfe von Rollen.
Abrufen von Ressourceninformationen
Sie müssen die folgenden Informationen abrufen, um Ihre Anwendung bei Ihrem Azure KI-Suche-Dienst zu authentifizieren:
Variablenname | Wert |
---|---|
SEARCH_API_ENDPOINT |
Diesen Wert finden Sie im Azure-Portal. Wählen Sie Ihren Suchdienst und dann im linken Menü die Option Übersicht aus. Der URL-Wert unter Essentials ist der Endpunkt, den Sie benötigen. Ein Beispiel für einen Endpunkt ist https://mydemo.search.windows.net . |
Erfahren Sie mehr über schlüssellose Authentifizierung und das Festlegen von Umgebungsvariablen.
Einrichten
Erstellen Sie einen neuen Ordner
full-text-quickstart
für die Anwendung, und öffnen Sie Visual Studio Code in diesem Ordner mit dem folgenden Befehl:mkdir full-text-quickstart && cd full-text-quickstart
Erstellen Sie
package.json
mit dem folgenden Befehl:npm init -y
Aktualisieren Sie
package.json
mit dem folgenden Befehl auf ECMAScript:npm pkg set type=module
Installieren Sie die Clientbibliothek von Azure KI-Suche (Azure.Search.Documents) für JavaScript mit:
npm install @azure/search-documents
Installieren Sie für die empfohlene kennwortlose Authentifizierung die Azure Identity-Clientbibliothek mit:
npm install @azure/identity
Erstellen, Laden und Abfragen eines Suchindexes
Im vorherigen Abschnitt Einrichten haben Sie die Clientbibliothek von Azure KI-Suche und andere Abhängigkeiten installiert.
In diesem Abschnitt fügen Sie Code hinzu, um einen Suchindex zu erstellen, ihn mit Dokumenten zu laden und Abfragen auszuführen. Sie führen das Programm aus, um die Ergebnisse in der Konsole anzuzeigen. Eine ausführliche Erläuterung des Codes finden Sie im Abschnitt Erläuterung des Codes.
Der Beispielcode in diesem Schnellstart verwendet Microsoft Entra ID für die empfohlene schlüssellose Authentifizierung. Wenn Sie einen API-Schlüssel verwenden möchten, können Sie das DefaultAzureCredential
-Objekt durch ein AzureKeyCredential
-Objekt ersetzen.
const searchServiceEndpoint = "https://<Put your search service NAME here>.search.windows.net/";
const credential = new DefaultAzureCredential();
Erstellen Sie eine neue Datei mit dem Namen index.ts, und fügen Sie den folgenden Code in index.ts ein:
// Import from the @azure/search-documents library import { SearchIndexClient, SearchClient, SearchFieldDataType, AzureKeyCredential, odata, SearchIndex } from "@azure/search-documents"; // Import from the Azure Identity library import { DefaultAzureCredential } from "@azure/identity"; // Importing the hotels sample data import hotelData from './hotels.json' assert { type: "json" }; // Load the .env file if it exists import * as dotenv from "dotenv"; dotenv.config(); // Defining the index definition const indexDefinition: SearchIndex = { "name": "hotels-quickstart", "fields": [ { "name": "HotelId", "type": "Edm.String" as SearchFieldDataType, "key": true, "filterable": true }, { "name": "HotelName", "type": "Edm.String" as SearchFieldDataType, "searchable": true, "filterable": false, "sortable": true, "facetable": false }, { "name": "Description", "type": "Edm.String" as SearchFieldDataType, "searchable": true, "filterable": false, "sortable": false, "facetable": false, "analyzerName": "en.lucene" }, { "name": "Description_fr", "type": "Edm.String" as SearchFieldDataType, "searchable": true, "filterable": false, "sortable": false, "facetable": false, "analyzerName": "fr.lucene" }, { "name": "Category", "type": "Edm.String" as SearchFieldDataType, "searchable": true, "filterable": true, "sortable": true, "facetable": true }, { "name": "Tags", "type": "Collection(Edm.String)", "searchable": true, "filterable": true, "sortable": false, "facetable": true }, { "name": "ParkingIncluded", "type": "Edm.Boolean", "filterable": true, "sortable": true, "facetable": true }, { "name": "LastRenovationDate", "type": "Edm.DateTimeOffset", "filterable": true, "sortable": true, "facetable": true }, { "name": "Rating", "type": "Edm.Double", "filterable": true, "sortable": true, "facetable": true }, { "name": "Address", "type": "Edm.ComplexType", "fields": [ { "name": "StreetAddress", "type": "Edm.String" as SearchFieldDataType, "filterable": false, "sortable": false, "facetable": false, "searchable": true }, { "name": "City", "type": "Edm.String" as SearchFieldDataType, "searchable": true, "filterable": true, "sortable": true, "facetable": true }, { "name": "StateProvince", "type": "Edm.String" as SearchFieldDataType, "searchable": true, "filterable": true, "sortable": true, "facetable": true }, { "name": "PostalCode", "type": "Edm.String" as SearchFieldDataType, "searchable": true, "filterable": true, "sortable": true, "facetable": true }, { "name": "Country", "type": "Edm.String" as SearchFieldDataType, "searchable": true, "filterable": true, "sortable": true, "facetable": true } ] } ], "suggesters": [ { "name": "sg", "searchMode": "analyzingInfixMatching", "sourceFields": [ "HotelName" ] } ] }; async function main() { // Your search service endpoint const searchServiceEndpoint = "https://<Put your search service NAME here>.search.windows.net/"; // Use the recommended keyless credential instead of the AzureKeyCredential credential. const credential = new DefaultAzureCredential(); //const credential = new AzureKeyCredential(Your search service admin key); // Create a SearchIndexClient to send create/delete index commands const searchIndexClient: SearchIndexClient = new SearchIndexClient( searchServiceEndpoint, credential ); // Creating a search client to upload documents and issue queries const indexName: string = "hotels-quickstart"; const searchClient: SearchClient<any> = searchIndexClient.getSearchClient(indexName); console.log('Checking if index exists...'); await deleteIndexIfExists(searchIndexClient, indexName); console.log('Creating index...'); let index: SearchIndex = await searchIndexClient.createIndex(indexDefinition); console.log(`Index named ${index.name} has been created.`); console.log('Uploading documents...'); let indexDocumentsResult = await searchClient.mergeOrUploadDocuments(hotelData['value']); console.log(`Index operations succeeded: ${JSON.stringify(indexDocumentsResult.results[0].succeeded)} `); // waiting one second for indexing to complete (for demo purposes only) sleep(1000); console.log('Querying the index...'); console.log(); await sendQueries(searchClient); } async function deleteIndexIfExists(searchIndexClient: SearchIndexClient, indexName: string) { try { await searchIndexClient.deleteIndex(indexName); console.log('Deleting index...'); } catch { console.log('Index does not exist yet.'); } } async function sendQueries(searchClient: SearchClient<any>) { // Query 1 console.log('Query #1 - search everything:'); let searchOptions: any = { includeTotalCount: true, select: ["HotelId", "HotelName", "Rating"] }; let searchResults = await searchClient.search("*", searchOptions); for await (const result of searchResults.results) { console.log(`${JSON.stringify(result.document)}`); } console.log(`Result count: ${searchResults.count}`); console.log(); // Query 2 console.log('Query #2 - search with filter, orderBy, and select:'); let state = 'FL'; searchOptions = { filter: odata`Address/StateProvince eq ${state}`, orderBy: ["Rating desc"], select: ["HotelId", "HotelName", "Rating"] }; searchResults = await searchClient.search("wifi", searchOptions); for await (const result of searchResults.results) { console.log(`${JSON.stringify(result.document)}`); } console.log(); // Query 3 console.log('Query #3 - limit searchFields:'); searchOptions = { select: ["HotelId", "HotelName", "Rating"], searchFields: ["HotelName"] }; searchResults = await searchClient.search("sublime cliff", searchOptions); for await (const result of searchResults.results) { console.log(`${JSON.stringify(result.document)}`); } console.log(); // Query 4 console.log('Query #4 - limit searchFields and use facets:'); searchOptions = { facets: ["Category"], select: ["HotelId", "HotelName", "Rating"], searchFields: ["HotelName"] }; searchResults = await searchClient.search("*", searchOptions); for await (const result of searchResults.results) { console.log(`${JSON.stringify(result.document)}`); } console.log(); // Query 5 console.log('Query #5 - Lookup document:'); let documentResult = await searchClient.getDocument('3'); console.log(`HotelId: ${documentResult.HotelId}; HotelName: ${documentResult.HotelName}`); console.log(); } function sleep(ms: number) { return new Promise(resolve => setTimeout(resolve, ms)); } main().catch((err) => { console.error("The sample encountered an error:", err); });
Erstellen Sie eine Datei mit dem Namen hotels.json, und fügen Sie den folgenden Code in hotels.json ein:
{ "value": [ { "HotelId": "1", "HotelName": "Secret Point Motel", "Description": "The hotel is ideally located on the main commercial artery of the city in the heart of New York. A few minutes away is Time's Square and the historic centre of the city, as well as other places of interest that make New York one of America's most attractive and cosmopolitan cities.", "Description_fr": "L'hôtel est idéalement situé sur la principale artère commerciale de la ville en plein cœur de New York. A quelques minutes se trouve la place du temps et le centre historique de la ville, ainsi que d'autres lieux d'intérêt qui font de New York l'une des villes les plus attractives et cosmopolites de l'Amérique.", "Category": "Boutique", "Tags": ["pool", "air conditioning", "concierge"], "ParkingIncluded": false, "LastRenovationDate": "1970-01-18T00:00:00Z", "Rating": 3.6, "Address": { "StreetAddress": "677 5th Ave", "City": "New York", "StateProvince": "NY", "PostalCode": "10022" } }, { "HotelId": "2", "HotelName": "Twin Dome Motel", "Description": "The hotel is situated in a nineteenth century plaza, which has been expanded and renovated to the highest architectural standards to create a modern, functional and first-class hotel in which art and unique historical elements coexist with the most modern comforts.", "Description_fr": "L'hôtel est situé dans une place du XIXe siècle, qui a été agrandie et rénovée aux plus hautes normes architecturales pour créer un hôtel moderne, fonctionnel et de première classe dans lequel l'art et les éléments historiques uniques coexistent avec le confort le plus moderne.", "Category": "Boutique", "Tags": ["pool", "free wifi", "concierge"], "ParkingIncluded": "false", "LastRenovationDate": "1979-02-18T00:00:00Z", "Rating": 3.6, "Address": { "StreetAddress": "140 University Town Center Dr", "City": "Sarasota", "StateProvince": "FL", "PostalCode": "34243" } }, { "HotelId": "3", "HotelName": "Triple Landscape Hotel", "Description": "The Hotel stands out for its gastronomic excellence under the management of William Dough, who advises on and oversees all of the Hotel’s restaurant services.", "Description_fr": "L'hôtel est situé dans une place du XIXe siècle, qui a été agrandie et rénovée aux plus hautes normes architecturales pour créer un hôtel moderne, fonctionnel et de première classe dans lequel l'art et les éléments historiques uniques coexistent avec le confort le plus moderne.", "Category": "Resort and Spa", "Tags": ["air conditioning", "bar", "continental breakfast"], "ParkingIncluded": "true", "LastRenovationDate": "2015-09-20T00:00:00Z", "Rating": 4.8, "Address": { "StreetAddress": "3393 Peachtree Rd", "City": "Atlanta", "StateProvince": "GA", "PostalCode": "30326" } }, { "HotelId": "4", "HotelName": "Sublime Cliff Hotel", "Description": "Sublime Cliff Hotel is located in the heart of the historic center of Sublime in an extremely vibrant and lively area within short walking distance to the sites and landmarks of the city and is surrounded by the extraordinary beauty of churches, buildings, shops and monuments. Sublime Cliff is part of a lovingly restored 1800 palace.", "Description_fr": "Le sublime Cliff Hotel est situé au coeur du centre historique de sublime dans un quartier extrêmement animé et vivant, à courte distance de marche des sites et monuments de la ville et est entouré par l'extraordinaire beauté des églises, des bâtiments, des commerces et Monuments. Sublime Cliff fait partie d'un Palace 1800 restauré avec amour.", "Category": "Boutique", "Tags": ["concierge", "view", "24-hour front desk service"], "ParkingIncluded": true, "LastRenovationDate": "1960-02-06T00:00:00Z", "Rating": 4.6, "Address": { "StreetAddress": "7400 San Pedro Ave", "City": "San Antonio", "StateProvince": "TX", "PostalCode": "78216" } } ] }
Erstellen Sie die Datei
tsconfig.json
, um den TypeScript-Code zu transpilieren, und kopieren Sie den folgenden Code für 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"] }
Transpilieren Sie von TypeScript in JavaScript:
tsc
Melden Sie sich mithilfe des folgenden Befehls bei Azure an:
az login
Führen Sie den JavaScript-Code mit dem folgenden Befehl aus:
node index.js
Erläutern des Codes
Erstellen eines Index
Erstellen Sie die Datei hotels_quickstart_index.json. Diese Datei definiert, wie Azure KI-Suche mit den Dokumenten verfährt, die Sie im nächsten Schritt laden. Jedes Feld wird durch einen name
identifiziert und hat einen bestimmten type
. Jedes Feld verfügt zudem über eine Reihe von Indexattributen, die angeben, ob Azure AI Search das Feld durchsuchen, filtern, sortieren und facettieren kann. Bei den meisten Feldern handelt es sich um einfache Datentypen, einige wie z.B. AddressType
sind aber komplexe Typen, die es Ihnen ermöglichen, umfangreiche Datenstrukturen in Ihrem Index zu erstellen. Informieren Sie sich weiter über die unterstützten Datentypen und die Indexattribute, die unter Erstellen eines Index (REST) beschrieben sind.
Wir möchten hotels_quickstart_index.json importieren, damit die Hauptfunktion auf die Indexdefinition zugreifen kann.
import indexDefinition from './hotels_quickstart_index.json';
interface HotelIndexDefinition {
name: string;
fields: SimpleField[] | ComplexField[];
suggesters: SearchSuggester[];
};
const hotelIndexDefinition: HotelIndexDefinition = indexDefinition as HotelIndexDefinition;
In der main-Funktion erstellen Sie ein SearchIndexClient
-Objekt, das zum Erstellen und Verwalten von Indizes für Azure AI Search verwendet wird.
const indexClient = new SearchIndexClient(endpoint, new AzureKeyCredential(apiKey));
Als nächstes löschen Sie den Index, falls er bereits existiert. Dies ist eine gängige Vorgehensweise für Test-/Democode.
Dazu wird eine einfache Funktion definiert, die versucht, den Index zu löschen.
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.');
}
}
Um die Funktion auszuführen, wird der Indexname aus der Indexdefinition extrahiert und das indexName
-Objekt zusammen mit dem indexClient
-Objekt an die deleteIndexIfExists()
-Funktion übergeben.
// 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);
Danach sind Sie bereit, den Index mit der createIndex()
-Methode zu erstellen.
console.log('Creating index...');
let index = await indexClient.createIndex(hotelIndexDefinition);
console.log(`Index named ${index.name} has been created.`);
Laden von Dokumenten
In Azure AI Search sind die Dokumente Datenstrukturen, bei denen es sich sowohl um Eingaben für die Indizierung als auch um Ausgaben von Abfragen handeln kann. Sie können diese Daten per Push an den Index senden oder einen Indexer verwenden. In diesem Fall werden die Dokumente programmseitig per Push an den Index gesendet.
Dokumenteingaben können Zeilen in einer Datenbank, Blobs in einem Blobspeicher oder JSON-Dokumente auf einem Datenträger sein. Sie können entweder hotels.json herunterladen oder selbst eine hotels.json-Datei mit folgendem Inhalt erstellen:
Ähnlich wie bei der Indexdefinition müssen Sie auch hierbei hotels.json
am Anfang von index.ts importieren, damit in der main-Funktion auf die Daten zugegriffen werden kann.
import hotelData from './hotels.json';
interface Hotel {
HotelId: string;
HotelName: string;
Description: string;
Description_fr: string;
Category: string;
Tags: string[];
ParkingIncluded: string | boolean;
LastRenovationDate: string;
Rating: number;
Address: {
StreetAddress: string;
City: string;
StateProvince: string;
PostalCode: string;
};
};
const hotels: Hotel[] = hotelData["value"];
Um Daten in den Suchindex zu indizieren, müssen Sie nun ein SearchClient
-Objekt erstellen. Während das SearchIndexClient
-Objekt zum Erstellen und Verwalten eines Index verwendet wird, dient das SearchClient
-Objekt zum Hochladen von Dokumenten und Abfragen des Index.
Es gibt zwei Möglichkeiten zum Erstellen einer SearchClient
: Die erste Option besteht darin, ein SearchClient
-Objekt von Grund auf neu zu erstellen:
const searchClient = new SearchClient<Hotel>(endpoint, indexName, new AzureKeyCredential(apiKey));
Alternativ können Sie die getSearchClient()
-Methode des SearchIndexClient
-Objekts verwenden, um das SearchClient
-Objekt zu erstellen:
const searchClient = indexClient.getSearchClient<Hotel>(indexName);
Nachdem der Client definiert wurde, laden Sie die Dokumente in den Suchindex hoch. In diesem Fall verwenden Sie die mergeOrUploadDocuments()
-Methode zum Hochladen der Dokumente, oder Sie führen sie mit einem bestehenden Dokument zusammen, wenn bereits ein Dokument mit demselben Schlüssel existiert. Überprüfen Sie dann, ob der Vorgang erfolgreich war, da zumindest das erste Dokument vorhanden ist.
console.log("Uploading documents...");
const indexDocumentsResult = await searchClient.mergeOrUploadDocuments(hotels);
console.log(`Index operations succeeded: ${JSON.stringify(indexDocumentsResult.results[0].succeeded)}`);
Führen Sie das Programm erneut mit tsc && node index.ts
aus. Jetzt werden etwas andere Meldungen angezeigt als in Schritt 1. Dieses Mal ist der Index vorhanden, und es sollte eine Meldung angezeigt werden, die besagt, dass dieser gelöscht wird, bevor die App den neuen Index erstellt und dort Daten einfügt.
Bevor Sie die Abfragen im nächsten Schritt ausführen, definieren Sie eine Funktion, die das Programm eine Sekunde lang warten lässt. Dies geschieht nur zu Test-/Demozwecken, um sicherzustellen, dass die Indizierung abgeschlossen ist und die Dokumente im Index für Abfragen zur Verfügung stehen.
function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
Um das Programm eine Sekunde lang warten zu lassen, rufen Sie die Funktion sleep
auf:
sleep(1000);
Durchsuchen eines Index
Nachdem Sie einen Index erstellt und Dokumente hochgeladen haben, können Sie nun Abfragen an den Index senden. In diesem Abschnitt werden fünf verschiedene Abfragen an den Suchindex gesendet, um verschiedene verfügbare Abfragefunktionen zu veranschaulichen.
Die Abfragen werden in einer sendQueries()
-Funktion geschrieben, die in der main-Funktion wie folgt aufgerufen wird:
await sendQueries(searchClient);
Abfragen werden mithilfe der search()
-Methode von searchClient
gesendet. Der erste Parameter ist der Suchtext, und der zweite Parameter gibt die Suchoptionen an.
Abfragebeispiel 1
Die erste Abfrage durchsucht *
, was dem Durchsuchen aller Elemente entspricht, und wählt drei der Felder im Index aus. Es ist ein bewährtes Verfahren, nur die Felder per select
auszuwählen, die Sie benötigen, da das Pullen unnötiger Daten die Latenz Ihrer Abfragen erhöhen kann.
Beim searchOptions
-Objekt für diese Abfrage ist zudem includeTotalCount
auf true
festgelegt, wodurch die Anzahl der gefundenen Treffer zurückgegeben wird.
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
}
Die übrigen unten beschriebenen Abfragen sollten auch der sendQueries()
-Funktion hinzugefügt werden. Sie sind hier aus Gründen der Lesbarkeit getrennt.
Abfragebeispiel 2
In der nächsten Abfrage geben Sie den Suchbegriff "wifi"
an und fügen zudem einen Filter hinzu, um nur Ergebnisse zurückzugeben, deren Zustand gleich 'FL'
ist. Die Ergebnisse werden außerdem nach dem Rating
-Objekt des Hotels sortiert.
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)}`);
}
Abfragebeispiel 3
Anschließend wird die Suche mit dem Parameter searchFields
auf ein einzelnes durchsuchbares Feld beschränkt. Dieser Ansatz ist eine großartige Möglichkeit, Ihre Abfrage effizienter zu gestalten, wenn Sie wissen, dass Sie nur an Übereinstimmungen in bestimmten Feldern interessiert sind.
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)}`);
}
Abfragebeispiel 4
Eine weitere gängige Option, die in eine Abfrage einbezogen werden kann, ist facets
. Mithilfe von Facets können Sie einen selbstgesteuerten Drilldown für die Ergebnisse auf der Benutzeroberfläche bereitstellen. Die Facets-Ergebnisse können im Ergebnisbereich in Kontrollkästchen umgewandelt werden.
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)}`);
}
Abfragebeispiel 5
Die abschließende Abfrage verwendet die getDocument()
-Methode des searchClient
-Objekts. Auf diese Weise können Sie ein Dokument effizient anhand seines Schlüssels abrufen.
console.log('Query #5 - Lookup document:');
let documentResult = await searchClient.getDocument('3')
console.log(`HotelId: ${documentResult.HotelId}; HotelName: ${documentResult.HotelName}`)
Zusammenfassung der Abfragen
Die obigen Abfragen verdeutlichen mehrere Möglichkeiten zum Abgleichen von Begriffen in einer Abfrage: Volltextsuche, Filter und AutoVervollständigen.
Volltextsuche und Filtervorgänge werden mit der searchClient.search
-Methode durchgeführt. Eine Suchanfrage kann in der searchText
-Zeichenfolge übergeben werden, während ein Filterausdruck in der filter
-Eigenschaft der SearchOptions
-Klasse übergeben werden kann. Um ohne Suche zu filtern, übergeben Sie einfach „*“ für den Parameter searchText
der search
-Methode. Wenn Sie ohne Filter suchen möchten, legen Sie die Eigenschaft filter
nicht fest, oder übergeben Sie einfach keine SearchOptions
-Instanz.
Bereinigen von Ressourcen
Wenn Sie in Ihrem eigenen Abonnement arbeiten, sollten Sie sich am Ende eines Projekts überlegen, ob Sie die erstellten Ressourcen noch benötigen. Ressourcen, die weiterhin ausgeführt werden, können Sie Geld kosten. Sie können einzelne Ressourcen oder die gesamte Ressourcengruppe mit allen darin enthaltenen Ressourcen löschen.
Sie können Ressourcen im Azure-Portal über den Link Alle Ressourcen oder Ressourcengruppen im linken Navigationsbereich suchen und verwalten.
Denken Sie bei Verwendung eines kostenlosen Diensts an die Beschränkung auf maximal drei Indizes, Indexer und Datenquellen. Sie können einzelne Elemente über das Azure-Portal löschen, um unter dem Grenzwert zu bleiben.
Nächster Schritt
In dieser Schnellstartanleitung haben Sie eine Reihe von Aufgaben ausgeführt, um einen Index zu erstellen, Dokumente in den Index zu laden und Abfragen auszuführen. In einzelnen Phasen haben wir den Code zur besseren Lesbarkeit und zum besseren Verständnis ein wenig vereinfacht. Nachdem Sie nun mit den grundlegenden Konzepten vertraut sind, probieren Sie das Tutorial aus, das die AI Search-APIs in einer Web-App aufruft.