Tutorial C# Use conjuntos de habilidades para gerar conteúdo pesquisável na Pesquisa de IA do Azure
Neste tutorial, aprenda como usar o SDK do Azure para .NET para criar um pipeline de enriquecimento de IA para extração de conteúdo e transformações durante a indexação.
Conjuntos de habilidades adicionam processamento de IA ao conteúdo bruto, tornando esse conteúdo mais uniforme e pesquisável. Depois de saber como funcionam os conjuntos de habilidades, você poderá oferecer suporte a uma ampla gama de transformações: desde a análise de imagens ao processamento de linguagem natural, até o processamento personalizado fornecido externamente.
Esse tutorial ajuda você a aprender como:
- Defina objetos em um pipeline de enriquecimento.
- Crie um conjunto de habilidades. Invoque o reconhecimento óptico de caracteres, a detecção de idioma, o reconhecimento de entidade e a extração de frase-chave.
- Execute o pipeline. Crie e carregue um índice de pesquisa.
- Verifique os resultados usando a pesquisa de texto completo.
Caso não tenha uma assinatura do Azure, abra uma conta gratuita antes de começar.
Visão geral
Este tutorial usa C# e a biblioteca de clientes Azure.Search.Documents para criar uma fonte de dados, um índice, um indexador e um conjunto de habilidades.
O indexador orienta cada etapa do pipeline, começando com a extração de conteúdo de dados de exemplo (texto e imagens não estruturados) em um contêiner de blob no Armazenamento do Microsoft Azure.
Depois que o conteúdo é extraído, o conjunto de habilidades executa habilidades integradas da Microsoft para localizar e extrair informações. Essas habilidades incluem OCR (reconhecimento óptico de caracteres) em imagens, detecção de idioma em texto, extração de frases-chave e reconhecimento de entidades (organizações). Novas informações criadas pela qualificação são enviadas para campos em um índice. Depois que o índice for preenchido, você poderá usar os campos em consultas, facetas e filtros.
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.
Baixar arquivos
Baixe um arquivo zip do repositório de dados de exemplo e extraia o conteúdo. Saiba como.
Carregar dados de exemplo para o Armazenamento do Microsoft Azure
No Armazenamento do Microsoft Azure, crie um contêiner e nomeie-o cog-search-demo.
Obtenha uma cadeia de conexão de armazenamento para que você possa formular uma conexão na Pesquisa de IA do Azure.
À esquerda, selecione Teclas de acesso.
Copie a cadeia de conexão para a chave um ou para a chave dois. A cadeia de conexão é semelhante ao seguinte exemplo:
DefaultEndpointsProtocol=https;AccountName=<your account name>;AccountKey=<your account key>;EndpointSuffix=core.windows.net
Serviços de IA do Azure
O enriquecimento interno de IA é apoiado pelos serviços de IA do Azure, incluindo o serviço de linguagem e a Visão de IA do Azure para processamento de imagens e linguagem natural. Para pequenas cargas de trabalho como esse tutorial, você pode usar a alocação gratuita de 20 transações por indexador. Para cargas de trabalho maiores, anexe um recurso de várias regiões dos Serviços de IA do Azure a um conjunto de habilidades para preços de pagamento conforme o uso.
Copiar uma URL do serviço de pesquisa e uma chave de API
Para esse tutorial, as conexões com a Pesquisa de IA do Azure exigem um ponto de extremidade e uma chave de API. Você pode obter esses valores no portal do Azure.
Entre no portal do Azure, navegue até a página Visão geral do serviço de pesquisa e copie a URL. Um ponto de extremidade de exemplo pode parecer com
https://mydemo.search.windows.net
.Em Configurações>Chaves, copie uma chave de administrador. As chaves de administrador são usadas para adicionar, modificar e excluir objetos. Há duas chaves de administrador intercambiáveis. Copie uma delas.
Configure seu ambiente
Comece abrindo o Visual Studio e criando um novo projeto de aplicativo de console que possa ser executado no .NET Core.
Instalar Azure.Search.Documents
O SDK do .NET da IA do Azure Search consiste de uma biblioteca de clientes que permite que você gerencie seus índices, fontes de dados, indexadores e conjuntos de habilidades, carregue e gerencie documentos e execute consultas, sem precisar lidar com os detalhes de HTTP e JSON. Essa biblioteca de clientes é distribuída como um pacote NuGet.
Para este projeto, instale a versão 11 ou posterior do Azure.Search.Documents
e a versão mais recente do Microsoft.Extensions.Configuration
.
No Visual Studio, selecione Ferramentas>Gerenciador de Pacotes NuGet>Gerenciar Pacotes NuGet para a Solução...
Procure por Azure.Search.Document.
Selecione a versão mais recente e selecione Instalar.
Repita as etapas anteriores para instalar Microsoft.Extensions.Configuration e Microsoft.Extensions.Configuration.Json.
Adicionar informações de conexão de serviço
Clique com o botão direito do mouse no projeto no Gerenciador de Soluções e selecione Adicionar>Novo Item... .
Nomeie o arquivo
appsettings.json
e selecione Adicionar.Inclua esse arquivo no diretório de saída.
- Clique com o botão direito do mouse em
appsettings.json
e selecione Propriedades. - Altere o valor de Copiar para Diretório de Saída para Copiar se for o mais recente.
- Clique com o botão direito do mouse em
Copie o JSON abaixo em seu novo arquivo JSON.
{ "SearchServiceUri": "<YourSearchServiceUri>", "SearchServiceAdminApiKey": "<YourSearchServiceAdminApiKey>", "SearchServiceQueryApiKey": "<YourSearchServiceQueryApiKey>", "AzureAIServicesKey": "<YourMultiRegionAzureAIServicesKey>", "AzureBlobConnectionString": "<YourAzureBlobConnectionString>" }
Adicione as informações do seu serviço de pesquisa e da conta de armazenamento de blobs. Lembre-se de que você pode obter essas informações nas etapas de provisionamento do serviço indicadas na seção anterior.
Para SearchServiceUri, insira a URL completa.
Adicionar namespaces
Em Program.cs
, adicione os namespaces a seguir.
using Azure;
using Azure.Search.Documents.Indexes;
using Azure.Search.Documents.Indexes.Models;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
namespace EnrichwithAI
Criar um cliente
Crie uma instância de um SearchIndexClient
e um SearchIndexerClient
em Main
.
public static void Main(string[] args)
{
// Create service client
IConfigurationBuilder builder = new ConfigurationBuilder().AddJsonFile("appsettings.json");
IConfigurationRoot configuration = builder.Build();
string searchServiceUri = configuration["SearchServiceUri"];
string adminApiKey = configuration["SearchServiceAdminApiKey"];
string azureAiServicesKey = configuration["AzureAIServicesKey"];
SearchIndexClient indexClient = new SearchIndexClient(new Uri(searchServiceUri), new AzureKeyCredential(adminApiKey));
SearchIndexerClient indexerClient = new SearchIndexerClient(new Uri(searchServiceUri), new AzureKeyCredential(adminApiKey));
}
Observação
Os clientes se conectam ao serviço de pesquisa. Para evitar abrir um número excessivo de conexões, tente compartilhar uma instância única em seu aplicativo, se possível. Os métodos são thread-safe para habilitar esse compartilhamento.
Adicionar uma função para sair do programa durante uma falha
Este tutorial pretende ajudar você a entender cada etapa do pipeline de indexação. Se houver um problema crítico que impeça o programa de criar a fonte de dados, o conjunto de habilidades, o índice ou o indexador, o programa produzirá a mensagem de erro e será fechado, de modo que o problema possa ser compreendido e resolvido.
Adicione ExitProgram
a Main
para processar cenários que exigem o fechamento do programa.
private static void ExitProgram(string message)
{
Console.WriteLine("{0}", message);
Console.WriteLine("Press any key to exit the program...");
Console.ReadKey();
Environment.Exit(0);
}
Criar o pipeline
Na IA do Azure Search, o processamento de IA ocorre durante a indexação (ou a ingestão de dados). Esta parte do passo a passo cria quatro objetos: fonte de dados, definição de índice, conjunto de habilidades e indexador.
Etapa 1: Criar uma fonte de dados
SearchIndexerClient
tem uma propriedade DataSourceName
que você pode definir para um objeto SearchIndexerDataSourceConnection
. Esse objeto fornece todos os métodos necessários para criar, listar, atualizar ou excluir fontes de dados da IA do Azure Search.
Crie uma nova instância SearchIndexerDataSourceConnection
chamando indexerClient.CreateOrUpdateDataSourceConnection(dataSource)
. O código a seguir cria uma fonte de dados do tipo AzureBlob
.
private static SearchIndexerDataSourceConnection CreateOrUpdateDataSource(SearchIndexerClient indexerClient, IConfigurationRoot configuration)
{
SearchIndexerDataSourceConnection dataSource = new SearchIndexerDataSourceConnection(
name: "demodata",
type: SearchIndexerDataSourceType.AzureBlob,
connectionString: configuration["AzureBlobConnectionString"],
container: new SearchIndexerDataContainer("cog-search-demo"))
{
Description = "Demo files to demonstrate Azure AI Search capabilities."
};
// The data source does not need to be deleted if it was already created
// since we are using the CreateOrUpdate method
try
{
indexerClient.CreateOrUpdateDataSourceConnection(dataSource);
}
catch (Exception ex)
{
Console.WriteLine("Failed to create or update the data source\n Exception message: {0}\n", ex.Message);
ExitProgram("Cannot continue without a data source");
}
return dataSource;
}
Para uma solicitação bem-sucedida, o método retornará a fonte de dados que foi criada. Se houver um problema com a solicitação, como um parâmetro inválido, o método gerará uma exceção.
Agora, adicione uma linha à Main
para chamar a função CreateOrUpdateDataSource
recém-adicionada.
// Create or Update the data source
Console.WriteLine("Creating or updating the data source...");
SearchIndexerDataSourceConnection dataSource = CreateOrUpdateDataSource(indexerClient, configuration);
Compile e execute a solução. Como esta é sua primeira solicitação, verifique o portal do Azure para confirmar a fonte de dados foi criado na IA do Azure Search. Na página de visão geral do serviço de pesquisa, verifique se a lista de Fontes de Dados tem um novo item. Talvez seja necessário aguardar alguns minutos para que a página do portal atualizar.
Etapa 2: Criar um conjunto de habilidades
Nesta seção, você deve definir um conjunto de etapas de enriquecimento que você deseja aplicar aos seus dados. Cada etapa de enriquecimento é chamada de habilidade, e o conjunto de etapas de enriquecimento é um conjunto de habilidades. Este tutorial usa habilidades cognitivas internas do conjunto de habilidades:
A qualificação OCR (Reconhecimento Óptico de Caracteres) reconhece textos impressos e manuscritos em arquivos de imagem.
Fusão de Texto para consolidar o texto de uma coleção de campos em um único campo de "conteúdo mesclado".
A detecção de idioma para identificar o idioma do conteúdo.
Reconhecimento de entidade para extrair os nomes das organizações de conteúdo no contêiner de blobs.
A Divisão de Texto divide o conteúdo grande em partes menores antes de chamar a habilidade de extração de frase-chave e a habilidade de reconhecimento de entidade. A extração de frase-chave e o reconhecimento de entidade aceitam entradas de 50 mil caracteres ou menos. Alguns dos arquivos de exemplo precisam dividir para se ajustar dentro desse limite.
Extração de frase chave para destacar as principais frases-chave.
Durante o processamento inicial, a IA do Azure Search abre os documentos para extrair o conteúdo dos diferentes formatos de arquivo. O texto originário do arquivo de origem é colocado em um campo content
gerado, um para cada documento. Assim, defina a entrada como "/document/content"
para usar esse texto. O conteúdo de imagem é colocado em um campo normalized_images
gerado, especificado em um conjunto de habilidades como /document/normalized_images/*
.
Saídas podem ser mapeadas para um índice usado como entrada para uma habilidade de downstream, ou ambos, como é o caso com o código de idioma. No índice, um código de idioma é útil para filtragem. Como uma entrada, o código de idioma é usado por habilidades de análise de texto para informar as regras linguísticas em torno de quebra de palavras.
Para obter mais informações sobre conceitos básicos do conjunto de qualificações, consulte como definir um conjunto de qualificações.
Habilidade OCR
A OcrSkill
extrai o texto das imagens. Essa habilidade presume que um campo de imagens normalizado existe. Para gerar este campo, mais adiante no tutorial, definiremos a configuração "imageAction"
na definição do indexador para "generateNormalizedImages"
.
private static OcrSkill CreateOcrSkill()
{
List<InputFieldMappingEntry> inputMappings = new List<InputFieldMappingEntry>();
inputMappings.Add(new InputFieldMappingEntry("image")
{
Source = "/document/normalized_images/*"
});
List<OutputFieldMappingEntry> outputMappings = new List<OutputFieldMappingEntry>();
outputMappings.Add(new OutputFieldMappingEntry("text")
{
TargetName = "text"
});
OcrSkill ocrSkill = new OcrSkill(inputMappings, outputMappings)
{
Description = "Extract text (plain and structured) from image",
Context = "/document/normalized_images/*",
DefaultLanguageCode = OcrSkillLanguage.En,
ShouldDetectOrientation = true
};
return ocrSkill;
}
Habilidade de mesclar
Nesta seção, você cria uma MergeSkill
que mescla o campo de conteúdo do documento com o texto produzido pela habilidade do OCR.
private static MergeSkill CreateMergeSkill()
{
List<InputFieldMappingEntry> inputMappings = new List<InputFieldMappingEntry>();
inputMappings.Add(new InputFieldMappingEntry("text")
{
Source = "/document/content"
});
inputMappings.Add(new InputFieldMappingEntry("itemsToInsert")
{
Source = "/document/normalized_images/*/text"
});
inputMappings.Add(new InputFieldMappingEntry("offsets")
{
Source = "/document/normalized_images/*/contentOffset"
});
List<OutputFieldMappingEntry> outputMappings = new List<OutputFieldMappingEntry>();
outputMappings.Add(new OutputFieldMappingEntry("mergedText")
{
TargetName = "merged_text"
});
MergeSkill mergeSkill = new MergeSkill(inputMappings, outputMappings)
{
Description = "Create merged_text which includes all the textual representation of each image inserted at the right location in the content field.",
Context = "/document",
InsertPreTag = " ",
InsertPostTag = " "
};
return mergeSkill;
}
Habilidade de detecção de idioma
A LanguageDetectionSkill
detecta o idioma de texto de entrada e os relatórios de um código de idioma único para cada documento enviado na solicitação. Usaremos a saída da habilidade Detecção de Idioma como parte da entrada para a habilidade Divisão de Texto.
private static LanguageDetectionSkill CreateLanguageDetectionSkill()
{
List<InputFieldMappingEntry> inputMappings = new List<InputFieldMappingEntry>();
inputMappings.Add(new InputFieldMappingEntry("text")
{
Source = "/document/merged_text"
});
List<OutputFieldMappingEntry> outputMappings = new List<OutputFieldMappingEntry>();
outputMappings.Add(new OutputFieldMappingEntry("languageCode")
{
TargetName = "languageCode"
});
LanguageDetectionSkill languageDetectionSkill = new LanguageDetectionSkill(inputMappings, outputMappings)
{
Description = "Detect the language used in the document",
Context = "/document"
};
return languageDetectionSkill;
}
Habilidade de divisão de texto
A SplitSkill
abaixo dividirá o texto por páginas e limitará o tamanho da página a 4 mil caracteres, conforme medido por String.Length
. O algoritmo tentará dividir o texto em blocos com no máximo maximumPageLength
de tamanho. Nesse caso, o algoritmo fará o possível para quebrar a frase em um limite de orações, de modo que o tamanho da parte possa ser um pouco menor que maximumPageLength
.
private static SplitSkill CreateSplitSkill()
{
List<InputFieldMappingEntry> inputMappings = new List<InputFieldMappingEntry>();
inputMappings.Add(new InputFieldMappingEntry("text")
{
Source = "/document/merged_text"
});
inputMappings.Add(new InputFieldMappingEntry("languageCode")
{
Source = "/document/languageCode"
});
List<OutputFieldMappingEntry> outputMappings = new List<OutputFieldMappingEntry>();
outputMappings.Add(new OutputFieldMappingEntry("textItems")
{
TargetName = "pages",
});
SplitSkill splitSkill = new SplitSkill(inputMappings, outputMappings)
{
Description = "Split content into pages",
Context = "/document",
TextSplitMode = TextSplitMode.Pages,
MaximumPageLength = 4000,
DefaultLanguageCode = SplitSkillLanguage.En
};
return splitSkill;
}
Habilidade de reconhecimento de entidade
Esta instância EntityRecognitionSkill
está configurada para reconhecer o tipo de categoria organization
. A EntityRecognitionSkill
também pode reconhecer os tipos de categoria person
e location
.
Observe que o campo "context" está definido como "/document/pages/*"
com um asterisco, o que significa que a etapa de enriquecimento é chamada para cada página em "/document/pages"
.
private static EntityRecognitionSkill CreateEntityRecognitionSkill()
{
List<InputFieldMappingEntry> inputMappings = new List<InputFieldMappingEntry>();
inputMappings.Add(new InputFieldMappingEntry("text")
{
Source = "/document/pages/*"
});
List<OutputFieldMappingEntry> outputMappings = new List<OutputFieldMappingEntry>();
outputMappings.Add(new OutputFieldMappingEntry("organizations")
{
TargetName = "organizations"
});
EntityRecognitionSkill entityRecognitionSkill = new EntityRecognitionSkill(inputMappings, outputMappings)
{
Description = "Recognize organizations",
Context = "/document/pages/*",
DefaultLanguageCode = EntityRecognitionSkillLanguage.En
};
entityRecognitionSkill.Categories.Add(EntityCategory.Organization);
return entityRecognitionSkill;
}
Habilidade de extração de frase-chave
Como a instância EntityRecognitionSkill
que acabou de ser criada, a habilidade KeyPhraseExtractionSkill
é chamada para cada página do documento.
private static KeyPhraseExtractionSkill CreateKeyPhraseExtractionSkill()
{
List<InputFieldMappingEntry> inputMappings = new List<InputFieldMappingEntry>();
inputMappings.Add(new InputFieldMappingEntry("text")
{
Source = "/document/pages/*"
});
inputMappings.Add(new InputFieldMappingEntry("languageCode")
{
Source = "/document/languageCode"
});
List<OutputFieldMappingEntry> outputMappings = new List<OutputFieldMappingEntry>();
outputMappings.Add(new OutputFieldMappingEntry("keyPhrases")
{
TargetName = "keyPhrases"
});
KeyPhraseExtractionSkill keyPhraseExtractionSkill = new KeyPhraseExtractionSkill(inputMappings, outputMappings)
{
Description = "Extract the key phrases",
Context = "/document/pages/*",
DefaultLanguageCode = KeyPhraseExtractionSkillLanguage.En
};
return keyPhraseExtractionSkill;
}
Construir e criar o conjunto de habilidades
Construa o SearchIndexerSkillset
usando as habilidades que você criou.
private static SearchIndexerSkillset CreateOrUpdateDemoSkillSet(SearchIndexerClient indexerClient, IList<SearchIndexerSkill> skills,string azureAiServicesKey)
{
SearchIndexerSkillset skillset = new SearchIndexerSkillset("demoskillset", skills)
{
// Azure AI services was formerly known as Cognitive Services.
// The APIs still use the old name, so we need to create a CognitiveServicesAccountKey object.
Description = "Demo skillset",
CognitiveServicesAccount = new CognitiveServicesAccountKey(azureAiServicesKey)
};
// Create the skillset in your search service.
// The skillset does not need to be deleted if it was already created
// since we are using the CreateOrUpdate method
try
{
indexerClient.CreateOrUpdateSkillset(skillset);
}
catch (RequestFailedException ex)
{
Console.WriteLine("Failed to create the skillset\n Exception message: {0}\n", ex.Message);
ExitProgram("Cannot continue without a skillset");
}
return skillset;
}
Adicione as linhas a seguir a Main
.
// Create the skills
Console.WriteLine("Creating the skills...");
OcrSkill ocrSkill = CreateOcrSkill();
MergeSkill mergeSkill = CreateMergeSkill();
EntityRecognitionSkill entityRecognitionSkill = CreateEntityRecognitionSkill();
LanguageDetectionSkill languageDetectionSkill = CreateLanguageDetectionSkill();
SplitSkill splitSkill = CreateSplitSkill();
KeyPhraseExtractionSkill keyPhraseExtractionSkill = CreateKeyPhraseExtractionSkill();
// Create the skillset
Console.WriteLine("Creating or updating the skillset...");
List<SearchIndexerSkill> skills = new List<SearchIndexerSkill>();
skills.Add(ocrSkill);
skills.Add(mergeSkill);
skills.Add(languageDetectionSkill);
skills.Add(splitSkill);
skills.Add(entityRecognitionSkill);
skills.Add(keyPhraseExtractionSkill);
SearchIndexerSkillset skillset = CreateOrUpdateDemoSkillSet(indexerClient, skills, azureAiServicesKey);
Etapa 3: Crie um índice
Nesta seção, você define o esquema de índice especificando quais campos serão incluídos no índice de pesquisa e os atributos de pesquisa para cada campo. Campos têm um tipo e podem levar a atributos que determinam como o campo é usado (pesquisável, classificável e assim por diante). Nomes de campos em um índice não são necessários para corresponder de modo idêntico aos nomes de campos na fonte. Em uma etapa posterior, você deve adicionar mapeamentos de campo em um indexador para conectar-se campos de origem-destino. Nesta etapa, defina o índice usando as convenções de nomenclatura de campo relevantes para o aplicativo de pesquisa.
Este exercício usa os seguintes campos e tipos de campo:
Nomes de campo | Tipos de campo |
---|---|
id |
Edm.String |
content |
Edm.String |
languageCode |
Edm.String |
keyPhrases |
List<Edm.String> |
organizations |
List<Edm.String> |
Criar classe DemoIndex
Os campos para este índice são definidos usando uma classe de modelo. Cada propriedade da classe de modelo tem atributos que determinam os comportamentos relacionados à pesquisa do campo de índice correspondente.
Vamos adicionar a classe de modelo a um novo arquivo C#. Clique com o botão direito do mouse em seu projeto e selecione Adicionar>Novo Item..., selecione "Classe" e nomeie o arquivo DemoIndex.cs
, depois selecione Adicionar.
Certifique-se de indicar que você deseja usar os tipos dos namespaces Azure.Search.Documents.Indexes
e System.Text.Json.Serialization
.
Adicione a definição de classe de modelo abaixo a DemoIndex.cs
e inclua-a no mesmo namespace onde você criará o índice.
using Azure.Search.Documents.Indexes;
using System.Text.Json.Serialization;
namespace EnrichwithAI
{
// The SerializePropertyNamesAsCamelCase is currently unsupported as of this writing.
// Replace it with JsonPropertyName
public class DemoIndex
{
[SearchableField(IsSortable = true, IsKey = true)]
[JsonPropertyName("id")]
public string Id { get; set; }
[SearchableField]
[JsonPropertyName("content")]
public string Content { get; set; }
[SearchableField]
[JsonPropertyName("languageCode")]
public string LanguageCode { get; set; }
[SearchableField]
[JsonPropertyName("keyPhrases")]
public string[] KeyPhrases { get; set; }
[SearchableField]
[JsonPropertyName("organizations")]
public string[] Organizations { get; set; }
}
}
Agora que você definiu uma classe de modelo, em Program.cs
você pode criar uma definição de índice com bastante facilidade. O nome desse índice será demoindex
. Se já existir um índice com esse nome, ele será excluído.
private static SearchIndex CreateDemoIndex(SearchIndexClient indexClient)
{
FieldBuilder builder = new FieldBuilder();
var index = new SearchIndex("demoindex")
{
Fields = builder.Build(typeof(DemoIndex))
};
try
{
indexClient.GetIndex(index.Name);
indexClient.DeleteIndex(index.Name);
}
catch (RequestFailedException ex) when (ex.Status == 404)
{
//if the specified index not exist, 404 will be thrown.
}
try
{
indexClient.CreateIndex(index);
}
catch (RequestFailedException ex)
{
Console.WriteLine("Failed to create the index\n Exception message: {0}\n", ex.Message);
ExitProgram("Cannot continue without an index");
}
return index;
}
Durante os testes, você poderá constatar que está tentando criar o índice mais de uma vez. Por isso, verifique se o índice que você está prestes a criar já existe antes de tentar criá-lo.
Adicione as linhas a seguir a Main
.
// Create the index
Console.WriteLine("Creating the index...");
SearchIndex demoIndex = CreateDemoIndex(indexClient);
Adicione a instrução using a seguir para resolver a referência de desambiguação.
using Index = Azure.Search.Documents.Indexes.Models;
Para saber mais sobre os conceitos de índice, confira Criar índice (API REST).
Etapa 4: Criar e executar um indexador
Até agora, você criou uma fonte de dados, um conjunto de qualificações e um índice. Esses três componentes se tornam parte de um indexador que reúne cada item em uma única operação de várias fases. Para unir esses em um indexador, você deve definir mapeamentos de campo.
Os fieldMappings são processados antes do conjunto de habilidades, mapeando campos de origem da fonte de dados para campos de destino em um índice. Se os tipos e os nomes do campo forem os mesmos em ambas as extremidades, nenhum mapeamento será necessário.
Os outputFieldMappings são processados depois do conjunto de habilidades, fazendo referência a sourceFieldNames que não existem até a decodificação de documentos ou até que o enriquecimento os crie. O targetFieldName é um campo em um índice.
Além de conectar entradas a saídas, você também pode usar mapeamentos de campo para mesclar estruturas de dados. Para obter mais informações, consulte Como mapear campos enriquecidos para um índice pesquisável.
private static SearchIndexer CreateDemoIndexer(SearchIndexerClient indexerClient, SearchIndexerDataSourceConnection dataSource, SearchIndexerSkillset skillSet, SearchIndex index)
{
IndexingParameters indexingParameters = new IndexingParameters()
{
MaxFailedItems = -1,
MaxFailedItemsPerBatch = -1,
};
indexingParameters.Configuration.Add("dataToExtract", "contentAndMetadata");
indexingParameters.Configuration.Add("imageAction", "generateNormalizedImages");
SearchIndexer indexer = new SearchIndexer("demoindexer", dataSource.Name, index.Name)
{
Description = "Demo Indexer",
SkillsetName = skillSet.Name,
Parameters = indexingParameters
};
FieldMappingFunction mappingFunction = new FieldMappingFunction("base64Encode");
mappingFunction.Parameters.Add("useHttpServerUtilityUrlTokenEncode", true);
indexer.FieldMappings.Add(new FieldMapping("metadata_storage_path")
{
TargetFieldName = "id",
MappingFunction = mappingFunction
});
indexer.FieldMappings.Add(new FieldMapping("content")
{
TargetFieldName = "content"
});
indexer.OutputFieldMappings.Add(new FieldMapping("/document/pages/*/organizations/*")
{
TargetFieldName = "organizations"
});
indexer.OutputFieldMappings.Add(new FieldMapping("/document/pages/*/keyPhrases/*")
{
TargetFieldName = "keyPhrases"
});
indexer.OutputFieldMappings.Add(new FieldMapping("/document/languageCode")
{
TargetFieldName = "languageCode"
});
try
{
indexerClient.GetIndexer(indexer.Name);
indexerClient.DeleteIndexer(indexer.Name);
}
catch (RequestFailedException ex) when (ex.Status == 404)
{
//if the specified indexer not exist, 404 will be thrown.
}
try
{
indexerClient.CreateIndexer(indexer);
}
catch (RequestFailedException ex)
{
Console.WriteLine("Failed to create the indexer\n Exception message: {0}\n", ex.Message);
ExitProgram("Cannot continue without creating an indexer");
}
return indexer;
}
Adicione as linhas a seguir a Main
.
// Create the indexer, map fields, and execute transformations
Console.WriteLine("Creating the indexer and executing the pipeline...");
SearchIndexer demoIndexer = CreateDemoIndexer(indexerClient, dataSource, skillset, demoIndex);
Espere que o processamento do indexador leve algum tempo para ser concluído. Embora o conjunto de dados é pequeno, capacidades analíticas são intensivas na computação. Algumas técnicas, como a análise de imagem, são demoradas.
Dica
Criar um indexador invoca o pipeline. Se houver problemas ao acessar os dados, as entradas de mapeamento e saídas ou ordem de operações, eles aparecem neste estágio.
Explorar a criação do indexador
O código define "maxFailedItems"
como -1, que instrui o mecanismo de indexação para ignorar erros durante a importação de dados. Isso é útil porque há portanto alguns documentos na fonte de dados de demonstração. Para uma fonte de dados maior, você definirá o valor maior que 0.
Observe também que "dataToExtract"
está definido como "contentAndMetadata"
. Essa instrução informa o indexador para extrair automaticamente o conteúdo de diferentes formatos de arquivo, como também os metadados relacionados a cada arquivo.
Quando o conteúdo é extraído, você pode definir imageAction
para extrair o texto da imagem foi encontrada na fonte de dados. A configuração "imageAction"
definida como "generateNormalizedImages"
, combinada com a habilidade de OCR e a habilidade de Mesclagem de Texto, instrui o indexador a extrair o texto das imagens (por exemplo, a palavra "pare" de uma placa de trânsito "Pare") e inseri-la como parte do campo de conteúdo. Esse comportamento se aplica a ambas as imagens inseridas nos documentos (imagine uma imagem dentro de um PDF), bem como imagens encontradas na fonte de dados, por exemplo um arquivo JPG.
Monitorar a indexação
Depois que o indexador for definido, ele é executado automaticamente quando você enviar a solicitação. Dependendo de quais habilidades cognitivas você definiu, a indexação pode demorar mais do que o esperado. Para descobrir se o indexador ainda está em execução, use o método GetStatus
.
private static void CheckIndexerOverallStatus(SearchIndexerClient indexerClient, SearchIndexer indexer)
{
try
{
var demoIndexerExecutionInfo = indexerClient.GetIndexerStatus(indexer.Name);
switch (demoIndexerExecutionInfo.Value.Status)
{
case IndexerStatus.Error:
ExitProgram("Indexer has error status. Check the Azure Portal to further understand the error.");
break;
case IndexerStatus.Running:
Console.WriteLine("Indexer is running");
break;
case IndexerStatus.Unknown:
Console.WriteLine("Indexer status is unknown");
break;
default:
Console.WriteLine("No indexer information");
break;
}
}
catch (RequestFailedException ex)
{
Console.WriteLine("Failed to get indexer overall status\n Exception message: {0}\n", ex.Message);
}
}
demoIndexerExecutionInfo
representa o status atual e o histórico de execução de um indexador.
Os avisos são comuns com algumas combinações de arquivo de origem e habilidade e nem sempre indicam um problema. Neste tutorial, os avisos são benignos (por exemplo, nenhuma entrada de texto dos arquivos JPEG).
Adicione as linhas a seguir a Main
.
// Check indexer overall status
Console.WriteLine("Check the indexer overall status...");
CheckIndexerOverallStatus(indexerClient, demoIndexer);
Search
Nos aplicativos de console do tutorial da IA do Azure Search, normalmente adicionamos um atraso de 2 segundos antes de executarmos consultas que retornam resultados, mas como o enriquecimento leva vários minutos para ser concluído, fecharemos o aplicativo de console e usaremos outra abordagem.
A opção mais fácil é o Gerenciador de pesquisa no portal. Você pode executar primeiro uma consulta vazia que retorna todos os documentos ou uma pesquisa mais direcionada que retorna o conteúdo de campo criado pelo pipeline.
No portal do Azure, na página de Visão geral da pesquisa, selecione Índices.
Localize
demoindex
na lista. Ele deve ter 14 documentos. Quando a contagem de documentos é zero, o indexador ainda está em execução ou a página ainda não foi atualizada.Selecione
demoindex
. O Gerenciador de pesquisa é a primeira guia.O conteúdo fica pesquisável assim que o primeiro documento é carregado. Para verificar se o conteúdo existe, execute uma consulta não especificada clicando em Pesquisar. Essa consulta retorna todos os documentos indexados atualmente, dando a você uma ideia do que o índice contém.
Em seguida, cole a seguinte cadeia de caracteres para obter resultados mais gerenciáveis:
search=*&$select=id, languageCode, organizations
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 deste tutorial verifica se há objetos existentes e os exclui, de modo que você possa executar novamente o código. Use também o portal para excluir índices, indexadores, fontes de dados e conjuntos de habilidades.
Observações
Este tutorial demonstrou as etapas básicas para a criação de um pipeline de indexação enriquecido durante a criação de partes dos componentes: uma fonte de dados, o conjunto de qualificações, o índice e o indexador.
Habilidades internas foram introduzidas, junto com a definição de conjunto de qualificações e a mecânica de encadear habilidades por meio de entradas e saídas. Você também aprendeu que outputFieldMappings
na definição do indexador é necessário para rotear valores enriquecidos do pipeline para um índice pesquisável em um serviço da IA do Azure Search.
Por fim, você aprendeu como resultados de teste e reinicie o sistema para obter mais iterações. Você aprendeu que emitir consultas em relação ao índice retorna a saída criada pelo pipeline de indexação enriquecido. Você também aprendeu como verificar o status do indexador e quais objetos a serem excluídos antes de executar novamente um pipeline.
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. Você pode excluir os recursos individualmente ou excluir o grupo de recursos para excluir todo o conjunto de recursos.
Você pode localizar e gerenciar recursos no portal 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 todos os objetos de um pipeline de enriquecimento de IA, vamos examinar mais de perto as definições de conjunto de habilidades e as habilidades individuais.