Compartilhar via


Tutorial: Indexar de várias fontes de dados usando o SDK do .NET

O Azure AI Search pode importar, analisar e indexar dados de várias fontes de dados em um único índice de pesquisa consolidado.

Este tutorial em C# usa a biblioteca de clientes Azure.Search.Documents no SDK do Azure para .NET para indexar dados de hotel de exemplo de uma instância do Azure Cosmos DB e mescla isso com os detalhes do quarto de hotel extraídos de documentos do Armazenamento de Blobs do Azure. O resultado é um índice combinado de pesquisa de hotéis que contém documentos de hotel, com quartos como tipos de dados complexos.

Neste tutorial, você executará as seguintes tarefas:

  • Fazer upload de dados de exemplo e criar fontes de dados
  • Identificar a chave de documento
  • Definir e criar o índice
  • Indexar dados de hotéis do Azure Cosmos DB
  • Mesclar dados de quartos de hotel do Armazenamento de Blobs

Se você não tiver uma assinatura do Azure, crie uma conta gratuita antes de começar.

Visão geral

Este tutorial usará Azure.Search.Documents para criar e executar vários indexadores. Neste tutorial, você configurará duas fontes de dados do Azure para que seja possível configurar um indexador que efetuará pull de ambas para preencher um índice de pesquisa. Os dois conjuntos de dados deverão ter um valor em comum para serem compatíveis com a mesclagem. Neste exemplo, esse campo será uma ID. Contanto que haja um campo em comum para ser compatível com o mapeamento, um indexador poderá mesclar dados de recursos diferentes: dados estruturados do SQL do Azure, dados não estruturados do Armazenamento de Blobs ou qualquer combinação de fontes de dados compatíveis com o Azure.

Uma versão concluída do código neste tutorial pode ser encontrada no seguinte projeto:

Pré-requisitos

Observação

Você pode usar um serviço de pesquisa gratuito para este tutorial. A camada gratuita limita você a três índices, três indexadores e três fontes de dados. Este tutorial cria um de cada. Antes de começar, reserve um espaço no seu serviço para aceitar os novos recursos.

1 – Criar serviços

Este tutorial usa o Azure AI Search para indexação e consultas, o Azure Cosmos DB para um conjunto de dados e o Armazenamento de Blobs do Azure para o segundo conjunto de dados.

Se possível, crie todos os serviços na mesma região e no mesmo grupo de recursos para facilitar a proximidade e a capacidade de gerenciamento. Na prática, os serviços podem estar em qualquer região.

Esta amostra usa dois conjuntos de dados pequenos que descrevem sete hotéis fictícios. Um conjunto descreve os hotéis em si e será carregado em um banco de dados do Azure Cosmos DB. O outro conjunto contém detalhes de quartos de hotel e é fornecido como sete arquivos JSON separados a serem carregados no Armazenamento de Blobs do Azure.

Iniciar com o Azure Cosmos DB

  1. Entre no portal do Azure e, em seguida, navegue até a página Visão Geral da sua conta do Azure Cosmos DB.

  2. Selecione Data Explorer e, em seguida, selecione Novo Banco de Dados.

    Criar um banco de dados

  3. Insira o nome hotel-rooms-db. Aceite os valores padrão para as configurações restantes.

    Configurar o banco de dados

  4. Criar um novo contêiner. Use o banco de dados existente recém-criado. Insira hotels como o nome do contêiner e use /HotelId como a chave de partição.

    Adicionar contêiner

  5. Selecione Itens em hotels e, em seguida, selecione Carregar Item na barra de comandos. Navegue até o arquivo cosmosdb/HotelsDataSubset_CosmosDb.json e selecione-o na pasta do projeto.

    Carregar na coleção do Azure Cosmos DB

  6. Use o botão Atualizar para atualizar a exibição dos itens na coleção de hotéis. Você deverá ver sete novos documentos de banco de dados listados.

  7. Copie uma cadeia de conexão da página Chaves no Bloco de notas. Você precisará desse valor para usar o appsettings.json em uma etapa posterior. Caso não use o nome do banco de dados sugerido, "hotel-rooms-db", copie o nome do banco de dados também.

