Använda Microsoft.Azure.Search i ett C# .NET-program
Den här artikeln beskriver hur du skapar och hanterar sökobjekt med hjälp av C# och det äldre klientbiblioteket Microsoft.Azure.Search (version 10) i Azure SDK för .NET.
Version 10 är den sista versionen av Microsoft.Azure.Search-paketet. Framöver distribueras nya funktioner i Azure.Search.Documents från Azure SDK-teamet.
Anteckning
Om du har befintliga eller inflight-utvecklingsprojekt kan du fortsätta att använda version 10. För nya projekt eller för att använda nya funktioner bör du övergå till det nya biblioteket.
Om version 10
SDK består av några klientbibliotek som gör att du kan hantera dina index, datakällor, indexerare och synonymkartor, samt ladda upp och hantera dokument och köra frågor, allt utan att behöva ta itu med informationen om HTTP och JSON. Alla dessa klientbibliotek distribueras som NuGet-paket.
Huvudpaketet för NuGet är Microsoft.Azure.Search
, vilket är ett metapaket som innehåller alla andra paket som beroenden. Använd det här paketet om du precis har börjat eller om du vet att ditt program behöver alla funktioner i Azure Cognitive Search.
De andra NuGet-paketen i SDK:n är:
-
Microsoft.Azure.Search.Data
: Använd det här paketet om du utvecklar ett .NET-program med Azure Cognitive Search och du bara behöver fråga eller uppdatera dokument i dina index. Om du också behöver skapa eller uppdatera index, synonymkartor eller andra resurser på tjänstnivå använder du paketetMicrosoft.Azure.Search
i stället. -
Microsoft.Azure.Search.Service
: Använd det här paketet om du utvecklar automatisering i .NET för att hantera Azure Cognitive Search index, synonymkartor, indexerare, datakällor eller andra resurser på tjänstnivå. Om du bara behöver fråga eller uppdatera dokument i dina index använder du paketetMicrosoft.Azure.Search.Data
i stället. Om du behöver alla funktioner i Azure Cognitive Search använder du paketetMicrosoft.Azure.Search
i stället. -
Microsoft.Azure.Search.Common
: Vanliga typer som behövs av Azure Cognitive Search .NET-bibliotek. Du behöver inte använda det här paketet direkt i ditt program. Den är bara avsedd att användas som ett beroende.
De olika klientbiblioteken definierar klasser som , och , samt åtgärder som Indexes.Create
och Documents.Search
i klasserna SearchServiceClient
och SearchIndexClient
.Document
Field
Index
Dessa klasser är ordnade i följande namnområden:
Om du vill ge feedback om en framtida uppdatering av SDK:t kan du läsa vår feedbacksida eller skapa ett problem på GitHub och nämna "Azure Cognitive Search" i ärenderubriken.
.NET SDK:n riktar sig mot versionen 2019-05-06
av Azure Cognitive Search REST API. Den här versionen innehåller stöd för komplexa typer, AI-berikning, automatisk komplettering och JsonLines-parsningsläge vid indexering av Azure Blobs.
Den här SDK:n stöder inte hanteringsåtgärder som att skapa och skala söktjänster och hantera API-nycklar. Om du behöver hantera dina sökresurser från ett .NET-program kan du använda Azure Cognitive Search .NET Management SDK.
Uppgradera till v10
Om du redan använder en äldre version av Azure Cognitive Search .NET SDK och vill uppgradera till den senaste allmänt tillgängliga versionen förklarar den här artikeln hur du gör.
Krav för SDK
- Visual Studio 2017 eller senare.
- Din egen Azure Cognitive Search tjänst. För att kunna använda SDK behöver du namnet på din tjänst och en eller flera API-nycklar. Om du skapar en tjänst i portalen får du hjälp med de här stegen.
- Ladda ned det Azure Cognitive Search .NET SDK NuGet-paketet med hjälp av "Hantera NuGet-paket" i Visual Studio. Sök bara efter paketnamnet
Microsoft.Azure.Search
på NuGet.org (eller något av de andra paketnamnen ovan om du bara behöver en delmängd av funktionen).
Azure Cognitive Search .NET SDK stöder program som är inriktade på .NET Framework 4.5.2 och senare, samt .NET Core 2.0 och senare.
Kärnscenarier
Det finns flera saker du behöver göra i sökprogrammet. I den här självstudien går vi igenom följande kärnscenarier:
- Skapa ett index
- Fylla i indexet med dokument
- Söka efter dokument med hjälp av fulltextsökning och -filter
Följande exempelkod illustrerar var och en av dessa scenarier. Använd gärna kodfragmenten i ditt eget program.
Översikt
Exempelprogrammet som vi ska utforska skapar ett nytt index med namnet "hotels", fyller det med några dokument och kör sedan några sökfrågor. Här är huvudprogrammet som visar det övergripande flödet:
// 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();
SearchServiceClient serviceClient = CreateSearchServiceClient(configuration);
string indexName = configuration["SearchIndexName"];
Console.WriteLine("{0}", "Deleting index...\n");
DeleteIndexIfExists(indexName, serviceClient);
Console.WriteLine("{0}", "Creating index...\n");
CreateIndex(indexName, serviceClient);
ISearchIndexClient indexClient = serviceClient.Indexes.GetClient(indexName);
Console.WriteLine("{0}", "Uploading documents...\n");
UploadDocuments(indexClient);
ISearchIndexClient indexClientForQueries = CreateSearchIndexClient(configuration);
RunQueries(indexClientForQueries);
Console.WriteLine("{0}", "Complete. Press any key to end application...\n");
Console.ReadKey();
}
Anteckning
Du hittar hela källkoden för exempelprogrammet i den här genomgången på GitHub.
Vi går igenom det här steg för steg. Först måste vi skapa en ny SearchServiceClient
. Med det här objektet kan du hantera index. För att kunna skapa en måste du ange ditt Azure Cognitive Search tjänstnamn samt en administratörs-API-nyckel. Du kan ange den här informationen i appsettings.json
exempelprogrammets fil.
private static SearchServiceClient CreateSearchServiceClient(IConfigurationRoot configuration)
{
string searchServiceName = configuration["SearchServiceName"];
string adminApiKey = configuration["SearchServiceAdminApiKey"];
SearchServiceClient serviceClient = new SearchServiceClient(searchServiceName, new SearchCredentials(adminApiKey));
return serviceClient;
}
Anteckning
Om du anger en felaktig nyckel (till exempel en frågenyckel där en administratörsnyckel krävdes) SearchServiceClient
genererar den ett CloudException
med felmeddelandet "Förbjuden" första gången du anropar en åtgärdsmetod på den, till exempel Indexes.Create
. Om detta händer dig dubbelkollar du vår API-nyckel.
De följande raderna anropar metoder för att skapa ett index med namnet "hotels", och tar bort det först om det redan finns. Vi går igenom dessa metoder lite senare.
Console.WriteLine("{0}", "Deleting index...\n");
DeleteIndexIfExists(indexName, serviceClient);
Console.WriteLine("{0}", "Creating index...\n");
CreateIndex(indexName, serviceClient);
Därefter måste indexet fyllas i. För att fylla i indexet behöver vi en SearchIndexClient
. Det finns två sätt att hämta en: genom att konstruera den eller genom att anropa Indexes.GetClient
på SearchServiceClient
. Vi använder det senare för enkelhetens skull.
ISearchIndexClient indexClient = serviceClient.Indexes.GetClient(indexName);
Anteckning
I ett vanligt sökprogram kan indexhantering och population hanteras av en separat komponent från sökfrågor.
Indexes.GetClient
är praktiskt för att fylla i ett index eftersom det sparar problem med att tillhandahålla ytterligare SearchCredentials
. Den gör det genom att skicka administratörsnyckeln som du använde för att skapa SearchServiceClient
till den nya SearchIndexClient
. Men i den del av programmet som kör frågor är det bättre att skapa SearchIndexClient
direkt så att du kan skicka in en frågenyckel, vilket bara gör att du kan läsa data i stället för en administratörsnyckel. Den här riktlinjen följer principen om lägsta behörighet och hjälper till att göra programmet säkrare. Du kan läsa mer om administratörsnycklar och frågenycklar här.
Nu när vi har en SearchIndexClient
kan vi fylla i indexet. Indexpopulationen görs med en annan metod som vi går igenom senare.
Console.WriteLine("{0}", "Uploading documents...\n");
UploadDocuments(indexClient);
Slutligen kör vi några sökfrågor och visar resultatet. Den här gången använder vi en annan SearchIndexClient
:
ISearchIndexClient indexClientForQueries = CreateSearchIndexClient(indexName, configuration);
RunQueries(indexClientForQueries);
Vi tar en närmare titt på RunQueries
metoden senare. Här är koden för att skapa den nya SearchIndexClient
:
private static SearchIndexClient CreateSearchIndexClient(string indexName, IConfigurationRoot configuration)
{
string searchServiceName = configuration["SearchServiceName"];
string queryApiKey = configuration["SearchServiceQueryApiKey"];
SearchIndexClient indexClient = new SearchIndexClient(searchServiceName, indexName, new SearchCredentials(queryApiKey));
return indexClient;
}
Den här gången använder vi en frågenyckel eftersom vi inte behöver skrivåtkomst till indexet. Du kan ange den här informationen i appsettings.json
exempelprogrammets fil.
Om du kör det här programmet med ett giltigt tjänstnamn och API-nycklar bör utdata se ut så här: (Vissa konsolutdata har ersatts med "..." för illustrationsändamål.)
Deleting index...
Creating index...
Uploading documents...
Waiting for documents to be indexed...
Search the entire index for the term 'motel' and return only the HotelName field:
Name: Secret Point Motel
Name: Twin Dome Motel
Apply a filter to the index to find hotels with a room cheaper than $100 per night, and return the hotelId and description:
HotelId: 1
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 Times Square and the historic centre of the city, as well as other places of interest that make New York one of America's most attractive and cosmopolitan cities.
HotelId: 2
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.
Search the entire index, order by a specific field (lastRenovationDate) in descending order, take the top two results, and show only hotelName and lastRenovationDate:
Name: Triple Landscape Hotel
Last renovated on: 9/20/2015 12:00:00 AM +00:00
Name: Twin Dome Motel
Last renovated on: 2/18/1979 12:00:00 AM +00:00
Search the hotel names for the term 'hotel':
HotelId: 3
Name: Triple Landscape Hotel
...
Complete. Press any key to end application...
Den fullständiga källkoden för programmet tillhandahålls i slutet av den här artikeln.
Därefter tar vi en närmare titt på var och en av metoderna som anropas av Main
.
Skapa ett index
När du har skapat ett SearchServiceClient
Main
tar du bort indexet "hotels" om det redan finns. Borttagningen görs med följande metod:
private static void DeleteIndexIfExists(string indexName, SearchServiceClient serviceClient)
{
if (serviceClient.Indexes.Exists(indexName))
{
serviceClient.Indexes.Delete(indexName);
}
}
Den här metoden använder angiven SearchServiceClient
för att kontrollera om indexet finns och i så fall ta bort det.
Anteckning
Exempelkoden i den här artikeln använder synkrona metoder i Azure Cognitive Search .NET SDK för enkelhetens skull. Vi rekommenderar att du använder asynkrona metoder i dina egna program så att de blir skalbara och responsiva. I metoden ovan kan du till exempel använda ExistsAsync
och DeleteAsync
i stället för Exists
och Delete
.
Main
Skapar sedan ett nytt "hotell"-index genom att anropa den här metoden:
private static void CreateIndex(string indexName, SearchServiceClient serviceClient)
{
var definition = new Index()
{
Name = indexName,
Fields = FieldBuilder.BuildForType<Hotel>()
};
serviceClient.Indexes.Create(definition);
}
Den här metoden skapar ett nytt Index
objekt med en lista över Field
objekt som definierar schemat för det nya indexet. Varje fält har ett namn, en datatyp och flera attribut som definierar dess sökbeteende. Klassen FieldBuilder
använder reflektion för att skapa en lista över Field
objekt för indexet genom att undersöka de offentliga egenskaperna och attributen för den angivna Hotel
modellklassen. Vi tar en närmare titt på Hotel
klassen senare.
Anteckning
Du kan alltid skapa listan med Field
objekt direkt i stället för att använda FieldBuilder
om det behövs. Du kanske till exempel inte vill använda en modellklass eller så kan du behöva använda en befintlig modellklass som du inte vill ändra genom att lägga till attribut.
Förutom fält kan du också lägga till bedömningsprofiler, förslagsmakare eller CORS-alternativ i indexet (dessa parametrar utelämnas från exemplet för korthet). Du hittar mer information om indexobjektet och dess komponenter i SDK-referensen, samt i referensen för Azure Cognitive Search REST API.
Fylla i indexet
Nästa steg i fyller i Main
det nyligen skapade indexet. Den här indexpopulationen görs med följande metod: (Viss kod ersätts med "..." för illustrationsändamål. Se den fullständiga exempellösningen för den fullständiga datapopulationskoden.)
private static void UploadDocuments(ISearchIndexClient indexClient)
{
var hotels = new Hotel[]
{
new Hotel()
{
HotelId = "1",
HotelName = "Secret Point Motel",
...
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)",
...
}
}
},
new Hotel()
{
HotelId = "2",
HotelName = "Twin Dome Motel",
...
{
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)",
...
}
}
},
new Hotel()
{
HotelId = "3",
HotelName = "Triple 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)",
...
}
}
}
};
var batch = IndexBatch.Upload(hotels);
try
{
indexClient.Documents.Index(batch);
}
catch (IndexBatchException e)
{
// 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}",
String.Join(", ", e.IndexingResults.Where(r => !r.Succeeded).Select(r => r.Key)));
}
Console.WriteLine("Waiting for documents to be indexed...\n");
Thread.Sleep(2000);
}
Den här metoden har fyra delar. Den första skapar en matris med 3 Hotel
objekt var och en med 3 Room
objekt som kommer att fungera som våra indata att ladda upp till indexet. Dessa data är hårdkodade för enkelhetens skull. I ditt eget program kommer dina data troligen från en extern datakälla, till exempel en SQL databas.
Den andra delen skapar en IndexBatch
som innehåller dokumenten. Du anger den åtgärd som du vill tillämpa på batchen när du skapar den, i det här fallet genom att anropa IndexBatch.Upload
. Batchen laddas sedan upp till Azure Cognitive Search index med Documents.Index
metoden .
Anteckning
I det här exemplet laddar vi bara upp dokument. Om du vill sammanfoga ändringar i befintliga dokument eller ta bort dokument kan du skapa batchar genom att anropa IndexBatch.Merge
, IndexBatch.MergeOrUpload
eller IndexBatch.Delete
i stället. Du kan också blanda olika åtgärder i en enda batch genom att anropa IndexBatch.New
, som tar en samling IndexAction
objekt, som var och en instruerar Azure Cognitive Search att utföra en viss åtgärd på ett dokument. Du kan skapa var och en IndexAction
med en egen åtgärd genom att anropa motsvarande metod, till exempel IndexAction.Merge
, IndexAction.Upload
och så vidare.
Den tredje delen av den här metoden är ett catch-block som hanterar ett viktigt felfall för indexering. Om din Azure Cognitive Search-tjänst inte kan indexera några av dokumenten i batchen genereras en IndexBatchException
av Documents.Index
. Det här undantaget kan inträffa om du indexerar dokument medan tjänsten är hårt belastad. Vi rekommenderar starkt att du uttryckligen hanterar den här situationen i din kod. Du kan fördröja och sedan försöka indexera dokumentet som misslyckades igen eller så kan du logga och fortsätta som i exemplet, eller göra något annat beroende på programmets krav på datakonsekvens.
Anteckning
Du kan använda FindFailedActionsToRetry
metoden för att skapa en ny batch som bara innehåller de åtgärder som misslyckades i ett tidigare anrop till Index
. Det finns en diskussion om hur du använder det korrekt på StackOverflow.
Slutligen fördröjs metoden i UploadDocuments
två sekunder. Indexering sker asynkront i din Azure Cognitive Search-tjänst, så exempelprogrammet måste vänta en kort stund för att säkerställa att dokumenten är tillgängliga för sökning. Fördröjningar som den här är normalt endast nödvändiga i demonstrationer, tester och exempelprogram.
Hur .NET SDK hanterar dokument
Du kanske undrar hur Azure Cognitive Search .NET SDK kan ladda upp instanser av en användardefinierad klass som Hotel
till indexet. För att besvara den frågan ska vi titta på Hotel
klassen :
using System;
using Microsoft.Azure.Search;
using Microsoft.Azure.Search.Models;
using Microsoft.Spatial;
using Newtonsoft.Json;
public partial class Hotel
{
[System.ComponentModel.DataAnnotations.Key]
[IsFilterable]
public string HotelId { get; set; }
[IsSearchable, IsSortable]
public string HotelName { get; set; }
[IsSearchable]
[Analyzer(AnalyzerName.AsString.EnLucene)]
public string Description { get; set; }
[IsSearchable]
[Analyzer(AnalyzerName.AsString.FrLucene)]
[JsonProperty("Description_fr")]
public string DescriptionFr { get; set; }
[IsSearchable, IsFilterable, IsSortable, IsFacetable]
public string Category { get; set; }
[IsSearchable, IsFilterable, IsFacetable]
public string[] Tags { get; set; }
[IsFilterable, IsSortable, IsFacetable]
public bool? ParkingIncluded { get; set; }
// SmokingAllowed reflects whether any room in the hotel allows smoking.
// The JsonIgnore attribute indicates that a field should not be created
// in the index for this property and it will only be used by code in the client.
[JsonIgnore]
public bool? SmokingAllowed => (Rooms != null) ? Array.Exists(Rooms, element => element.SmokingAllowed == true) : (bool?)null;
[IsFilterable, IsSortable, IsFacetable]
public DateTimeOffset? LastRenovationDate { get; set; }
[IsFilterable, IsSortable, IsFacetable]
public double? Rating { get; set; }
public Address Address { get; set; }
[IsFilterable, IsSortable]
public GeographyPoint Location { get; set; }
public Room[] Rooms { get; set; }
}
Det första du bör notera är att namnet på varje offentlig egenskap i Hotel
klassen mappas till ett fält med samma namn i indexdefinitionen. Om du vill att varje fält ska börja med en gemen [SerializePropertyNamesAsCamelCase]
bokstav ("kamelfall") kan du instruera SDK:t att mappa egenskapsnamnen till kamelfallet automatiskt med attributet för klassen . Det här scenariot är vanligt i .NET-program som utför databindning där målschemat ligger utanför programutvecklarens kontroll utan att behöva bryta mot riktlinjerna för namngivning av "Pascal-fall" i .NET.
Anteckning
Azure Cognitive Search .NET SDK använder NewtonSoft-JSON.NET-biblioteket för att serialisera och deserialisera dina anpassade modellobjekt till och från JSON. Du kan anpassa den här serialiseringen om det behövs. Mer information finns i Anpassad serialisering med JSON.NET.
Det andra att märka är att varje egenskap är dekorerad med attribut som IsFilterable
, IsSearchable
, Key
och Analyzer
. Dessa attribut mappas direkt till motsvarande fältattribut i ett Azure Cognitive Search index. Klassen FieldBuilder
använder dessa egenskaper för att konstruera fältdefinitioner för indexet.
Det tredje viktiga med Hotel
klassen är datatyperna för de offentliga egenskaperna. .NET-typerna för dessa egenskaper mappar till deras motsvarande fälttyper i indexdefinitionen. Exempelvis mappar Category
-strängegenskapen till category
-fältet, som är av typen Edm.String
. Det finns liknande typmappningar mellan bool?
, Edm.Boolean
, DateTimeOffset?
och Edm.DateTimeOffset
så vidare. De specifika reglerna för typmappningen dokumenteras med Documents.Get
metoden i referensen för Azure Cognitive Search .NET SDK. Klassen FieldBuilder
tar hand om den här mappningen åt dig, men det kan fortfarande vara bra att förstå om du behöver felsöka eventuella serialiseringsproblem.
Såg du SmokingAllowed
egenskapen?
[JsonIgnore]
public bool? SmokingAllowed => (Rooms != null) ? Array.Exists(Rooms, element => element.SmokingAllowed == true) : (bool?)null;
Attributet JsonIgnore
för den här egenskapen instruerar FieldBuilder
att inte serialisera det till indexet som ett fält. Det här är ett bra sätt att skapa beräknade egenskaper på klientsidan som du kan använda som hjälp i ditt program. I det här fallet återspeglar egenskapen SmokingAllowed
om någon Room
i Rooms
samlingen tillåter rökning. Om alla är falska indikerar det att hela hotellet inte tillåter rökning.
Vissa egenskaper som Address
och Rooms
är instanser av .NET-klasser. Dessa egenskaper representerar mer komplexa datastrukturer och kräver därför fält med en komplex datatyp i indexet.
Egenskapen Address
representerar en uppsättning med flera värden i Address
klassen, som definieras nedan:
using System;
using Microsoft.Azure.Search;
using Microsoft.Azure.Search.Models;
using Newtonsoft.Json;
namespace AzureSearch.SDKHowTo
{
public partial class Address
{
[IsSearchable]
public string StreetAddress { get; set; }
[IsSearchable, IsFilterable, IsSortable, IsFacetable]
public string City { get; set; }
[IsSearchable, IsFilterable, IsSortable, IsFacetable]
public string StateProvince { get; set; }
[IsSearchable, IsFilterable, IsSortable, IsFacetable]
public string PostalCode { get; set; }
[IsSearchable, IsFilterable, IsSortable, IsFacetable]
public string Country { get; set; }
}
}
Den här klassen innehåller de standardvärden som används för att beskriva adresser i USA eller Kanada. Du kan använda typer som denna för att gruppera logiska fält i indexet.
Egenskapen Rooms
representerar en matris med Room
objekt:
using System;
using Microsoft.Azure.Search;
using Microsoft.Azure.Search.Models;
using Newtonsoft.Json;
namespace AzureSearch.SDKHowTo
{
public partial class Room
{
[IsSearchable]
[Analyzer(AnalyzerName.AsString.EnMicrosoft)]
public string Description { get; set; }
[IsSearchable]
[Analyzer(AnalyzerName.AsString.FrMicrosoft)]
[JsonProperty("Description_fr")]
public string DescriptionFr { get; set; }
[IsSearchable, IsFilterable, IsFacetable]
public string Type { get; set; }
[IsFilterable, IsFacetable]
public double? BaseRate { get; set; }
[IsSearchable, IsFilterable, IsFacetable]
public string BedOptions { get; set; }
[IsFilterable, IsFacetable]
public int SleepsCount { get; set; }
[IsFilterable, IsFacetable]
public bool? SmokingAllowed { get; set; }
[IsSearchable, IsFilterable, IsFacetable]
public string[] Tags { get; set; }
}
}
Din datamodell i .NET och dess motsvarande indexschema bör utformas för att stödja den sökupplevelse som du vill ge till slutanvändaren. Varje objekt på den översta nivån i .NET, dvs. dokumentet i indexet, motsvarar ett sökresultat som du skulle presentera i användargränssnittet. I ett hotellsökningsprogram kanske slutanvändarna till exempel vill söka efter hotellnamn, hotellets funktioner eller egenskaperna hos ett visst rum. Vi går igenom några frågeexempel lite senare.
Den här möjligheten att använda dina egna klasser för att interagera med dokument i indexet fungerar i båda riktningarna. Du kan också hämta sökresultat och låta SDK:t automatiskt deserialisera dem till valfri typ, som vi ser i nästa avsnitt.
Anteckning
Azure Cognitive Search .NET SDK stöder också dynamiskt skrivna dokument med hjälp av Document
klassen , vilket är en nyckel/värde-mappning av fältnamn till fältvärden. Detta är användbart i scenarier då du inte känner till indexeringsschemat redan i designfasen, eller då det skulle vara opraktiskt att binda till specifika modellklasser. Alla metoder i SDK som hanterar dokument har överlagringar som fungerar med klassen Document
, samt starkt typifierade överlagringar som använder en parameter av generisk typ. Endast de senare används i exempelkoden i den här självstudien.
KlassenDocument
ärver från Dictionary<string, object>
.
Varför du bör använda datatyper som kan ha värdet null
När du utformar dina egna modellklasser för att mappa till ett Azure Cognitive Search index rekommenderar vi att du deklarerar egenskaper för värdetyper som bool
och int
ska vara nullbara (till exempel bool?
i stället för bool
). Om du använder en icke-nullbar egenskap måste du se till att inga dokument i indexet innehåller ett null-värde för motsvarande fält. Varken SDK:et eller Azure Cognitive Search-tjänsten hjälper dig att framtvinga detta.
Detta är inte bara ett hypotetiskt problem. Tänk dig ett scenario där du lägger till ett nytt fält till ett befintligt index som är av typen Edm.Int32
. När indexdefinitionen har uppdaterats har alla dokument ett null-värde för det nya fältet (eftersom alla typer kan ha värdet null i Azure Cognitive Search). Om du sedan använder en modellklass med en icke-nullbar int
-egenskap för det fältet returneras ett JsonSerializationException
som detta när du försöker hämta dokument:
Error converting value {null} to type 'System.Int32'. Path 'IntValue'.
Av den anledningen rekommenderar vi att du använder nullbara typer i dina modellklasser som bästa praxis.
Anpassad serialisering med JSON.NET
SDK använder JSON.NET för serialisering och avserialisering av dokument. Du kan anpassa serialisering och deserialisering om det behövs genom att definiera din egen JsonConverter
eller IContractResolver
. Mer information finns i dokumentationen om JSON.NET. Detta kan vara användbart när du vill anpassa en befintlig modellklass från ditt program för användning med Azure Cognitive Search och andra mer avancerade scenarier. Med anpassad serialisering kan du till exempel:
- Inkludera eller exkludera vissa egenskaper för din modellklass från att lagras som dokumentfält.
- Mappa mellan egenskapsnamn i koden och fältnamnen i ditt index.
- Skapa anpassade attribut som kan användas för att mappa egenskaper till dokumentfält.
Du hittar exempel på hur du implementerar anpassad serialisering i enhetstesterna för Azure Cognitive Search .NET SDK på GitHub. En bra utgångspunkt är den här mappen. Den innehåller klasser som används av anpassade serialiseringstester.
Söka efter dokument i indexet
Det sista steget i exempelprogrammet är att söka efter några dokument i indexet:
private static void RunQueries(ISearchIndexClient indexClient)
{
SearchParameters parameters;
DocumentSearchResult<Hotel> results;
Console.WriteLine("Search the entire index for the term 'motel' and return only the HotelName field:\n");
parameters =
new SearchParameters()
{
Select = new[] { "HotelName" }
};
results = indexClient.Documents.Search<Hotel>("motel", parameters);
WriteDocuments(results);
Console.Write("Apply a filter to the index to find hotels with a room cheaper than $100 per night, ");
Console.WriteLine("and return the hotelId and description:\n");
parameters =
new SearchParameters()
{
Filter = "Rooms/any(r: r/BaseRate lt 100)",
Select = new[] { "HotelId", "Description" }
};
results = indexClient.Documents.Search<Hotel>("*", parameters);
WriteDocuments(results);
Console.Write("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");
parameters =
new SearchParameters()
{
OrderBy = new[] { "LastRenovationDate desc" },
Select = new[] { "HotelName", "LastRenovationDate" },
Top = 2
};
results = indexClient.Documents.Search<Hotel>("*", parameters);
WriteDocuments(results);
Console.WriteLine("Search the entire index for the term 'hotel':\n");
parameters = new SearchParameters();
results = indexClient.Documents.Search<Hotel>("hotel", parameters);
WriteDocuments(results);
}
Varje gång den kör en fråga skapar den här metoden först ett nytt SearchParameters
objekt. Det här objektet används för att ange ytterligare alternativ för frågan, till exempel sortering, filtrering, sidindelning och fasettering. I den här metoden ställer vi in Filter
egenskapen , Select
, OrderBy
och Top
för olika frågor.
SearchParameters
Alla egenskaper dokumenteras här.
Nästa steg är att faktiskt köra sökfrågan. Sökningen körs med hjälp av Documents.Search
metoden . För varje fråga skickar vi den söktext som ska användas som en sträng (eller "*"
om det inte finns någon söktext), plus de sökparametrar som skapades tidigare. Vi anger Hotel
även som typparameter för Documents.Search
, som instruerar SDK:t att deserialisera dokument i sökresultaten till objekt av typen Hotel
.
Anteckning
Du hittar mer information om syntaxen för sökfrågeuttryck här.
Efter varje fråga itererar slutligen den här metoden igenom alla matchningar i sökresultaten och skriver ut varje dokument till konsolen:
private static void WriteDocuments(DocumentSearchResult<Hotel> searchResults)
{
foreach (SearchResult<Hotel> result in searchResults.Results)
{
Console.WriteLine(result.Document);
}
Console.WriteLine();
}
Låt oss ta en närmare titt på var och en av frågorna i tur och ordning. Här är koden för att köra den första frågan:
parameters =
new SearchParameters()
{
Select = new[] { "HotelName" }
};
results = indexClient.Documents.Search<Hotel>("motel", parameters);
WriteDocuments(results);
I det här fallet söker vi i hela indexet efter ordet "motell" i ett sökbart fält och vi vill bara hämta hotellnamnen enligt parametern Select
. Här är resultatet:
Name: Secret Point Motel
Name: Twin Dome Motel
Nästa fråga är lite mer intressant. Vi vill hitta alla hotell som har ett rum med ett nattpris på mindre än $ 100 och returnerar endast hotellets ID och beskrivning:
parameters =
new SearchParameters()
{
Filter = "Rooms/any(r: r/BaseRate lt 100)",
Select = new[] { "HotelId", "Description" }
};
results = indexClient.Documents.Search<Hotel>("*", parameters);
WriteDocuments(results);
Den här frågan använder ett OData-uttryck $filter
, Rooms/any(r: r/BaseRate lt 100)
, för att filtrera dokumenten i indexet. Då används alla operatorer för att tillämpa "BaseRate lt 100" på varje objekt i samlingen Rum. Du kan läsa mer om OData-syntaxen som Azure Cognitive Search stöder här.
Här är resultatet av frågan:
HotelId: 1
Description: The hotel is ideally located on the main commercial artery of the city in the heart of New York...
HotelId: 2
Description: The hotel is situated in a nineteenth century plaza, which has been expanded and renovated to...
Härnäst vill vi hitta de två bästa hotellen som har renoverats senast och visa hotellets namn och senaste renoveringsdatum. Här är koden:
parameters =
new SearchParameters()
{
OrderBy = new[] { "LastRenovationDate desc" },
Select = new[] { "HotelName", "LastRenovationDate" },
Top = 2
};
results = indexClient.Documents.Search<Hotel>("*", parameters);
WriteDocuments(results);
I det här fallet använder vi återigen OData-syntax för att ange parametern OrderBy
som lastRenovationDate desc
. Vi ställer också in Top
på 2 för att se till att vi bara får de två översta dokumenten. Precis som tidigare anger Select
vi vilka fält som ska returneras.
Här är resultatet:
Name: Fancy Stay Last renovated on: 6/27/2010 12:00:00 AM +00:00
Name: Roach Motel Last renovated on: 4/28/1982 12:00:00 AM +00:00
Slutligen vill vi hitta alla hotellnamn som matchar ordet "hotell":
parameters = new SearchParameters()
{
SearchFields = new[] { "HotelName" }
};
results = indexClient.Documents.Search<Hotel>("hotel", parameters);
WriteDocuments(results);
Och här är resultatet, som innehåller alla fält eftersom vi inte angav Select
egenskapen:
HotelId: 3
Name: Triple Landscape Hotel
...
Det här steget slutför självstudien, men sluta inte här. **Nästa steg ger ytterligare resurser för att lära dig mer om Azure Cognitive Search.
Nästa steg
- Bläddra i referensinformationen till .NET SDK och REST API.
- Granska namngivningskonventionerna för att lära dig reglerna för namngivning av olika objekt.
- Granska datatyper som stöds i Azure Cognitive Search.