快速入門:使用 Azure SDK 進行全文搜索

瞭解如何使用 Azure SDK 中的 Azure.Search.Documents 用戶端連結庫,以使用全文搜索的範例數據來建立、載入及查詢搜尋索引。 全文搜索會使用 Apache Lucene 來編制索引和查詢,並使用 BM25 排名演算法來評分結果。

本快速入門提供 下列 SDK 的步驟

必要條件

  • 具有有效訂用帳戶的 Azure 帳戶。 免費建立帳戶

  • Azure AI 搜尋服務。 如果您沒有服務,請建立服務 。 您可以針對本快速入門使用免費層。

  • API 金鑰和服務端點。 登入 Azure 入口網站,然後尋找您的搜尋服務

    在 [概觀] 中,複製 URL 並將其儲存至 記事本 以供後續步驟使用。 範例端點看起來會像是 https://mydemo.search.windows.net

    在 [金鑰] 中,複製並儲存系統管理金鑰,以取得建立和刪除物件的完整許可權。 有兩個可互換的主要和次要密鑰。 選擇其中一個。

    Get an HTTP endpoint and access key

建立、載入和查詢索引

選擇下一個步驟的程式設計語言。 Azure.Search.Documents 用戶端連結庫適用於 .NET、Python、Java 和 JavaScript 的 Azure SDK 中提供。

使用 Azure.Search.Documents 用戶端連結庫建置主控台應用程式,以建立、載入及查詢搜尋索引。 或者,您可以 下載原始程式碼 以從已完成的項目開始,或遵循下列步驟來建立您自己的專案。

設定您的環境

  1. 啟動 Visual Studio 並建立主控台應用程式的新專案。

  2. [工具>NuGet 封裝管理員] 中,選取 [管理解決方案的 NuGet 套件...]。

  3. 選取瀏覽

  4. 搜尋 Azure.Search.Documents 套件 ,然後選取 11.0 版或更新版本。

  5. 選取 右側的 [安裝 ],將元件新增至您的專案和方案。

建立搜尋用戶端

  1. Program.cs 中,將 命名空間變更為 AzureSearch.SDK.Quickstart.v11 ,然後新增下列 using 指示詞。

    using Azure;
    using Azure.Search.Documents;
    using Azure.Search.Documents.Indexes;
    using Azure.Search.Documents.Indexes.Models;
    using Azure.Search.Documents.Models;
    
  2. 建立兩個用戶端:SearchIndexClient 會建立索引,而 SearchClient 會載入和查詢現有的索引。 兩者都需要服務端點和系統管理 API 金鑰,才能使用建立/刪除許可權進行驗證。

    因為程式代碼會為您建置 URI,請在 「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);
         . . . 
     }
    

建立索引

本快速入門會建置使用旅館數據載入的 Hotels 索引,並對其執行查詢。 在此步驟中,定義索引中的欄位。 每個欄位定義都包含名稱、資料類型和屬性,以決定欄位的使用方式。

在此範例中,Azure.Search.Documents 連結庫的同步方法會用於簡單且易讀性。 不過,針對生產案例,您應該使用異步方法來讓您的應用程式保持可調整且回應。 例如,您會使用 CreateIndexAsync而不是 CreateIndex

  1. 將空白類別定義新增至您的專案: Hotel.cs

  2. 將下列程式代碼 複製到 Hotel.cs ,以定義旅館文件的結構。 欄位上的屬性會決定它在應用程式中的使用方式。 例如, IsFilterable 屬性必須指派給支援篩選表達式的每個欄位。

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

    在 Azure.Search.Documents 用戶端連結庫中,您可以使用 SearchableField 和 SimpleField 來簡化欄位定義。 這兩者 都是 SearchField 的衍生專案,而且可能會簡化您的程式代碼:

    • SimpleField 可以是任何數據類型,一律不可搜尋(全文搜索查詢會予以忽略),而且是可擷取的(不會隱藏)。 其他屬性預設為關閉,但可以啟用。 您可以將 用於 SimpleField 文件識別碼或字段,只用於篩選、Facet 或評分配置檔。 如果是,請務必套用案例所需的任何屬性,例如 IsKey = true 文件標識符。 如需詳細資訊,請參閱 原始碼中的SimpleFieldAttribute.cs

    • SearchableField 必須是字串,且一律可搜尋且可擷取。 其他屬性預設為關閉,但可以啟用。 由於此欄位類型是可搜尋的,因此它支援同義字和分析器屬性的完整補充。 如需詳細資訊,請參閱 原始程式碼中的SearchableFieldAttribute.cs

    無論您使用基本 SearchField API 還是其中一個協助程式模型,都必須明確啟用篩選、Facet 和排序屬性。 例如,IsFilterable、IsSortableIsFacetable 必須明確屬性化,如上述範例所示。

  3. 將第二個空白類別定義新增至您的專案: Address.cs。 將下列程式代碼複製到類別。

    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. 再建立兩個類別: Hotel.Methods.cstoString() 覆寫的Address.Methods.cs 。 這些類別可用來在控制台輸出中轉譯搜尋結果。 本文未提供這些類別的內容,但您可以從 GitHub 中的檔案複製程式代碼

  5. Program.cs中,建立 SearchIndex 物件,然後呼叫 CreateIndex 方法來表達搜尋服務中的索引。 索引也包含 SearchSuggester ,以在指定的欄位上啟用自動完成。

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

載入檔

Azure AI 搜尋會搜尋儲存在服務中的內容。 在此步驟中,您將載入符合您剛才建立之旅館索引的 JSON 檔。