Armazenamento do Blobs do Azure

  1. Entre no portal do Azure, navegue até a sua conta de armazenamento do Azure, selecione Blobs e, em seguida, + Contêiner.

  2. Crie um contêiner de blob chamado hotel-rooms para armazenar os arquivos JSON de quartos de hotel de exemplo. Você pode definir o Nível de Acesso Público para qualquer um de seus valores válidos.

    Crie um contêiner de blob

  3. Depois que o contêiner for criado, abra-o e selecione Carregar na barra de comandos. Navegue até a pasta que contém os arquivos de exemplo. Selecione todos eles e, em seguida, selecione Carregar.

    Carregar arquivos

  4. Copie o nome da conta de armazenamento e uma cadeia de conexão da página Chaves de Acesso no Bloco de notas. Você precisará dos dois valores para usar o appsettings.json em uma etapa posterior.

O terceiro componente é a Pesquisa de IA do Azure, que você pode criar no portal do Azure ou encontrar um serviço de pesquisa existente nos recursos do Azure.

Para se autenticar no serviço de pesquisa, você precisará obter uma URL do serviço e uma chave de acesso.

  1. Entre no portal do Azure e, na página Visão geral do serviço de pesquisa, obtenha a URL. Um ponto de extremidade de exemplo pode parecer com https://mydemo.search.windows.net.

  2. Em Configurações>Chaves, obtenha uma chave de administração para adquirir todos os direitos sobre o serviço. Há duas chaves de administração intercambiáveis, fornecidas para a continuidade dos negócios, caso seja necessário sobrepor uma. É possível usar a chave primária ou secundária em solicitações para adicionar, modificar e excluir objetos.

    Obter o nome do serviço e as chaves de consulta e de administrador

Ter uma chave válida estabelece a relação de confiança, para cada solicitação, entre o aplicativo que envia a solicitação e o serviço que lida com ela.

2 – Configurar o ambiente

  1. Inicie o Visual Studio e, no menu Ferramentas, selecione Gerenciador de Pacotes NuGet e clique em Gerenciar Pacotes NuGet para a Solução... .

  2. Na guia Procurar, localize e instale o Azure.Search.Documents (versão 11.0 ou posterior).

  3. Pesquise os pacotes NuGet Microsoft.Extensions.Configuration e Microsoft.Extensions.Configuration.Json e instale-os também.

  4. Abra o arquivo de solução /v11/AzureSearchMultipleDataSources.sln.

  5. No Gerenciador de Soluções, edite o arquivo appsettings.json para adicionar informações de conexão.

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

As duas primeiras entradas serão a URL e as chaves de administrador de um serviço de pesquisa. Use um ponto de extremidade completo, por exemplo: https://mydemo.search.windows.net.

As próximas entradas especificam os nomes de conta e as informações de cadeia de conexão do Armazenamento de Blobs do Azure, bem como as fontes de dados do Azure Cosmos DB.

3 – Mapear campos de chave

A mesclagem de conteúdo exige que ambos os fluxos de dados sejam direcionados para os mesmos documentos no índice de pesquisa.

No Azure AI Search, o campo de chave identifica exclusivamente cada documento. Cada índice de pesquisa deve ter exatamente um campo de chave do tipo Edm.String. Esse campo de chave precisa estar presente para cada documento em uma fonte de dados que é adicionada ao índice. (Na verdade, ele é o único campo obrigatório.)

Ao indexar dados de várias fontes de dados, verifique se cada linha ou documento de entrada contém uma chave de documento comum para mesclar dados de dois documentos de origem fisicamente distintos em um novo documento de pesquisa no índice combinado.

Isso geralmente exige algum planejamento inicial para identificar uma chave de documento significativa para o índice e verificar se ela existe nas duas fontes de dados. Nesta demonstração, a chave HotelId de cada hotel no Azure Cosmos DB também está presente nos blobs JSON de quartos no Armazenamento de Blobs.

