Поделиться через


Учебник: Индексация данных из нескольких источников с помощью SDK .NET

Поиск ИИ Azure поддерживает импорт, анализ и индексирование данных из нескольких источников данных в единый консолидированный индекс поиска.

В этом руководстве по C# используется клиентская библиотека Azure.Search.Documents в пакете SDK azure для .NET для индексирования примеров данных отеля из экземпляра Azure Cosmos DB. Затем вы объединяете данные с сведениями о номере отеля, полученными из документов хранилища BLOB-объектов Azure. Результатом является объединенный индекс поиска отелей, содержащий документы отелей, в которых номера представлены как сложные типы данных.

Изучив это руководство, вы:

  • отправка примера данных и создание источников данных;
  • Определение ключа документа
  • определение и создание индекса;
  • индексирование данных об отелях из Azure Cosmos DB;
  • Объединение данных по номерам отелей из хранилища Blob

Обзор

В этом руководстве используется Azure.Search.Documents для создания и запуска нескольких индексаторов. В этом руководстве вы настроили два источника данных Azure, чтобы настроить индексатор, извлекаемый из обоих источников для заполнения одного индекса поиска. Для поддержки слияния оба набора данных должны иметь общее значение. В этом примере таким полем является идентификатор. Если есть общее поле для сопоставления, индексатор может объединять данные из различных ресурсов: структурированные данные из Azure SQL, неструктурированные данные из хранилища Blob или любое сочетание поддерживаемых источников данных на Azure.

Готовую версию кода для этого руководства можно найти в следующем проекте:

Предварительные требования

Примечание.

Вы можете использовать бесплатную службу поиска для этого руководства. Уровень "Бесплатный" ограничивается тремя индексами, тремя индексаторами и тремя источниками данных. В этом руководстве создается по одному объекту из каждой категории. Перед началом работы убедитесь, что у службы есть достаточно места, чтобы принять новые ресурсы.

Создание служб

В этом руководстве используется поиск ИИ Azure для индексирования и запросов, Azure Cosmos DB для первого набора данных и хранилища BLOB-объектов Azure для второго набора данных.

Желательно создать все службы в одном регионе и в одной группе ресурсов, чтобы упростить взаимодействие и управление. На практике ваши услуги могут находиться в любом регионе.

В этом примере используется два небольших набора данных, описывающих семь вымышленных отелей. Один набор описывает сами отели и будет загружен в базу данных Azure Cosmos DB. Другой набор содержит сведения о номере отеля и предоставляется в виде семи отдельных JSON-файлов для отправки в хранилище BLOB-объектов Azure.

Начало работы с Azure Cosmos DB

  1. Войдите на портал Azure и перейдите на страницу обзора учетной записи Azure Cosmos DB.

  2. Выберите Обозреватель данных и выберите "Создать базу данных".

    Создание базы данных

  3. Введите имя hotel-rooms-db. Примите значения по умолчанию для остальных параметров.

    Настройка базы данных

  4. Создайте новый контейнер. Используйте ранее созданную базу данных. Введите отели для имени контейнера и используйте /HotelId для ключа секции.

    Добавление контейнера

  5. Выберите "Элементы " в отелях и нажмите кнопку "Отправить элемент " на панели команд. Перейдите к файлу cosmosdb илиHotelsDataSubset_CosmosDb.json в папке проекта.

    Загрузка в коллекцию Azure Cosmos DB

  6. С помощью кнопки "Обновить" обновите отображение элементов в коллекции гостиниц. Вы увидите в списке семь новых документов базы данных.

  7. Скопируйте строку подключения со страницы Ключи в блокнот. Это значение необходимо для appsettings.json на следующем шаге. Если вы не использовали предлагаемое имя базы данных "hotel-rooms-db", скопируйте имя базы данных.

Хранилище BLOB-объектов Azure

  1. Войдите на портал Azure, перейдите к учетной записи хранения Azure, выберите BLOB-объекты и нажмите + Контейнер.

  2. Создайте контейнер больших двоичных объектов с именем hotel-rooms, в котором будут храниться JSON-файлы с примерами данных о номерах отелей. Можно задать любое из допустимых значений уровня общего доступа.

    Создать контейнер Blob

  3. Откройте контейнер после создания и на панели команд выберите Загрузить. Перейдите к папке, содержащей примеры файлов. Выберите все из них и нажмите кнопку "Отправить".

    Отправить файлы

  4. Скопируйте имя учетной записи хранения и строку подключения со страницы «Ключи доступа» в блокнот. Эти значения нужны для appsettings.json на следующем шаге.

Третий компонент — поиск ИИ Azure, который можно создать в портал 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. Найдите и установите пакеты NuGet Microsoft.Extensions.Configuration и Microsoft.Extensions.Json .

  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.

Следующие записи содержат имена учетных записей и строки подключения для хранилища BLOB-объектов Azure и источников данных Azure Cosmos DB.

Ключевые поля карты

Для объединения содержимого требуется, чтобы оба потока данных использовали одни и те же документы в индексе поиска.

В поиске ИИ Azure ключевое поле однозначно идентифицирует каждый документ. Каждый индекс поиска должен содержать только одно поле ключа типа Edm.String. Это поле ключа должно присутствовать в источнике данных для каждого документа, который добавляется к индексу. (Фактически, это единственное обязательное для заполнения поле.)

При индексировании данных из нескольких источников данных убедитесь, что каждая входящая строка или документ содержит общий ключ документа. Это позволяет объединить данные из двух физически разных исходных документов в новый документ поиска в объединенном индексе.

