Snabbstart: Fulltextsökning med hjälp av Azure SDK:er

Lär dig hur du använder klientbiblioteket Azure.Search.Documents i en Azure SDK för att skapa, läsa in och fråga ett sökindex med hjälp av exempeldata för fulltextsökning. Fulltextsökning använder Apache Lucene för indexering och frågor samt en BM25-rangordningsalgoritm för bedömning av resultat.

Den här snabbstarten innehåller steg för följande SDK:er:

Förutsättningar

  • Ett Azure-konto med en aktiv prenumeration. Skapa ett konto utan kostnad.

  • En Azure AI-tjänsten Search. Skapa en tjänst om du inte har någon. Du kan använda en kostnadsfri nivå för den här snabbstarten.

  • En API-nyckel och tjänstslutpunkt. Logga in på Azure-portalen och leta reda på söktjänsten.

    I Översikt kopierar du URL:en och sparar den i Anteckningar för ett senare steg. Här följer ett exempel på hur en slutpunkt kan se ut: https://mydemo.search.windows.net.

    I Nycklar kopierar och sparar du en administratörsnyckel för fullständig behörighet för att skapa och ta bort objekt. Det finns två utbytbara primära och sekundära nycklar. Välj någon av dem.

    Hämta en HTTP-slutpunkt och åtkomstnyckel

Skapa, läsa in och fråga ett index

Välj ett programmeringsspråk för nästa steg. Klientbiblioteken för Azure.Search.Documents är tillgängliga i Azure SDK:er för .NET, Python, Java och JavaScript.

Skapa ett konsolprogram med hjälp av klientbiblioteket Azure.Search.Documents för att skapa, läsa in och köra frågor mot ett sökindex. Du kan också ladda ned källkoden för att börja med ett färdigt projekt eller följa dessa steg för att skapa din egen.

Konfigurera din miljö

  1. Starta Visual Studio och skapa ett nytt projekt för en konsolapp.

  2. I Verktyg>NuGet Package Manager väljer du Hantera NuGet-paket för lösning....

  3. Välj bläddra.

  4. Sök efter Azure.Search.Documents-paketet och välj version 11.0 eller senare.

  5. Välj Installera till höger för att lägga till sammansättningen i projektet och lösningen.

Skapa en sökklient

  1. I Program.cs ändrar du namnområdet till AzureSearch.SDK.Quickstart.v11 och lägger sedan till följande using direktiv.

    using Azure;
    using Azure.Search.Documents;
    using Azure.Search.Documents.Indexes;
    using Azure.Search.Documents.Indexes.Models;
    using Azure.Search.Documents.Models;
    
  2. Skapa två klienter: SearchIndexClient skapar indexet och SearchClient läser in och frågar ett befintligt index. Båda behöver tjänstslutpunkten och en administratörs-API-nyckel för autentisering med behörighet att skapa/ta bort.

    Eftersom koden skapar URI:n åt dig anger du bara söktjänstens namn i egenskapen "serviceName".

     static void Main(string[] args)
     {
         string serviceName = "<your-search-service-name>";
         string apiKey = "<your-search-service-admin-api-key>";
         string indexName = "hotels-quickstart";
    
         // Create a SearchIndexClient to send create/delete index commands
         Uri serviceEndpoint = new Uri($"https://{serviceName}.search.windows.net/");
         AzureKeyCredential credential = new AzureKeyCredential(apiKey);
         SearchIndexClient adminClient = new SearchIndexClient(serviceEndpoint, credential);
    
         // Create a SearchClient to load and query documents
         SearchClient srchclient = new SearchClient(serviceEndpoint, indexName, credential);
         . . . 
     }
    

Skapa ett index

Den här snabbstarten skapar ett Hotell-index som du läser in med hotelldata och kör frågor mot. I det här steget definierar du fälten i indexet. Varje fältdefinition innehåller ett namn, en datatyp och attribut som avgör hur fältet används.