Os indexadores do Azure AI Search podem usar mapeamentos de campo para renomear e, até mesmo, reformatar os campos de dados durante o processo de indexação, de modo que os dados de origem possam ser direcionados para o campo de índice correto. Por exemplo, no Azure Cosmos DB, o identificador de hotel é chamado HotelId. Mas, nos arquivos de blob JSON dos quartos de hotel, o identificador de hotel é chamado Id. O programa lidará com essa discrepância mapeando o campo Id dos blobs para o campo-chave HotelId do indexador.

Observação

Na maioria dos casos, as chaves de documento geradas automaticamente, como aquelas criadas por padrão por alguns indexadores, não servem como chaves de documento úteis para índices combinados. Em geral, o recomendável é usar um valor de chave significativo e exclusivo que já exista nas fontes de dados ou que possa ser adicionado a elas com facilidade.

4 – Explorar o código

Depois que os dados e os parâmetros de configuração estiverem em vigor, o programa de exemplo deverá estar pronto para ser criado e executado em /v11/AzureSearchMultipleDataSources.sln.

Este aplicativo de console C#/.NET simples realiza as seguintes tarefas:

  • Cria um índice baseado na estrutura de dados da classe Hotel C# (que também referencia as classes Address e Room).
  • Cria uma fonte de dados e um indexador que mapeia os dados do Azure Cosmos DB para os campos do índice. Ambos são objetos no Azure AI Search.
  • Executa o indexador para carregar os dados de Hotel do Azure Cosmos DB.
  • Cria uma segunda fonte de dados e um indexador que mapeia dados de blob JSON para os campos do índice.
  • Executa o segundo indexador para carregar os dados de Rooms do Armazenamento de Blobs.

Antes de executar o programa, reserve um minuto para estudar o código e as definições de índice e indexador desta amostra. O código relevante encontra-se em dois arquivos:

  • Hotel.cs contém o esquema que define o índice
  • O Program.cs contém funções que criam o índice, as fontes de dados e os indexadores do Azure AI Search e carrega os resultados combinados no índice.

Crie um índice

Este programa de exemplo usa o CreateIndexAsync para definir e criar um índice do Azure AI Search. Ele aproveita a classe FieldBuilder para gerar uma estrutura de índice de uma classe de modelo de dados C#.

O modelo de dados é definido pela classe Hotel, que também contém referências às classes Address e Room. O FieldBuilder faz uma busca detalhada em várias definições de classe para gerar uma estrutura de dados complexa para o índice. As marcas de metadados são usadas para definir os atributos de cada campo, como se ele é pesquisável ou classificável.

O programa excluirá os indexadores existentes com o mesmo nome antes de criar outro, caso você queira executar esse exemplo mais de uma vez.

Os trechos de código a seguir do arquivo Hotel.cs mostrarão campos únicos, seguidos por uma referência a outra classe de modelo de dados, Room[], que por sua vez será definida no arquivo Room.cs (não mostrado).

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

No arquivo Program.cs, o SearchIndex será definido com um nome e uma coleção de campos gerados pelo método FieldBuilder.Build e criado da seguinte maneira:

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

Criar uma fonte de dados e um indexador do Azure Cosmos DB

Em seguida, o programa principal inclui a lógica para criar a fonte de dados do Azure Cosmos DB para os dados de hotéis.

Primeiro, ele concatena o nome do banco de dados do Azure Cosmos DB com a cadeia de conexão. Depois ele definirá um objeto 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);

Depois que a fonte de dados é criada, o programa configura um indexador do Azure Cosmos DB chamado hotel-rooms-cosmos-indexer.

O programa atualizará todos os indexadores existentes com o mesmo nome, além de substituir o indexador existente pelo conteúdo do código acima. Ele também incluirá ações de redefinição e execução, caso você queira executar esse exemplo mais de uma vez.

O exemplo a seguir definirá uma agenda para o indexador com o objetivo de que ele seja executado uma vez por dia. Você poderá remover a propriedade de agendamento desta chamada se não desejar que o indexador seja executado de forma automática novamente no futuro.

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

Este exemplo inclui um bloco simples try-catch para relatar os erros que podem ocorrer durante a execução.