在 Azure AI 搜尋服務中,搜尋檔是數據結構,兩者都是索引編製和查詢輸出的輸入。 從外部數據源取得時,檔輸入可能是資料庫中的數據列、Blob 記憶體中的 Blob,或磁碟上的 JSON 檔。 在此範例中,我們會針對程序代碼本身的四家酒店,取得快捷方式並內嵌 JSON 檔。

上傳檔時,您必須使用 IndexDocumentsBatch 物件。 IndexDocumentsBatch物件包含 Actions集合,每個動作都包含文件和屬性,告知 Azure AI 搜尋要執行的動作(上傳、合併、刪除和 mergeOrUpload)。

  1. Program.cs中,建立檔案和索引動作的陣列,然後將陣列傳遞至 IndexDocumentsBatch。 下列檔符合 hotels-quickstart 索引,如旅館類別所定義。

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

    初始化 IndexDocumentsBatch 對象之後,您可以在 SearchClient 物件上呼叫 IndexDocuments,將其傳送至索引。

  2. 將下列幾行新增至Main()。 載入檔是使用 SearchClient 完成,但作業也需要服務的系統管理員許可權,這通常與 SearchIndexClient 相關聯。 設定這項作業的其中一種方式是透過 SearchIndexClient 取得 SearchClient(此範例中的 adminClient)。

     SearchClient ingesterClient = adminClient.GetSearchClient(indexName);
    
     // Load documents
     Console.WriteLine("{0}", "Uploading documents...\n");
     UploadDocuments(ingesterClient);
    
  3. 因為這是依序執行所有命令的控制台應用程式,因此請在索引編製和查詢之間新增 2 秒的等候時間。

    // Wait 2 seconds for indexing to complete before starting queries (for demo and console-app purposes only)
    Console.WriteLine("Waiting for indexing...\n");
    System.Threading.Thread.Sleep(2000);
    

    2 秒的延遲會補償異步的編製索引,以便在執行查詢之前先編製所有檔的索引。 在延遲中撰寫程式代碼通常只有在示範、測試和範例應用程式中才需要。

搜尋索引

您可以在第一份文件編製索引后立即取得查詢結果,但索引的實際測試應該等到所有文件編製索引為止。

本節會新增兩個功能:查詢邏輯和結果。 針對查詢,請使用 Search 方法。 此方法會採用搜尋文字(查詢字串)和其他 選項

SearchResults 類別代表結果。

  1. Program.cs中,建立 WriteDocuments 方法,將搜尋結果列印至控制台。

    // 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. 建立 RunQueries 方法來執行查詢並傳回結果。 結果為 Hotel 物件。 此範例顯示方法簽章和第一個查詢。 此查詢示範 Select 參數,可讓您使用檔中選取的欄位來撰寫結果。

    // 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. 在第二個查詢中,搜尋字詞、新增篩選,以選取評分大於 4 的文件,然後依遞減順序依評分排序。 Filter 是布爾表示式,會透過 索引中的IsFilterable 字段進行評估。 篩選查詢包括或排除值。 因此,沒有與篩選查詢相關聯的相關性分數。

    // 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. 第三個查詢示範 searchFields,用來將全文搜索作業的範圍限定為特定欄位。

    // 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. 第四個查詢示範 Facet,可用來建構多面向導覽結構。

     // 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. 在第五個查詢中,傳回特定檔。 檔查閱是結果集中 OnClick 事件的一般回應。

     // 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. 最後一個查詢會顯示自動完成的語法,模擬 「sa」 的部分使用者輸入,其解析為與索引中定義之建議工具相關聯的 sourceFields 中兩個可能的相符專案。

     // Query 6
     Console.WriteLine("Query #6: Call Autocomplete on HotelName that starts with 'sa'...\n");
    
     var autoresponse = srchclient.Autocomplete("sa", "sg");
     WriteDocuments(autoresponse);
    
  8. 將 RunQueries 新增至 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();
    

先前的查詢會在查詢中顯示多個比對詞彙的方式:全文搜索、篩選和自動完成。

全文搜索和篩選是使用 SearchClient.Search 方法執行。 搜尋查詢可以傳入searchText字串,而篩選表達式則可在 SearchOptions 類別的 Filter 屬性中傳遞。 若要篩選而不搜尋,只要傳遞 "*"searchText Search 方法的 參數即可。 若要搜尋而不篩選,請將 屬性保持 Filter 未設定,或完全不傳入 SearchOptions 實例。

執行程式

按 F5 重建應用程式,並完整執行程式。

輸出包含來自 Console.WriteLine 的訊息,以及新增查詢資訊和結果。

清除資源

如果您是在自己的訂用帳戶中進行,建議您在專案結束時判斷自己是否仍需要先前所建立的資源。 資源若繼續執行,將需付費。 您可以個別刪除資源,或刪除資源群組以刪除整組資源。

您可以使用左側瀏覽窗格中的 [ 所有資源 ] 或 [資源群組 ] 連結,在入口網站中找到和管理資源。

如果您使用免費服務,請記住,您僅限於三個索引、索引器和數據源。 您可以刪除入口網站中的個別專案,以維持在限制之下。

下一步

在本快速入門中,您已完成一組工作來建立索引、使用檔載入索引,以及執行查詢。 在不同的階段,我們採取了快捷方式來簡化程式碼的可讀性和理解性。 現在您已熟悉基本概念,請嘗試在 Web 應用程式中呼叫 Azure AI 搜尋 API 的教學課程。