Часто требуется предварительное планирование, чтобы определить значимый ключ документа для вашего индекса и удостовериться, что он присутствует в обоих источниках данных. В этой демонстрации HotelId ключ для каждого отеля в Azure Cosmos DB также присутствует в JSON BLOB-объектах, представляющих комнаты, в хранилище BLOB.

Индексаторы поиска ИИ Azure могут использовать сопоставления полей для переименования и даже переформатирования полей данных во время процесса индексирования, чтобы исходные данные могли быть перенаправлены в правильное поле индекса. Например, в Azure Cosmos DB идентификатор отеля называется HotelId, но в BLOB-файлах JSON для номеров отеля идентификатор отеля называется Id. Программа обрабатывает это несоответствие путем сопоставления Id поля из больших двоичных объектов с HotelId ключевым полем индексатора.

Примечание.

В большинстве случаев автоматически сгенерированные ключи документов, такие как создаваемые по умолчанию некоторыми индексаторами, не подходят в качестве ключей документов для комбинированных индексов. Как правило, используйте понятное, уникальное значение ключа, которое уже существует в источниках данных или можно легко добавить.

Изучение кода

При наличии параметров данных и конфигурации пример программы в /v11/AzureSearchMultipleDataSources.sln должен быть готов к сборке и запуску.

Это простое консольное приложение для C#/.NET выполняет следующие задачи:

  • Создает новый индекс на основе структуры данных класса C# Hotel, который также ссылается на классы Address и Room.
  • создает источник данных и индексатор, который сопоставляет данные в Azure Cosmos DB с полями индекса Это оба объекта в поиске ИИ Azure.
  • Запускает индексатор для загрузки данных отеля из Azure Cosmos DB.
  • Создает второй источник данных и индексатор, который сопоставляет данные JSON-объектов с полями индекса.
  • Запускает второй индексатор для загрузки данных номера отеля из хранилища Blob.

Перед выполнением этой программы, уделите минуту, чтобы изучить ее код и определения индекса и индексатора для этого примера. Соответствующий код находится в двух файлах:

  • Hotel.cs содержит схему, определяющую индекс.
  • Program.cs содержит функции, которые создают индекс поиска Azure AI, источники данных и индексаторы, а также загружают объединенные результаты в индекс.

Создание индекса

В этом примере программы для определения и создания индекса поиска ИИ Azure используется CreateIndexAsync . Она использует класс FieldBuilder для создания структуры индекса из класса модели данных на C#.

Модель данных определяется классом Hotel, который также содержит ссылки на классы Address и Room. 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 для SearchIndex определяется имя и коллекция полей, созданных методом 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);

После создания источника данных программа настраивает индексатор Azure Cosmos DB с именем hotel-rooms-cosmos-indexer.

Программа обновляет все существующие индексаторы с тем же именем, перезаписав существующий индексатор с содержимым предыдущего кода. Она также включает действия сброса и запуска, если вы хотите несколько раз выполнить этот пример.

В следующем примере определяется расписание индексатора, поэтому оно выполняется один раз в день. Вы можете удалить свойство расписания из этого вызова, если вам не нужно, чтобы индексатор автоматически запускался в дальнейшем.

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-файлов с большими двоичными объектами.

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, как показано ниже.

Блобы в формате JSON содержат ключевое поле с именем Id вместо HotelId. В коде используется класс FieldMapping, сообщающий индексатору о необходимости направить значения поля Id в ключ документа HotelId в индексе.

Индексаторы объектов BLOB хранилища могут использовать IndexingParameters для установки режима парсинга. Необходимо задать разные режимы синтаксического анализа в зависимости от того, представляют ли большие двоичные объекты один документ или несколько документов в одном большом двоичном объекте. В нашем примере каждый большой двоичный объект представляет один документ JSON, поэтому в коде используется режим анализа json. Дополнительные сведения о параметрах индексатора для анализа больших двоичных объектов JSON см. в этой статье.

В этом примере определяется расписание индексатора, поэтому оно выполняется один раз в день. Вы можете удалить свойство расписания из вызова функции, если не хотите, чтобы индексатор запускался автоматически в будущем.

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.

На портале перейдите на страницу "Обзор" службы поиска, а затем найдите в списке индексов пример номера отеля.

Список индексов поиска ИИ Azure

Выберите индекс hotel-rooms-sample, чтобы увидеть интерфейс обозревателя поиска для этого индекса. Введите запрос для поиска термина, например Luxury. В результатах поиска вы должны увидеть хотя бы один документ, в котором содержится массив с перечнем объектов комнат.

Сброс и повторный запуск

На ранних экспериментальных этапах разработки наиболее эффективный способ итерации проектирования заключается в удалении объектов из службы "Поиск ИИ Azure", чтобы позволить вашему коду перестроить их. Имена ресурсов уникальны. Удаление объекта позволяет воссоздать его с использованием того же имени.

Пример кода проверяет наличие объектов и удаляет или обновляет их, так чтобы вы могли повторно выполнить программу.

Вы также можете использовать портал Azure для удаления индексов, индексаторов и источников данных.

Очистка ресурсов

При работе с собственной подпиской в конце проекта рекомендуется удалить ресурсы, которые больше не нужны. Оставленные работающими ресурсы могут стоить вам денег. Вы можете удалить ресурсы по отдельности либо удалить всю группу ресурсов.

Ресурсы на портале Azure можно найти и управлять ими, используя ссылку "Все ресурсы" или "Группы ресурсов" в левой области.

Следующий шаг

Теперь, когда вы знакомы с приемом данных из нескольких источников, ознакомьтесь с конфигурацией индексатора, начиная с Azure Cosmos DB: