共用方式為


教學課程:使用 .NET SDK 從多個資料來源編製索引

Azure AI 搜尋服務支援將多個數據源的數據匯入、分析及編製索引到單一合併的搜尋索引。

本 C# 教學課程使用適用於 .NET 的 Azure SDK 中的 Azure.Search.Documents 用戶端連結庫,從 Azure Cosmos DB 實例編製範例旅館數據的索引。 然後,您會將數據與從 Azure Blob 記憶體檔繪製的旅館房間詳細數據合併。 結果是一個綜合的飯店搜尋索引,其中包含飯店文件,以房間作為複雜數據類型。

在本教學課程中,您會:

  • 上傳範例資料並建立資料來源
  • 識別文件索引鍵
  • 定義並建立索引
  • 為來自 Azure Cosmos DB 的旅館資料編製索引
  • 合併來自 Blob 儲存體的旅館房間資料

概觀

本教學課程使用 Azure.Search.Documents 建立及執行多個索引子。 在本教學課程中,您會設定兩個 Azure 數據源,以便設定從兩者提取以填入單一搜尋索引的索引器。 這兩個資料集必須有共同的值以支援合併。 在此範例中,該欄位是識別碼。 只要有一個共同的欄位可支援對應,索引子就可以合併來自不同資源的資料:來自 Azure SQL 的結構化資料、來自 Blob 儲存體的非結構化資料,或 Azure 上支援的資料來源的任意組合。

您可以在下列專案中找到本教學課程中的最終版本程式碼:

必要條件

註記

您可以使用免費搜尋服務進行本教學。 免費層的限制為三個索引、三個索引子、以及三個資料來源。 本教學課程會各建立一個。 開始之前,請確定您的服務有空間可接受新的資源。

建立服務

本教學課程使用 Azure AI Search 來對資料建立索引和查詢,對於第一個數據集使用 Azure Cosmos DB,對於第二個數據集使用 Azure Blob 儲存。

為具備鄰近性和管理方面的優勢,如果可能,請將這些服務全都建立在相同的區域和資源群組中。 在實務上,您的服務可位於任何區域。

此範例使用兩組描述七家虛構旅館的小型數據集。 一組描述旅館本身,並將載入 Azure Cosmos DB 資料庫。 另一個集合包含旅館房間詳細數據,並提供七個不同的 JSON 檔案,以便上傳至 Azure Blob 儲存。

開始使用 Azure Cosmos DB

  1. 登入 Azure 入口網站,然後移至 Azure Cosmos DB 帳戶的 [概 ] 頁面。

  2. 選取 [數據總管],然後選取 [ 新增資料庫]。

    建立新的  資料庫

  3. 輸入名稱 hotel-rooms-db。 接受其餘設定的預設值。

    設定資料庫

  4. 建立新的容器。 使用您先前建立的現有資料庫。 輸入 hotels 作為容器名稱,並將 /HotelId 用作分區索引鍵。

    新增容器

  5. 選取 hotels 底下的 [項目],然後選取命令列上的 [上傳項目]。 導航至並選取項目資料夾中 cosmosdb/HotelsDataSubset_CosmosDb.json 檔案。

    上傳至 Azure Cosmos DB 集合

  6. 使用 [重新整理] 按鈕來重新整理您在旅館集合中的項目檢視。 您應該會看到列出七份新的資料庫文件。

  7. 將 [金鑰] 頁面中的連接字串複製到 [記事本] 中。 在後續步驟中,您必須將此值用於 appsettings.json。 如果您未使用建議的資料庫名稱 "hotel-rooms-db",請一併複製資料庫名稱。

