Verwenden von Azure.Search.Documents in einer .NET-Anwendung
In diesem Artikel wird erläutert, wie Sie Suchobjekte mit C# und der Azure.Search.Documents (Version 11)-Clientbibliothek im Azure SDK für .NET erstellen und verwalten.
Informationen zu Version 11
Azure SDK für .NET enthält eine Azure.Search.Documents-Clientbibliothek des Azure SDK-Teams, die funktional der vorherigen Clientbibliothek Microsoft.Azure.Search entspricht. Version 11 ist in Bezug auf die Programmierbarkeit von Azure konsistenter. Beispiele sind die AzureKeyCredential
-Schlüsselauthentifizierung und System.Text.Json.Serialization für die JSON-Serialisierung.
Wie die Vorgängerversionen können Sie diese Bibliothek zu Folgendem verwenden:
- Erstellen und Verwalten von Suchindizes, Datenquellen, Indexern, Skillsets und Synonymzuordnungen
- Laden und Verwalten von Suchdokumenten in einem Index
- Ausführen von Abfragen, ohne sich um die Details von HTTP und JSON kümmern zu müssen
- Aufrufen und Verwalten von KI-Anreicherung (Skillsets) und Ausgaben
Die Bibliothek wird als einzelnes NuGet-Paket verteilt, das alle APIs umfasst, die für den programmgesteuerten Zugriff auf einen Suchdienst erforderlich sind.
Die Clientbibliothek definiert Klassen wie SearchIndex
, SearchField
und SearchDocument
sowie Operationen wie SearchIndexClient.CreateIndex
und SearchClient.Search
für die Klassen SearchIndexClient
und SearchClient
. Diese Klassen sind in die folgenden Namespaces aufgeteilt:
Azure.Search.Documents
Azure.Search.Documents.Indexes
Azure.Search.Documents.Indexes.Models
Azure.Search.Documents.Models
Version 11 zielt auf die Suchdienstspezifikation 2020-06-30 ab.
Die Clientbibliothek bietet keine Dienstverwaltungsvorgänge wie das Erstellen und Skalieren von Suchdiensten und das Verwalten von API-Schlüsseln. Wenn Sie Ihre Ressourcen für die Suche in einer .NET-Anwendung verwalten müssen, können Sie die Microsoft.Azure.Management.Search-Bibliothek im Azure SDK für .NET verwenden.
Upgrade auf Version 11
Wenn Sie die vorherige Version des .NET SDK verwendet haben und auf die aktuelle, allgemein verfügbare Version aktualisieren möchten, lesen Sie Upgrade auf Version 11 des Azure AI Search .NET SDK.
SDK-Anforderungen
Visual Studio 2019 oder höher
Ihr eigener Azure AI Search Service. Um das SDK verwenden zu können, benötigen Sie den Namen Ihres Diensts und einen oder mehrere API-Schlüssel. Erstellen Sie einen Dienst im Portal, wenn Sie über keinen verfügen.
Laden Sie das NuGet-Paket über Extras>NuGet-Paket-Manager>NuGet-Pakete für Projektmappe verwalten in Visual Studio herunter. Suchen Sie nach dem Paketname
Azure.Search.Documents
.
Das Azure SDK für .NET entspricht .NET Standard 2.0.
Beispielanwendung
Dieser Artikel lehrt durch Beispiele und stützt sich auf das Codebeispiel DotNetHowTo auf GitHub, um grundlegende Konzepte in Azure KI-Suche sowie das Erstellen, Laden und Abfragen eines Suchindex zu veranschaulichen.
Nehmen Sie für den restlichen Artikel einen neuen Index namens hotels an, der mit einigen Dokumenten aufgefüllt ist, sowie mehrere Abfragen, die mit den Ergebnissen übereinstimmen.
Das folgende Beispiel zeigt das Hauptprogramm mit dem Gesamtflow:
// This sample shows how to delete, create, upload documents and query an index
static void Main(string[] args)
{
IConfigurationBuilder builder = new ConfigurationBuilder().AddJsonFile("appsettings.json");
IConfigurationRoot configuration = builder.Build();
SearchIndexClient indexClient = CreateSearchIndexClient(configuration);
string indexName = configuration["SearchIndexName"];
Console.WriteLine("{0}", "Deleting index...\n");
DeleteIndexIfExists(indexName, indexClient);
Console.WriteLine("{0}", "Creating index...\n");
CreateIndex(indexName, indexClient);
SearchClient searchClient = indexClient.GetSearchClient(indexName);
Console.WriteLine("{0}", "Uploading documents...\n");
UploadDocuments(searchClient);
SearchClient indexClientForQueries = CreateSearchClientForQueries(indexName, configuration);
Console.WriteLine("{0}", "Run queries...\n");
RunQueries(indexClientForQueries);
Console.WriteLine("{0}", "Complete. Press any key to end application...\n");
Console.ReadKey();
}
Als Nächstes sehen Sie einen Screenshotausschnitt der Ausgabe unter der Annahme, dass Sie diese Anwendung mit einem gültigen Dienstnamen und API-Schlüsseln ausführen:
Clienttypen
Die Clientbibliothek verwendet drei Clienttypen für verschiedene Vorgänge: SearchIndexClient
zum Erstellen, Aktualisieren oder Löschen von Indizes, SearchClient
zum Laden oder Abfragen eines Index und SearchIndexerClient
zum Arbeiten mit Indexern und Skillsets. In diesem Artikel werden hauptsächlich die ersten beiden behandelt.
Für alle Clients ist mindestens der Dienstname oder der Endpunkt und ein API-Schlüssel erforderlich. In der Regel werden diese Informationen in einer Konfigurationsdatei angegeben, ähnlich zu den Angaben in der Datei appsettings.json der DotNetHowTo-Beispielanwendung. Fügen Sie für Lesevorgänge in der Konfigurationsdatei Ihrem Programm using Microsoft.Extensions.Configuration;
hinzu.
Die folgende Anweisung erstellt den Indexclient, der verwendet wird, um Indizes zu erstellen, zu aktualisieren oder zu löschen. Er benötigt einen Dienst-Endpunkt und einen API-Schlüssel für den Administrator.
private static SearchIndexClient CreateSearchIndexClient(IConfigurationRoot configuration)
{
string searchServiceEndPoint = configuration["YourSearchServiceEndPoint"];
string adminApiKey = configuration["YourSearchServiceAdminApiKey"];
SearchIndexClient indexClient = new SearchIndexClient(new Uri(searchServiceEndPoint), new AzureKeyCredential(adminApiKey));
return indexClient;
}
Die nächste Anweisung erstellt den Suchclient, der verwendet wird, um Dokumente zu laden oder Abfragen auszuführen. Für SearchClient
ist ein Index erforderlich. Sie benötigen einen Admin-API-Schlüssel, um Dokumente zu laden, aber Sie können einen Abfrage-API-Schlüssel verwenden, um Abfragen auszuführen.
string indexName = configuration["SearchIndexName"];
private static SearchClient CreateSearchClientForQueries(string indexName, IConfigurationRoot configuration)
{
string searchServiceEndPoint = configuration["YourSearchServiceEndPoint"];
string queryApiKey = configuration["YourSearchServiceQueryApiKey"];
SearchClient searchClient = new SearchClient(new Uri(searchServiceEndPoint), indexName, new AzureKeyCredential(queryApiKey));
return searchClient;
}
Hinweis
Wenn Sie einen ungültigen Schlüssel für den Importvorgang angeben (z. B. einen Abfrageschlüssel statt eines Administratorschlüssels), gibt SearchClient
beim ersten Aufruf einer Vorgangsmethode eine CloudException
-Ausnahme mit der Fehlermeldung Unzulässig zurück. Überprüfen Sie in diesem Fall den API-Schlüssel.
Löschen des Indexes
In den frühen Entwicklungsphasen sollten Sie eine DeleteIndex
-Anweisung einschließen, um einen laufenden Index zu löschen, damit Sie ihn mit aktualisierter Definition neu erstellen können. Der Beispielcode für Azure AI Search enthält oft einen Löschschritt, damit Sie das Beispiel erneut ausführen können.
Die folgende Zeile ruft DeleteIndexIfExists
auf:
Console.WriteLine("{0}", "Deleting index...\n");
DeleteIndexIfExists(indexName, indexClient);
Diese Methode verwendet die bereitgestellte Klasse SearchIndexClient
, um zu überprüfen, ob der Index vorhanden ist, und löscht ihn gegebenenfalls:
private static void DeleteIndexIfExists(string indexName, SearchIndexClient indexClient)
{
try
{
if (indexClient.GetIndex(indexName) != null)
{
indexClient.DeleteIndex(indexName);
}
}
catch (RequestFailedException e) when (e.Status == 404)
{
// Throw an exception if the index name isn't found
Console.WriteLine("The index doesn't exist. No deletion occurred.");
Hinweis
Im Beispielcode dieses Artikels werden der Einfachheit halber die synchronen Methoden verwenden. In Ihren Anwendungen sollten Sie jedoch die asynchronen Methoden verwenden, damit sie skaliert werden können und reaktionsfähig bleiben. In der vorherigen Methode können Sie beispielsweise DeleteIndexAsync
anstelle von DeleteIndex
verwenden.
Erstellen eines Index
Sie können SearchIndexClient
verwenden, um einen Index zu erstellen.
Die Methode unten erstellt ein neues SearchIndex
-Objekt mit einer Liste von SearchField
-Objekten, die das Schema des neuen Index definieren. Jedes Feld weist einen Namen, einen Datentyp und mehrere Attribute auf, die das Suchverhalten des Felds definieren.
Felder können in einer Modellklasse mithilfe von FieldBuilder
definiert werden. Die Klasse FieldBuilder
verwendet Reflexion, um durch Untersuchen der öffentlichen Eigenschaften und Attribute der entsprechenden Hotel
-Modellklasse eine Liste von SearchField
-Objekten für den Index zu erstellen. Wir werden uns die Klasse Hotel
später genauer ansehen.
private static void CreateIndex(string indexName, SearchIndexClient indexClient)
{
FieldBuilder fieldBuilder = new FieldBuilder();
var searchFields = fieldBuilder.Build(typeof(Hotel));
var definition = new SearchIndex(indexName, searchFields);
indexClient.CreateOrUpdateIndex(definition);
}
Neben Feldern können Sie dem Index auch Bewertungsprofile, Vorschlagsfunktionen oder CORS-Optionen hinzufügen (diese Parameter fehlen im Beispiel, um es einfach zu halten). Weitere Informationen zum SearchIndex
-Objekt und seinen Bestandteilen finden Sie in der SearchIndex-Eigenschaftenliste sowie im Referenzartikel zur REST-API.
Hinweis
Sie können die Liste der Field
-Objekte immer direkt erstellen, anstatt FieldBuilder
bei Bedarf zu verwenden. Sie möchten z. B. vielleicht keine Modellklasse verwenden oder müssen möglicherweise eine vorhandene Modellklasse verwenden, die Sie nicht durch Hinzufügen von Attributen ändern möchten.
Aufrufen von CreateIndex in Main()
Main
ruft die vorherige Methode auf, um einen neuen Index mit dem Namen hotels zu erstellen:
Console.WriteLine("{0}", "Creating index...\n");
CreateIndex(indexName, indexClient);
Verwenden einer Modellklasse für die Datendarstellung
Im DotNetHowTo-Beispiel werden Modellklassen für die Datenstrukturen Hotel, Address und Room verwendet. Hotel
verweist auf Address
, ein komplexer Typ mit einzelner Ebene (ein mehrteiliges Feld) und Room
(eine Sammlung mit mehrteiligen Feldern).
Sie können diese Typen verwenden, um den Index zu erstellen und zu laden und um die Antwort einer Abfrage zu strukturieren:
// Use-case: <Hotel> in a field definition
FieldBuilder fieldBuilder = new FieldBuilder();
var searchFields = fieldBuilder.Build(typeof(Hotel));
// Use-case: <Hotel> in a response
private static void WriteDocuments(SearchResults<Hotel> searchResults)
{
foreach (SearchResult<Hotel> result in searchResults.GetResults())
{
Console.WriteLine(result.Document);
}
Console.WriteLine();
}
Eine alternative Methode besteht darin, einem Index die Felder direkt hinzuzufügen. Im folgenden Beispiel werden nur einige Felder gezeigt.
SearchIndex index = new SearchIndex(indexName)
{
Fields =
{
new SimpleField("hotelId", SearchFieldDataType.String) { IsKey = true, IsFilterable = true, IsSortable = true },
new SearchableField("hotelName") { IsFilterable = true, IsSortable = true },
new SearchableField("hotelCategory") { IsFilterable = true, IsSortable = true },
new SimpleField("baseRate", SearchFieldDataType.Int32) { IsFilterable = true, IsSortable = true },
new SimpleField("lastRenovationDate", SearchFieldDataType.DateTimeOffset) { IsFilterable = true, IsSortable = true }
}
};
Felddefinitionen
Ihr Datenmodell in .NET und das zugehörige Indexschema sollten so konzipiert sein, dass sie die Suchfunktion unterstützen, die Sie Ihrem Endbenutzer bieten möchten. Jedes Objekt der obersten Ebene in .NET, z. B. ein Suchdokument in einem Suchindex, entspricht einem Suchergebnis, das Sie auf Ihrer Benutzeroberfläche präsentieren würden. In einer Hotelsuchanwendung können Ihre Endbenutzer beispielsweise nach Hotelnamen, der Ausstattung des Hotels oder den Merkmalen eines bestimmten Zimmers suchen.
In jeder Klasse wird ein Feld mit einem Datentyp und Attributen definiert, die bestimmen, wie es verwendet wird. Der Name jeder öffentlichen Eigenschaft in jeder Klasse wird einem Feld mit dem gleichen Namen in der Indexdefinition zugeordnet.
Sehen Sie sich den folgenden Codeausschnitt an, der mehrere Felddefinitionen von der „Hotel“-Klasse pullt. Beachten Sie, dass es sich bei Address
und Rooms
um C#-Typen mit eigenen Klassendefinitionen handelt. Sehen Sie sich dazu den Beispielcode an, wenn Sie sie anzeigen möchten. Bei beiden handelt es sich um komplexe Typen. Weitere Informationen finden Sie unter Modellieren komplexer Datentypen in Azure Search.
public partial class Hotel
{
[SimpleField(IsKey = true, IsFilterable = true)]
public string HotelId { get; set; }
[SearchableField(IsSortable = true)]
public string HotelName { get; set; }
[SearchableField(AnalyzerName = LexicalAnalyzerName.Values.EnLucene)]
public string Description { get; set; }
[SearchableField(IsFilterable = true, IsSortable = true, IsFacetable = true)]
public string Category { get; set; }
[JsonIgnore]
public bool? SmokingAllowed => (Rooms != null) ? Array.Exists(Rooms, element => element.SmokingAllowed == true) : (bool?)null;
[SearchableField]
public Address Address { get; set; }
public Room[] Rooms { get; set; }
Auswählen einer Feldklasse
Beim Definieren von Feldern können Sie die SearchField
-Basisklasse verwenden, oder Sie nutzen abgeleitete Hilfsprogrammmodelle, die als Vorlagen fungieren, mit vorab konfigurierten Eigenschaften.
Genau ein Feld in Ihrem Index muss als Dokumentschlüssel dienen (IsKey = true
). Dabei muss es sich um eine Zeichenfolge handeln, und diese muss jedes Dokument eindeutig identifizieren können. Außerdem ist IsHidden = true
erforderlich, das heißt, die Sichtbarkeit in den Suchergebnissen darf hier nicht gegeben sein.
Feldtyp | Beschreibung und Verwendung |
---|---|
SearchField |
Hierbei handelt es sich um eine Basisklasse, für die die meisten Eigenschaften auf NULL festgelegt sind, mit Ausnahme von einem erforderlichen Wert für Name und von AnalyzerName , wofür der Standardwert „Lucene“ gilt. |
SimpleField |
Hierbei handelt es sich um ein Hilfsprogrammmodell. Hierbei kann es sich um einen beliebigen Datentyp handeln, der immer nicht durchsuchbar (wird bei Volltextsuchabfragen ignoriert) und immer abrufbar (nicht ausgeblendet) ist. Andere Attribute sind standardmäßig deaktiviert, können jedoch aktiviert werden. Sie können ein SimpleField 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 |
Hierbei handelt es sich um ein Hilfsprogrammmodell. Hierbei muss es sich um eine Zeichenfolge handeln, die immer durchsuchbar und abrufbar ist. 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.
Hinzufügen von Feldattributen
Beachten Sie, wie jedes Feld mit Attributen wie IsFilterable
, IsSortable
, IsKey
und AnalyzerName
ergänzt wird. Diese Attribute werden direkt den entsprechenden Feldattributen in einem Azure AI Search Index zugeordnet. Die FieldBuilder
-Klasse verwendet diese Eigenschaften, um Felddefinitionen für den Index zu erstellen.
Feldtypzuordnung
Die .NET-Typen dieser Eigenschaften stimmen mit den entsprechenden Feldtypen in der Indexdefinition überein. Die Zeichenfolgeeigenschaft Category
passt zum Beispiel zum Feld category
, das den Typ Edm.String
hat. Ähnliche Zuordnungen bestehen auch zwischen bool?
, Edm.Boolean
, DateTimeOffset?
und Edm.DateTimeOffset
usw.
Haben Sie die SmokingAllowed
-Eigenschaft bemerkt?
[JsonIgnore]
public bool? SmokingAllowed => (Rooms != null) ? Array.Exists(Rooms, element => element.SmokingAllowed == true) : (bool?)null;
Das JsonIgnore
-Attribut in dieser Eigenschaft weist FieldBuilder
an, sie nicht als Feld an den Index zu serialisieren. Dies ist eine gute Möglichkeit, clientseitig berechnete Eigenschaften zu erstellen, die Sie als Hilfsprogramme in Ihrer Anwendung nutzen können. In diesem Fall spiegelt die SmokingAllowed
-Eigenschaft wider, ob in einem Room
in der Rooms
-Sammlung Rauchen erlaubt. Wenn alle „false“ sind, bedeutet dies, dass im gesamten Hotel Rauchverbot gilt.
Laden eines Index
Im nächsten Schritt in Main
wird der neu erstellte Index hotels gefüllt. Zum Auffüllen des Index wird die folgende Methode verwendet. (Ein Teil des Codes wurde zur Veranschaulichung durch ...
ersetzt. Beachten Sie die vollständige Beispiellösung für den vollständigen Datenauffüllungscode.)
private static void UploadDocuments(SearchClient searchClient)
{
IndexDocumentsBatch<Hotel> batch = IndexDocumentsBatch.Create(
IndexDocumentsAction.Upload(
new Hotel()
{
HotelId = "1",
HotelName = "Stay-Kay City Hotel",
...
Address = new Address()
{
StreetAddress = "677 5th Ave",
...
},
Rooms = new Room[]
{
new Room()
{
Description = "Budget Room, 1 Queen Bed (Cityside)",
...
},
new Room()
{
Description = "Budget Room, 1 King Bed (Mountain View)",
...
},
new Room()
{
Description = "Deluxe Room, 2 Double Beds (City View)",
...
}
}
}),
IndexDocumentsAction.Upload(
new Hotel()
{
HotelId = "2",
HotelName = "Old Century Hotel",
...
{
StreetAddress = "140 University Town Center Dr",
...
},
Rooms = new Room[]
{
new Room()
{
Description = "Suite, 2 Double Beds (Mountain View)",
...
},
new Room()
{
Description = "Standard Room, 1 Queen Bed (City View)",
...
},
new Room()
{
Description = "Budget Room, 1 King Bed (Waterfront View)",
...
}
}
}),
IndexDocumentsAction.Upload(
new Hotel()
{
HotelId = "3",
HotelName = "Gastronomic Landscape Hotel",
...
Address = new Address()
{
StreetAddress = "3393 Peachtree Rd",
...
},
Rooms = new Room[]
{
new Room()
{
Description = "Standard Room, 2 Queen Beds (Amenities)",
...
},
new Room ()
{
Description = "Standard Room, 2 Double Beds (Waterfront View)",
...
},
new Room()
{
Description = "Deluxe Room, 2 Double Beds (Cityside)",
...
}
}
}
};
try
{
IndexDocumentsResult result = searchClient.IndexDocuments(batch);
}
catch (Exception)
{
// Sometimes when your Search service is under load, indexing will fail for some of the documents in
// the batch. Depending on your application, you can take compensating actions like delaying and
// retrying. For this simple demo, we just log the failed document keys and continue.
Console.WriteLine("Failed to index some of the documents: {0}");
}
Console.WriteLine("Waiting for documents to be indexed...\n");
Thread.Sleep(2000);
Diese Methode besteht aus vier Teilen. Die erste erstellt ein Array aus drei Hotel
-Objekten mit jeweils drei Room
-Objekten, die als unsere Eingabedaten zum Hochladen in den Index dienen. Diese Daten sind der Einfachheit halber fest codiert. In einer tatsächlichen Anwendung stammen Daten wahrscheinlich aus einer externen Datenquelle, z. B. einer SQL-Datenbank.
Im zweiten Teil wird IndexDocumentsBatch
mit den Dokumenten erstellt. Sie geben den Vorgang an, den Sie auf den Batch zum Zeitpunkt seiner Erstellung anwenden möchten, in diesem Fall durch Aufruf von IndexDocumentsAction.Upload
. Der Stapel wird dann mit der Methode IndexDocuments
in den Azure AI Search-Index hochgeladen.
Hinweis
In diesem Beispiel werden nur Dokumente hochgeladen. Wenn Sie z.B. Änderungen in vorhandenen Dokumenten zusammenführen oder Dokumente löschen möchten, können Sie zum Erstellen von Batches IndexDocumentsAction.Merge
, IndexDocumentsAction.MergeOrUpload
oder IndexDocumentsAction.Delete
aufrufen. Sie können auch verschiedene Operationen in einem einzigen Stapel mischen, indem Sie IndexBatch.New
aufrufen, der eine Sammlung von IndexDocumentsAction
Objekten enthält, von denen jedes Azure AI Search anweist, eine bestimmte Operation an einem Dokument durchzuführen. Sie können jede IndexDocumentsAction
mit ihrem eigenen Vorgang erstellen, indem Sie die entsprechende Methode aufrufen, z.B. IndexDocumentsAction.Merge
, IndexAction.Upload
usw.
Der dritte Teil dieser Methode ist ein Catch-Block, der einen wichtigen Fehlerfall bei der Indizierung abfängt. Falls der Suchdienst Dokumente im Batch nicht indizieren kann, wird eine RequestFailedException
ausgelöst. Eine Ausnahme kann auftreten, wenn Sie Dokumente indizieren, während Ihr Dienst stark ausgelastet ist. Es wird dringend empfohlen, diesen Fall in Ihrem Code explizit zu behandeln. Zum Beispiel kann die Indizierung der zuvor nicht indizierten Dokumente nach einer Weile wieder aufgenommen werden oder der Vorgang kann, wie im Beispiel gezeigt, nach der Aufzeichnung des Fehlers fortgeführt werden. Je nach Datenkonsistenzanforderungen Ihrer Anwendung sind aber auch andere Lösungen möglich. Eine Alternative besteht darin, SearchIndexingBufferedSender für intelligente Batchverarbeitung, automatische Bereinigung und die Wiederholung fehlgeschlagener Indizierungsaktionen zu verwenden. Weiteren Kontext finden Sie im SearchIndexingBufferedSender-Beispiel.
Der letzte Teil der Methode UploadDocuments
fügt eine Verzögerung von zwei Sekunden hinzu. Da die Indizierung in Ihrem Suchdienst asynchron erfolgt, muss die Beispielanwendung einen Augenblick warten, damit sichergestellt ist, dass die Dokumente für Suchen zur Verfügung stehen. Verzögerungen wie diese sind in der Regel nur in Demos, Tests und Beispielanwendungen erforderlich.
Aufrufen von UploadDocuments in Main()
Der folgende Codeausschnitt richtet eine Instanz von SearchClient
mithilfe der GetSearchClient
-Methode von indexClient ein. indexClient verwendet einen API-Schlüssel für Administratoren für die dazugehörigen Anforderungen. Dieser ist erforderlich, um Dokumente laden oder aktualisieren zu können.
Ein alternativer Ansatz besteht darin, SearchClient
direkt aufzurufen und dabei einen API-Schlüssel für Administratoren für AzureKeyCredential
zu übergeben.
SearchClient searchClient = indexClient.GetSearchClient(indexName);
Console.WriteLine("{0}", "Uploading documents...\n");
UploadDocuments(searchClient);
Ausführen von Abfragen
Richten Sie zunächst einen SearchClient
ein, der den Dienstendpunkt und den Abfrage-API-Schlüssel aus appsettings.json liest:
private static SearchClient CreateSearchClientForQueries(string indexName, IConfigurationRoot configuration)
{
string searchServiceEndPoint = configuration["YourSearchServiceEndPoint"];
string queryApiKey = configuration["YourSearchServiceQueryApiKey"];
SearchClient searchClient = new SearchClient(new Uri(searchServiceEndPoint), indexName, new AzureKeyCredential(queryApiKey));
return searchClient;
}
Definieren Sie dann eine Methode, die eine Abfrageanforderung sendet.
Jedes Mal, wenn eine Abfrage von der Methode ausgeführt wird, erstellt diese Methode ein neues SearchOptions
-Objekt. Mit diesem Objekt werden zusätzliche Abfrageoptionen wie Sortierung, Filter, Paging und Facettierung festgelegt. Bei dieser Methode werden die Eigenschaften Filter
, Select
und OrderBy
für verschiedene Abfragen festgelegt. Weitere Informationen zur Syntax von Suchabfrageausdrücken finden Sie unter Einfache Abfragesyntax in Azure Cognitive Search.
Der nächste Schritt ist die Abfrageausführung. Zum Ausführen der Suche wird die SearchClient.Search
-Methode verwendet. Übergeben Sie für jede Abfrage den zu verwendenden Suchtext als Zeichenfolge (bzw. "*"
, wenn kein Suchtext vorliegt) sowie die zuvor erstellten Suchoptionen. Außerdem geben wir Hotel
als Typparameter für SearchClient.Search
an, wodurch das SDK angewiesen wird, die Dokumente im Suchergebnis in Objekte des Typs Hotel
zu deserialisieren.
private static void RunQueries(SearchClient searchClient)
{
SearchOptions options;
SearchResults<Hotel> results;
Console.WriteLine("Query 1: Search for 'motel'. Return only the HotelName in results:\n");
options = new SearchOptions();
options.Select.Add("HotelName");
results = searchClient.Search<Hotel>("motel", options);
WriteDocuments(results);
Console.Write("Query 2: Apply a filter to find hotels with rooms cheaper than $100 per night, ");
Console.WriteLine("returning the HotelId and Description:\n");
options = new SearchOptions()
{
Filter = "Rooms/any(r: r/BaseRate lt 100)"
};
options.Select.Add("HotelId");
options.Select.Add("Description");
results = searchClient.Search<Hotel>("*", options);
WriteDocuments(results);
Console.Write("Query 3: Search the entire index, order by a specific field (lastRenovationDate) ");
Console.Write("in descending order, take the top two results, and show only hotelName and ");
Console.WriteLine("lastRenovationDate:\n");
options =
new SearchOptions()
{
Size = 2
};
options.OrderBy.Add("LastRenovationDate desc");
options.Select.Add("HotelName");
options.Select.Add("LastRenovationDate");
results = searchClient.Search<Hotel>("*", options);
WriteDocuments(results);
Console.WriteLine("Query 4: Search the HotelName field for the term 'hotel':\n");
options = new SearchOptions();
options.SearchFields.Add("HotelName");
//Adding details to select, because "Location" isn't supported yet when deserializing search result to "Hotel"
options.Select.Add("HotelId");
options.Select.Add("HotelName");
options.Select.Add("Description");
options.Select.Add("Category");
options.Select.Add("Tags");
options.Select.Add("ParkingIncluded");
options.Select.Add("LastRenovationDate");
options.Select.Add("Rating");
options.Select.Add("Address");
options.Select.Add("Rooms");
results = searchClient.Search<Hotel>("hotel", options);
WriteDocuments(results);
}
Definieren Sie als dritten Schritt eine Methode, die die Antwort schreibt und dabei jedes Dokument in die Konsole schreibt:
private static void WriteDocuments(SearchResults<Hotel> searchResults)
{
foreach (SearchResult<Hotel> result in searchResults.GetResults())
{
Console.WriteLine(result.Document);
}
Console.WriteLine();
}
Aufrufen von RunQueries in Main()
SearchClient indexClientForQueries = CreateSearchClientForQueries(indexName, configuration);
Console.WriteLine("{0}", "Running queries...\n");
RunQueries(indexClientForQueries);
Informationen zu Abfragekonstrukten
Lassen Sie uns die einzelnen Abfragen einmal näher betrachten. Hier ist der Code zum Ausführen der ersten Abfrage:
options = new SearchOptions();
options.Select.Add("HotelName");
results = searchClient.Search<Hotel>("motel", options);
WriteDocuments(results);
In diesem Fall durchsuchen wir den gesamten Index nach dem Wort motel in einem beliebigen durchsuchbaren Feld und möchten nur die Hotelnamen abrufen, wie durch die Option Select
angegeben. Dies sind die Ergebnisse:
Name: Stay-Kay City Hotel
Name: Old Century Hotel
Verwenden Sie in der zweiten Abfrage einen Filter, um Ergebnisse für „Rooms“ mit einem Preis pro Nacht unter 100 US-Dollar auszuwählen. Geben Sie in den Ergebnissen nur Hotel-ID und -Beschreibung zurück:
options = new SearchOptions()
{
Filter = "Rooms/any(r: r/BaseRate lt 100)"
};
options.Select.Add("HotelId");
options.Select.Add("Description");
results = searchClient.Search<Hotel>("*", options);
Diese Abfrage verwendet einen OData $filter
-Ausdruck, Rooms/any(r: r/BaseRate lt 100)
, um die Dokumente im Index zu filtern. Dadurch wird der Any-Operator verwendet, um „BaseRate lt 100“ auf jedes Element in der Sammlung „Rooms“ anzuwenden. Weitere Informationen finden Sie unter OData-Filtersyntax.
Suchen Sie in der dritten Abfrage nach den zwei besten, in jüngster Zeit renovierten Hotels, und zeigen Sie deren Hotelnamen und das Datum der letzten Renovierung an. Hier ist der -Code:
options =
new SearchOptions()
{
Size = 2
};
options.OrderBy.Add("LastRenovationDate desc");
options.Select.Add("HotelName");
options.Select.Add("LastRenovationDate");
results = searchClient.Search<Hotel>("*", options);
WriteDocuments(results);
Suchen Sie in der letzten Abfrage nach allen Hotelnamen, die das Wort hotel enthalten:
options.Select.Add("HotelId");
options.Select.Add("HotelName");
options.Select.Add("Description");
options.Select.Add("Category");
options.Select.Add("Tags");
options.Select.Add("ParkingIncluded");
options.Select.Add("LastRenovationDate");
options.Select.Add("Rating");
options.Select.Add("Address");
options.Select.Add("Rooms");
results = searchClient.Search<Hotel>("hotel", options);
WriteDocuments(results);
In diesem Abschnitt schließt sich der Kreis zur Einführung in das .NET SDK, hören Sie hier aber noch nicht auf. Im nächsten Abschnitt werden weitere Ressourcen vorgeschlagen, um mehr über die Programmierung mit Azure AI Search zu erfahren.
Zugehöriger Inhalt
Sehen Sie sich die API-Referenzdokumentation für Azure.Search.Documents und die REST-API an.
Sehen Sie sich unter azure-search-dotnet-samples und search-dotnet-getting-started andere auf Azure.Search.Documents basierende Codebeispiele an.
Lesen Sie den Abschnitt Namenskonventionen, um sich mit den Namensregeln für verschiedene Objekte vertraut zu machen.
Sehen Sie sich den Artikel zu Unterstützten Datentypen an.