I det här exemplet används synkrona metoder i biblioteket Azure.Search.Documents för enkelhet och läsbarhet. För produktionsscenarier bör du dock använda asynkrona metoder för att hålla appen skalbar och dynamisk. Du skulle till exempel använda CreateIndexAsync i stället för CreateIndex.

  1. Lägg till en tom klassdefinition i projektet: Hotel.cs

  2. Kopiera följande kod till Hotel.cs för att definiera strukturen för ett hotelldokument. Attribut i fältet avgör hur det används i ett program. Attributet måste till exempel IsFilterable tilldelas till varje fält som stöder ett filteruttryck.

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

    I azure.search.documents-klientbiblioteket kan du använda SearchableField och SimpleField för att effektivisera fältdefinitioner. Båda är derivat av ett SearchField och kan förenkla koden:

    • SimpleField kan vara vilken datatyp som helst, är alltid inte sökbar (den ignoreras för fulltextsökningsfrågor) och kan hämtas (den är inte dold). Andra attribut är inaktiverade som standard, men kan aktiveras. Du kan använda ett SimpleField för dokument-ID eller fält som endast används i filter, fasetter eller bedömningsprofiler. I så fall bör du tillämpa eventuella attribut som är nödvändiga för scenariot, till exempel IsKey = true för ett dokument-ID. Mer information finns i SimpleFieldAttribute.cs i källkoden.

    • SearchableField måste vara en sträng och är alltid sökbar och hämtningsbar. Andra attribut är inaktiverade som standard, men kan aktiveras. Eftersom den här fälttypen är sökbar stöder den synonymer och det fullständiga komplementet av analysverktygsegenskaper. Mer information finns i SearchableFieldAttribute.cs i källkoden.

    Oavsett om du använder det grundläggande SearchField API:et eller någon av hjälpmodellerna måste du uttryckligen aktivera attribut för filter, fasetter och sortering. Till exempel måste IsFilterable, IsSortable och IsFacetable uttryckligen tillskrivas, som du ser i exemplet ovan.

  3. Lägg till en andra tom klassdefinition i projektet: Address.cs. Kopiera följande kod till klassen.

    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; }
         }
     }
    
  4. Skapa ytterligare två klasser: åsidosättningar Hotel.Methods.cs och Address.Methods.cs för ToString(). Dessa klasser används för att återge sökresultat i konsolens utdata. Innehållet i dessa klasser finns inte i den här artikeln, men du kan kopiera koden från filer i GitHub.

  5. I Program.cs skapar du ett SearchIndex-objekt och anropar sedan metoden CreateIndex för att uttrycka indexet i söktjänsten. Indexet innehåller också en SearchSuggester för att aktivera automatisk komplettering i de angivna fälten.

     // Create hotels-quickstart index
     private static void CreateIndex(string indexName, SearchIndexClient adminClient)
     {
         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);
    
         adminClient.CreateOrUpdateIndex(definition);
     }
    

Läsa in dokument

Azure AI Search söker efter innehåll som lagras i tjänsten. I det här steget läser du in JSON-dokument som överensstämmer med det hotellindex som du nyss skapade.

I Azure AI Search är sökdokument datastrukturer som både är indata för indexering och utdata från frågor. Som hämtats från en extern datakälla kan dokumentindata vara rader i en databas, blobar i Blob Storage eller JSON-dokument på disk. I det här exemplet tar vi en genväg och bäddar in JSON-dokument för fyra hotell i själva koden.

När du laddar upp dokument måste du använda ett IndexDocumentsBatch-objekt . Ett IndexDocumentsBatch objekt innehåller en samling åtgärder, som var och en innehåller ett dokument och en egenskap som talar om för Azure AI Search vilken åtgärd som ska utföras (ladda upp, slå samman, ta bort och slå sammanEllerUpload).

  1. I Program.cs skapar du en matris med dokument och indexåtgärder och skickar sedan matrisen till IndexDocumentsBatch. Dokumenten nedan överensstämmer med indexet hotels-quickstart enligt definitionen i hotellklassen.

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

    När du har initierat Objektet IndexDocumentsBatch kan du skicka det till indexet genom att anropa IndexDocuments på ditt SearchClient-objekt .

  2. Lägg till följande rader i Main(). Inläsning av dokument görs med Hjälp av SearchClient, men åtgärden kräver även administratörsbehörighet för tjänsten, som vanligtvis är associerad med SearchIndexClient. Ett sätt att konfigurera den här åtgärden är att hämta SearchClient via SearchIndexClient (adminClient i det här exemplet).

     SearchClient ingesterClient = adminClient.GetSearchClient(indexName);
    
     // Load documents
     Console.WriteLine("{0}", "Uploading documents...\n");
     UploadDocuments(ingesterClient);
    
  3. Eftersom det här är en konsolapp som kör alla kommandon sekventiellt lägger du till en väntetid på 2 sekunder mellan indexering och frågor.

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

    Fördröjningen på 2 sekunder kompenserar för indexering, vilket är asynkront, så att alla dokument kan indexeras innan frågorna körs. Kodning i en fördröjning är vanligtvis bara nödvändigt i demonstrationer, tester och exempelprogram.

Sök i ett index

Du kan få frågeresultat så snart det första dokumentet indexeras, men den faktiska testningen av indexet bör vänta tills alla dokument har indexerats.

Det här avsnittet lägger till två funktioner: frågelogik och resultat. För frågor använder du sökmetoden . Den här metoden tar söktext (frågesträngen) och andra alternativ.