Azure Blob 儲存體

  1. 登入 Azure 入口網站,前往您的 Azure 儲存體帳戶,選取 Blob,然後選取 [+ 容器]

  2. 建立 Blob 容器 (名稱為 hotel-rooms) 來儲存範例旅館房間 JSON 檔案。 您可以將公用存取層級設定為任何有效值。

    建立 Blob 容器

  3. 建立容器之後,請加以開啟,然後選取命令列的 [上傳]。 瀏覽至包含範例檔案的資料夾。 選取所有項目,然後選取 [ 上傳]。

    上傳檔案

  4. 將儲存體帳戶名稱和 [存取金鑰] 頁面中的連接字串複製到 [記事本] 中。 在後續步驟中,您必須將這兩個值用於 appsettings.json

第三個元件是 Azure AI 搜尋,您可以在 Azure 入口網站 中建立,或在 Azure 資源中尋找現有的搜尋服務

若要向搜尋服務進行驗證,您需要服務 URL 和存取密鑰。

  1. 登入 Azure 入口網站

  2. 在搜尋服務的 [ 概觀 ] 頁面上,取得 URL。 範例端點看起來會像是 https://mydemo.search.windows.net

  3. [設定>金鑰] 上,取得服務完整許可權的管理金鑰。 可互換的管理金鑰有兩個,可在您需要變換金鑰時提供商務持續性。 您可以在新增、修改及刪除物件的要求上使用主要或次要金鑰。

在應用程序傳送要求與處理要求的服務之間,持有有效的密鑰可以根據每次要求建立信任。

設定您的環境

  1. 開啟 Visual Studio。

  2. 在 [ 工具] 功能表中,選取 [NuGet 套件管理員],然後選取 [ 管理方案的 NuGet 套件...]。

  3. 在 [ 流覽] 索引標籤上,尋找並安裝 Azure.Search.Documents (11.0 版或更新版本)。

  4. 尋找並安裝 Microsoft.Extensions.ConfigurationMicrosoft.Extensions.Configuration.Json NuGet 套件。

  5. 開啟解決方案檔案 /v11/AzureSearchMultipleDataSources.sln

  6. 在方案總管中編輯 appsettings.json 檔案,以新增連線資訊。

    {
      "SearchServiceUri": "<YourSearchServiceURL>",
      "SearchServiceAdminApiKey": "<YourSearchServiceAdminApiKey>",
      "BlobStorageAccountName": "<YourBlobStorageAccountName>",
      "BlobStorageConnectionString": "<YourBlobStorageConnectionString>",
      "CosmosDBConnectionString": "<YourCosmosDBConnectionString>",
      "CosmosDBDatabaseName": "hotel-rooms-db"
    }
    

前兩個項目是搜尋服務的 URL 和管理金鑰。 使用完整端點。 例如: https://mydemo.search.windows.net

後續項目會指定帳戶名稱,以及 Azure Blob 儲存體和 Azure Cosmos DB 資料來源的連接字串資訊。

對應索引鍵欄位

合併內容時,兩個資料流必須以搜尋索引中的相同文件作為目標。

在 Azure AI 搜尋服務中,索引鍵欄位會唯一識別每份文件。 每個搜尋索引必須確實具有一個 Edm.String類型的索引鍵欄位。 在新增至索引的資料來源中,每份文件都必須有該索引鍵欄位。 (實際上它是唯一必要的欄位。)

從多個數據源編製數據索引時,請確定每個傳入的數據列或檔都包含一般檔索引鍵。 這可讓您將數據從兩個實體相異源檔合併到合併索引中的新搜尋檔。

這通常需要一些事先規劃來找出對您的索引有意義的文件索引鍵,並確定該索引鍵存在於兩個資料來源中。 在此示範中,Azure Cosmos DB 中每家旅館的 HotelId 索引鍵也出現在 Blob 儲存體中的房間 JSON 資料塊中。