Depois que o indexador do Azure Cosmos DB for executado, o índice de pesquisa conterá um conjunto completo de documentos de hotéis de exemplo. No entanto, o campo Quartos será uma matriz vazia para cada hotel, pois a fonte de dados do Azure Cosmos DB omitirá os detalhes de quartos. Em seguida, o programa efetuará pull do Armazenamento de Blobs para carregar e mesclar os dados de quartos.

Criar uma fonte de dados e um indexador do Armazenamento de Blobs

Para obter detalhes de quartos, o programa primeiro configurará uma fonte de dados do Armazenamento de Blobs para fazer referência a um conjunto de arquivos individuais de blobs 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);

Depois que a fonte de dados for criada, o programa configurará um indexador de blobs chamado hotel-rooms-blob-indexer, conforme mostrado abaixo.

Os blobs JSON contêm um campo de chave chamado Id em vez de HotelId . O código usa a classe FieldMapping para instruir o indexador a direcionar o valor do campo Id para a chave de documento HotelId no índice.

Os indexadores do Armazenamento de Blobs poderão usar o IndexingParameters para especificar um modo de análise. Será necessário definir diferentes modos de análise dependendo das hipóteses em que os blobs representam um documento ou vários documentos dentro do mesmo blob. Neste exemplo, cada blob representará um documento JSON, portanto, o código usará o modo de análise json. Para obter mais informações sobre parâmetros de análise de indexador para blobs JSON, confira Indexar blobs JSON.

Este exemplo define um agendamento para o indexador, de modo que ele seja executado uma vez por dia. Você poderá remover a propriedade de agendamento desta chamada se não desejar que o indexador seja executado de forma automática novamente no futuro.

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

Como o índice já foi populado com os dados de hotéis do banco de dados do Azure Cosmos DB, o indexador de blob atualiza os documentos existentes no índice e adiciona os detalhes de quartos.

Observação

Se você tiver os mesmos campos não chave em ambas as fontes de dados e os dados contidos nesses campos não forem correspondentes, o índice conterá os valores de qualquer indexador executado mais recentemente. Em nosso exemplo, ambas as fontes de dados contêm um campo HotelName. Se, por alguma razão, os dados desse campo forem diferentes, para documentos com o mesmo valor de chave, os dados de HotelName da fonte de dados que foi indexada mais recentemente serão o valor armazenado no índice.

Explore o índice de pesquisa populado após a execução do programa usando o Gerenciador de Pesquisa no portal do Azure.

No portal do Azure, abra a página Visão Geral do serviço de pesquisa e localize o índice hotel-rooms-sample na lista Índices.

Lista de índices do Azure AI Search

Selecione o índice hotel-rooms-sample na lista. Você verá uma interface do Search Explorer para o índice. Insira uma consulta para um termo como "Luxo". Você deverá ver, pelo menos, um documento nos resultados, o qual deverá mostrar uma lista de objetos de quarto em sua matriz de quartos.

Redefinir e execute novamente

Nos primeiros estágios experimentais de desenvolvimento, a abordagem mais prática para iterações de design é excluir os objetos da IA do Azure Search e permitir que seu código os reconstrua. Nomes de recurso são exclusivos. Excluir um objeto permite que você recriá-la usando o mesmo nome.

O código de exemplo verificará os objetos existentes. Além disso, ele excluirá ou atualizará os objetos para que seja possível executar o programa novamente.

Use também o portal do Azure para excluir índices, indexadores e fontes de dados.

Limpar os recursos

Quando você está trabalhando em sua própria assinatura, no final de um projeto, é uma boa ideia remover os recursos que já não são necessários. Recursos deixados em execução podem custar dinheiro. É possível excluir os recursos individualmente ou excluir o grupo de recursos para excluir todo o conjunto de recursos.

Você pode encontrar e gerenciar recursos no portal do Azure usando o link Todos os recursos ou Grupos de recursos no painel de navegação à esquerda.

Próximas etapas

Agora que você está familiarizado com o conceito de ingestão de dados de várias fontes, vamos examinar mais de perto a configuração do indexador, começando com o Azure Cosmos DB.