Klassen SearchResults representerar resultatet.

  1. I Program.cs skapar du en WriteDocuments-metod som skriver ut sökresultat till konsolen.

    // Write search results to console
    private static void WriteDocuments(SearchResults<Hotel> searchResults)
    {
        foreach (SearchResult<Hotel> result in searchResults.GetResults())
        {
            Console.WriteLine(result.Document);
        }
    
        Console.WriteLine();
    }
    
    private static void WriteDocuments(AutocompleteResults autoResults)
    {
        foreach (AutocompleteItem result in autoResults.Results)
        {
            Console.WriteLine(result.Text);
        }
    
        Console.WriteLine();
    }
    
  2. Skapa en RunQueries-metod för att köra frågor och returnera resultat. Resultatet är Hotellobjekt. Det här exemplet visar metodsignaturen och den första frågan. Den här frågan visar parametern Välj som gör att du kan skapa resultatet med hjälp av valda fält från dokumentet.

    // Run queries, use WriteDocuments to print output
    private static void RunQueries(SearchClient srchclient)
    {
        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 = srchclient.Search<Hotel>("*", options);
        WriteDocuments(response);
    
  3. I den andra frågan söker du efter en term, lägger till ett filter som väljer dokument där Omdöme är större än 4 och sorterar sedan efter Klassificering i fallande ordning. Filter är ett booleskt uttryck som utvärderas över IsFilterable-fält i ett index. Filtrera frågor antingen inkludera eller exkludera värden. Därför finns det ingen relevanspoäng associerad med en filterfråga.

    // 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 = srchclient.Search<Hotel>("hotels", options);
    WriteDocuments(response);
    
  4. Den tredje frågan visar sökfält, som används för att begränsa en fulltextsökningsåtgärd till specifika fält.

    // 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 = srchclient.Search<Hotel>("pool", options);
    WriteDocuments(response);
    
  5. Den fjärde frågan visar fasetter som kan användas för att strukturera en fasetterad navigeringsstruktur.

     // 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 = srchclient.Search<Hotel>("*", options);
     WriteDocuments(response);
    
  6. I den femte frågan returnerar du ett specifikt dokument. Ett dokumentuppslag är ett typiskt svar på OnClick-händelsen i en resultatuppsättning.

     // Query 5
     Console.WriteLine("Query #5: Look up a specific document...\n");
    
     Response<Hotel> lookupResponse;
     lookupResponse = srchclient.GetDocument<Hotel>("3");
    
     Console.WriteLine(lookupResponse.Value.HotelId);
    
  7. Den sista frågan visar syntaxen för automatisk komplettering och simulerar en partiell användarinmatning av "sa" som matchar två möjliga matchningar i de sourceFields som är associerade med den förslagsanvändare som du definierade i indexet.

     // Query 6
     Console.WriteLine("Query #6: Call Autocomplete on HotelName that starts with 'sa'...\n");
    
     var autoresponse = srchclient.Autocomplete("sa", "sg");
     WriteDocuments(autoresponse);
    
  8. Lägg till RunQueries i Main().

    // Call the RunQueries method to invoke a series of queries
    Console.WriteLine("Starting queries...\n");
    RunQueries(srchclient);
    
    // End the program
    Console.WriteLine("{0}", "Complete. Press any key to end this program...\n");
    Console.ReadKey();
    

Föregående frågor visar flera sätt att matcha termer i en fråga: fulltextsökning, filter och automatisk komplettering.

Fulltextsökning och -filter utförs med metoden SearchClient.Search . En sökfråga kan skickas i strängensearchText, medan ett filteruttryck kan skickas i filteregenskapen för klassen SearchOptions. Om du vill filtrera utan att söka skickar du "*" bara efter parametern searchTextför sökmetoden . Om du vill söka utan filtrering lämnar du Filter egenskapen oetig eller skickar inte någon SearchOptions instans alls.

Köra programmet

Tryck på F5 för att återskapa appen och köra programmet i sin helhet.

Utdata innehåller meddelanden från Console.WriteLine, med tillägg av frågeinformation och resultat.

Rensa resurser

När du arbetar i din egen prenumeration kan det dock vara klokt att i slutet av ett projekt kontrollera om du fortfarande behöver de resurser som du skapade. Resurser som fortsätter att köras kostar pengar. Du kan ta bort enstaka resurser eller hela resursgruppen om du vill ta bort alla resurser.

Du kan hitta och hantera resurser i portalen med hjälp av länken Alla resurser eller Resursgrupper i det vänstra navigeringsfönstret.

Om du använder en kostnadsfri tjänst ska du komma ihåg att du är begränsad till tre index, indexerare och datakällor. Du kan ta bort enskilda objekt i portalen för att hålla dig under gränsen.

Nästa steg

I den här snabbstarten arbetade du med en uppsättning uppgifter för att skapa ett index, läsa in det med dokument och köra frågor. I olika steg tog vi genvägar för att förenkla koden för läsbarhet och förståelse. Nu när du är bekant med de grundläggande begreppen kan du prova en självstudiekurs som anropar API:erna för Azure AI Search i en webbapp.