Azure AI 搜尋服務索引子可以使用欄位對應來重新命名,甚至可在編製索引過程中將資料欄位重新格式化,如此一來,便可將該來源資料導向至正確的索引欄位。 例如,在 Azure Cosmos DB 中,會呼叫 HotelId旅館標識碼,但在旅館房間的 JSON Blob 檔案中,旅館標識碼會命名為 Id。 程式會藉由將 Blob 的 Id 欄位對應到索引子中的 HotelId 索引鍵欄位,來處理不一致的情況。

附註

在大部分情況下,自動產生的文件索引鍵 (例如,預設由某些索引子建立的索引鍵) 無法為合併的索引建立良好的文件索引鍵。 一般而言,請使用已存在於數據源中或可以輕鬆地新增有意義的唯一索引鍵值。

探索程序代碼

當數據和組態設定就緒時, /v11/AzureSearchMultipleDataSources.sln 中的範例程式應該已準備好建置並執行。

這個簡單的 C#/.NET 主控台應用程式會執行下列工作:

  • 根據 C# Hotel 類別的數據結構建立新的索引,該類別也會參考 Address 和 Room 類別。
  • 建立新的資料來源和索引子,以將 Azure Cosmos DB 資料對應到索引欄位。 這是 Azure AI 搜尋服務中的兩個物件。
  • 執行索引器以從 Azure Cosmos DB 載入旅館數據。
  • 建立第二個資料來源和索引子,以將 JSON Blob 資料對應到索引欄位。
  • 執行第二個索引器,以從 Blob 記憶體載入旅館房間數據。

執行程式之前,請花一分鐘研讀此範例的程式碼及索引和索引子定義。 相關程式碼位於兩個檔案中:

  • Hotel.cs 包含定義索引的架構。
  • Program.cs 包含函式,可用來建立 Azure AI 搜尋服務索引、資料來源和索引子,並將已合併的結果載入至索引。

建立索引

此範例程式會使用 CreateIndexAsync 來定義並建立 Azure AI 搜尋服務索引。 它會利用 FieldBuilder \(英文\) 類別,從 C# 資料模型類別產生索引結構。

資料模型會透過旅館類別來定義,其中也包含對地址和房間類別的參考。 FieldBuilder 會向下鑽研多個類別定義,以針對索引產生複雜的資料結構。 中繼資料標記可用來定義每個欄位的屬性,例如,其是否可搜尋或可排序。

如果想要多次執行此範例,程式會先刪除同名的任何現有索引,再建立新的索引。

下列來自 Hotel.cs 檔案的程式碼片段會顯示單一欄位,後面接著另一個資料模型類別 Room[] 的參考,而該類別會定義於 Room.cs 檔案中 (未顯示)。

. . .
[SimpleField(IsFilterable = true, IsKey = true)]
public string HotelId { get; set; }

[SearchableField(IsFilterable = true, IsSortable = true)]
public string HotelName { get; set; }
. . .
public Room[] Rooms { get; set; }
. . .

Program.cs 檔案中,會使用 方法所產生的名稱和欄位集合來定義 FieldBuilder.Build,然後透過如下方式加以建立:

private static async Task CreateIndexAsync(string indexName, SearchIndexClient indexClient)
{
    // Create a new search index structure that matches the properties of the Hotel class.
    // The Address and Room classes are referenced from the Hotel class. The FieldBuilder
    // will enumerate these to create a complex data structure for the index.
    FieldBuilder builder = new FieldBuilder();
    var definition = new SearchIndex(indexName, builder.Build(typeof(Hotel)));

    await indexClient.CreateIndexAsync(definition);
}

建立 Azure Cosmos DB 資料來源和索引子

主要程式包含邏輯,可建立旅館數據的 Azure Cosmos DB 數據源。

首先,它會將 Azure Cosmos DB 資料庫名稱串連至連接字串。 然後,它會定義 SearchIndexerDataSourceConnection 物件。

private static async Task CreateAndRunCosmosDbIndexerAsync(string indexName, SearchIndexerClient indexerClient)
{
    // Append the database name to the connection string
    string cosmosConnectString =
        configuration["CosmosDBConnectionString"]
        + ";Database="
        + configuration["CosmosDBDatabaseName"];

    SearchIndexerDataSourceConnection cosmosDbDataSource = new SearchIndexerDataSourceConnection(
        name: configuration["CosmosDBDatabaseName"],
        type: SearchIndexerDataSourceType.CosmosDb,
        connectionString: cosmosConnectString,
        container: new SearchIndexerDataContainer("hotels"));

    // The Azure Cosmos DB data source does not need to be deleted if it already exists,
    // but the connection string might need to be updated if it has changed.
    await indexerClient.CreateOrUpdateDataSourceConnectionAsync(cosmosDbDataSource);

建立資料來源之後,程式會設定名為 hotel-rooms-cosmos-indexer 的 Azure Cosmos DB 索引子。

程式會以相同名稱更新任何現有的索引器,並使用先前程式代碼的內容覆寫現有的索引器。 如果您想要多次執行此範例,則也會包含重設和執行動作。

下列範例會定義索引器排程,以便每天執行一次。 如果您未來不想讓索引子再次自動執行,即可從此呼叫中移除排程屬性。

SearchIndexer cosmosDbIndexer = new SearchIndexer(
    name: "hotel-rooms-cosmos-indexer",
    dataSourceName: cosmosDbDataSource.Name,
    targetIndexName: indexName)
{
    Schedule = new IndexingSchedule(TimeSpan.FromDays(1))
};

// Indexers keep metadata about how much they have already indexed.
// If we already ran the indexer, it "remembers" and does not run again.
// To avoid this, reset the indexer if it exists.
try
{
    await indexerClient.GetIndexerAsync(cosmosDbIndexer.Name);
    // Reset the indexer if it exists.
    await indexerClient.ResetIndexerAsync(cosmosDbIndexer.Name);
}
catch (RequestFailedException ex) when (ex.Status == 404)
{
    // If the indexer does not exist, 404 will be thrown.
}

await indexerClient.CreateOrUpdateIndexerAsync(cosmosDbIndexer);

Console.WriteLine("Running Azure Cosmos DB indexer...\n");

try
{
    // Run the indexer.
    await indexerClient.RunIndexerAsync(cosmosDbIndexer.Name);
}
catch (RequestFailedException ex) when (ex.Status == 429)
{
    Console.WriteLine("Failed to run indexer: {0}", ex.Message);
}

此範例包含簡單的 try-catch 區塊,以報告可能在執行期間發生的任何錯誤。

執行 Azure Cosmos DB 索引器之後,搜尋索引會包含一組完整的範例旅館檔。 不過,每個旅館的會議室字段都是空陣列,因為 Azure Cosmos DB 數據源會省略房間詳細數據。 接下來,程式會從 Blob 記憶體提取,以載入和合併會議室數據。

建立 Blob 儲存體資料來源和索引子

為了取得房間詳細資料,程式會先設定 Blob 儲存體資料來源,以參考一組個別的 JSON Blob 檔案。

private static async Task CreateAndRunBlobIndexerAsync(string indexName, SearchIndexerClient indexerClient)
{
    SearchIndexerDataSourceConnection blobDataSource = new SearchIndexerDataSourceConnection(
        name: configuration["BlobStorageAccountName"],
        type: SearchIndexerDataSourceType.AzureBlob,
        connectionString: configuration["BlobStorageConnectionString"],
        container: new SearchIndexerDataContainer("hotel-rooms"));

    // The blob data source does not need to be deleted if it already exists,
    // but the connection string might need to be updated if it has changed.
    await indexerClient.CreateOrUpdateDataSourceConnectionAsync(blobDataSource);

建立資料來源之後,程式會設定名為 hotel-rooms-blob-indexer 的 Blob 索引子,如下所示。

JSON Blob 包含名為 Id (而非 HotelId) 的索引鍵欄位。 程式碼會使用 FieldMapping 類別,來告知索引子要將 Id 欄位值導向至索引中的 HotelId 文件索引鍵。

Blob 儲存體索引子可使用 IndexingParameters 來指定剖析模式。 您應該根據 Blob 是否代表同一個 Blob 內的單一檔或多個檔,來設定不同的剖析模式。 在此範例中,每個 Blob 均代表單一 JSON 文件,因此程式碼會使用 json 剖析模式。 如需用以剖析 JSON Blob 參數的索引子詳細資訊,請參閱為 JSON Blob 編製索引

此範例會定義索引器排程,以便每天執行一次。 如果您未來不想讓索引子再次自動執行,即可從此呼叫中移除排程屬性。

IndexingParameters parameters = new IndexingParameters();
parameters.Configuration.Add("parsingMode", "json");

SearchIndexer blobIndexer = new SearchIndexer(
    name: "hotel-rooms-blob-indexer",
    dataSourceName: blobDataSource.Name,
    targetIndexName: indexName)
{
    Parameters = parameters,
    Schedule = new IndexingSchedule(TimeSpan.FromDays(1))
};

// Map the Id field in the Room documents to the HotelId key field in the index
blobIndexer.FieldMappings.Add(new FieldMapping("Id") { TargetFieldName = "HotelId" });

// Reset the indexer if it already exists
try
{
    await indexerClient.GetIndexerAsync(blobIndexer.Name);
    await indexerClient.ResetIndexerAsync(blobIndexer.Name);
}
catch (RequestFailedException ex) when (ex.Status == 404) { }

await indexerClient.CreateOrUpdateIndexerAsync(blobIndexer);

try
{
    // Run the indexer.
    await searchService.Indexers.RunAsync(blobIndexer.Name);
}
catch (CloudException e) when (e.Response.StatusCode == (HttpStatusCode)429)
{
    Console.WriteLine("Failed to run indexer: {0}", e.Response.Content);
}

因為索引已經填入來自 Azure Cosmos DB 資料庫的旅館數據,因此 Blob 索引器會更新索引中現有的檔,並新增房間詳細數據。

附註

如果您在兩個數據源中具有相同的非索引鍵欄位,而且這些欄位中的數據不相符,索引會包含最近執行之索引器的值。 在此範例中,這兩個資料來源均包含 HotelName 欄位。 如果基於某些原因,此欄位中的數據不同,對於具有相同索引鍵值的檔,來自最近索引數據源的 HotelName 數據是儲存在索引中的值。

執行程式之後,您可以使用 Azure 入口網站中的 搜尋探索器 來探索填入的搜尋索引。

在入口網站中,移至搜尋服務的 [概] 頁面,然後在 [索引] 列表中尋找 hotel-rooms-sample 索引。

Azure AI 搜尋服務索引的清單

選取 hotel-rooms-sample 索引,查看索引的搜尋介面。 輸入像「奢華」這樣的字詞進行查詢。 您應該會在結果中至少看見一份文件,而這份文件應該會在其房間陣列中顯示房間物件的清單。

重設並重新執行

在開發的早期實驗階段中,若要設計反覆項目,最實用的方法是從 Azure AI 搜尋服務中刪除物件,並讓您的程式碼重建這些物件。 資源名稱是唯一的。 刪除物件可讓您使用相同的名稱加以重新建立。

範例程式碼會檢查是否有現有的物件,並將其刪除或更新,以便您重新執行程式。

您也可以使用 Azure 入口網站 來刪除索引、索引器和數據源。

清除資源

當您在自己的訂用帳戶中工作時,在項目結束時,最好移除不再需要的資源。 讓資源繼續執行可能會產生費用。 您可以個別刪除資源,或刪除資源群組以刪除整組資源。

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

後續步驟

既然您已熟悉從多個來源擷取數據,請仔細看看索引器設定,從 Azure Cosmos DB 開始: