Partilhar via


Tutorial: Criar seu primeiro aplicativo de pesquisa na Pesquisa Cognitiva do Azure usando o SDK do .NET

Este tutorial mostra como criar um aplicativo Web que consulta e retorna resultados de um índice de pesquisa usando a Pesquisa Cognitiva do Azure e o Visual Studio.

Neste tutorial, você aprenderá a:

  • Configurar um ambiente de desenvolvimento
  • Modelar estruturas de dados
  • Criar uma página da Web para coletar entradas de consulta e exibir resultados
  • Definir um método de pesquisa
  • Testar a aplicação

Você também aprenderá como é simples uma chamada de pesquisa. As principais instruções no código são encapsuladas nas seguintes linhas:

var options = new SearchOptions()
{
    // The Select option specifies fields for the result set
    options.Select.Add("HotelName");
    options.Select.Add("Description");
};

var searchResult = await _searchClient.SearchAsync<Hotel>(model.searchText, options).ConfigureAwait(false);
model.resultList = searchResult.Value.GetResults().ToList();

Apenas uma chamada consulta o índice de pesquisa e retorna resultados.

Procurando por *pool*

Visão geral

Este tutorial utiliza o hotels-sample-index, que o utilizador pode criar rapidamente no seu próprio serviço de pesquisa ao seguir a introdução rápida de importação de dados Importar dados. O índice contém dados fictícios de hotéis, disponíveis como fonte de dados integrada em todos os serviços de pesquisa.

A primeira lição deste tutorial cria uma estrutura de consulta básica e uma página de pesquisa, que você aprimorará nas lições subsequentes para incluir paginação, facetas e uma experiência de digitação antecipada.

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

Pré-requisitos

Instalar e executar o projeto a partir do GitHub

Se você quiser avançar para um aplicativo de trabalho, siga as etapas abaixo para baixar e executar o código concluído.

  1. Localize o exemplo no GitHub: Criar primeiro aplicativo.

  2. Na pasta raiz, selecione Código, seguido de Clone ou Download ZIP para fazer sua cópia local privada do projeto.

  3. Usando o Visual Studio, navegue até e abra a solução para a página de pesquisa básica ("1-basic-search-page") e selecione Iniciar sem depuração (ou pressione F5) para criar e executar o programa.

  4. Este é um índice de hotéis, portanto, digite algumas palavras que você pode usar para pesquisar hotéis (por exemplo, "wifi", "view", "bar", "estacionamento"). Examine os resultados.

    Procurando por *wifi*

Os componentes essenciais para pesquisas mais sofisticadas estão incluídos neste aplicativo. Se você é novo no desenvolvimento de pesquisa, pode recriar este aplicativo passo a passo para aprender o fluxo de trabalho. As seções a seguir mostram como.

Configurar um ambiente de desenvolvimento

Para criar este projeto do zero e, assim, reforçar os conceitos da Pesquisa Cognitiva do Azure, comece com um projeto do Visual Studio.

  1. No Visual Studio, selecione Novo>Projeto e, em seguida, ASP.NET Core Web App (Model-View-Controller).

    Criando um projeto na nuvem

  2. Dê ao projeto um nome como "FirstSearchApp" e defina o local. Selecione Seguinte.

  3. Aceite os padrões para estrutura de destino, tipo de autenticação e HTTPS. Selecione Criar.

  4. Instale a biblioteca do cliente. Em Ferramentas>Gestor de Pacotes NuGet>Gerir Pacotes NuGet pela Solução..., selecione Pesquisar e procure por "azure.search.documents". Instale Azure.Search.Documents (versão 11 ou posterior), aceitando os contratos de licença e dependências.

    Usando o NuGet para adicionar bibliotecas do Azure

Nesta etapa, defina o ponto de extremidade e a chave de acesso para se conectar ao serviço de pesquisa que fornece o índice de amostra de hotéis.

  1. Abra appsettings.json e substitua as linhas padrão pelo URL do serviço de pesquisa (no formato https://<service-name>.search.windows.net) e uma chave de API de administrador ou consulta do seu serviço de pesquisa. Como não é necessário criar ou atualizar um índice, você pode usar a chave de consulta para este tutorial.

    {
        "SearchServiceUri": "<YOUR-SEARCH-SERVICE-URI>",
        "SearchServiceQueryApiKey": "<YOUR-SEARCH-SERVICE-API-KEY>"
    }
    
  2. No Gerenciador de Soluções, selecione o arquivo e, em Propriedades, altere a configuração Copiar para Diretório de Saída para Copiar se for mais recente.

    Copiando as configurações do aplicativo para a saída

Modelar estruturas de dados

Os modelos (classes C#) são usados para comunicar dados entre o cliente (a exibição), o servidor (o controlador) e também a nuvem do Azure usando a arquitetura MVC (modelo, exibição, controlador). Normalmente, esses modelos refletem a estrutura dos dados que estão sendo acessados.

Nesta etapa, você modelará as estruturas de dados do índice de pesquisa, bem como a cadeia de caracteres de pesquisa usada nas comunicações de visualização/controlador. No índice de hotéis, cada hotel tem muitos quartos e cada hotel tem um endereço com várias partes. Em conjunto, a representação completa de um hotel é uma estrutura de dados hierárquica e aninhada. Você precisará de três classes para criar cada componente.

O conjunto de classes Hotel, Address e Room são conhecidos como tipos complexos, um recurso importante da Pesquisa Cognitiva do Azure. Tipos complexos podem ter muitos níveis de profundidade de classes e subclasses, e permitir que estruturas de dados muito mais complexas sejam representadas do que usando tipos simples (uma classe contendo apenas membros primitivos).

  1. No Gerenciador de Soluções, clique com o botão direito do mouse em Modelos>Adicionar>Novo Item.

  2. Selecione Classe e nomeie o item Hotel.cs. Substitua todo o conteúdo do Hotel.cs pelo código a seguir. Note os membros Endereço e Sala da classe, esses campos são classes em si, então você precisará de modelos para estas também.

    using Azure.Search.Documents.Indexes;
    using Azure.Search.Documents.Indexes.Models;
    using Microsoft.Spatial;
    using System;
    using System.Text.Json.Serialization;
    
    namespace FirstAzureSearchApp.Models
    {
        public partial class Hotel
        {
            [SimpleField(IsFilterable = true, IsKey = 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; }
    
            public Address Address { get; set; }
    
            [SimpleField(IsFilterable = true, IsSortable = true)]
            public GeographyPoint Location { get; set; }
    
            public Room[] Rooms { get; set; }
        }
    }
    
  3. Repita o mesmo processo de criação de um modelo para a classe Address , nomeando o arquivo Address.cs. Substitua o conteúdo pelo seguinte.

    using Azure.Search.Documents.Indexes;
    
    namespace FirstAzureSearchApp.Models
    {
        public partial class Address
        {
            [SearchableField]
            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. E novamente, siga o mesmo processo para criar a classe Room , nomeando o arquivo Room.cs.

    using Azure.Search.Documents.Indexes;
    using Azure.Search.Documents.Indexes.Models;
    using System.Text.Json.Serialization;
    
    namespace FirstAzureSearchApp.Models
    {
        public partial class Room
        {
            [SearchableField(AnalyzerName = LexicalAnalyzerName.Values.EnMicrosoft)]
            public string Description { get; set; }
    
            [SearchableField(AnalyzerName = LexicalAnalyzerName.Values.FrMicrosoft)]
            [JsonPropertyName("Description_fr")]
            public string DescriptionFr { get; set; }
    
            [SearchableField(IsFilterable = true, IsFacetable = true)]
            public string Type { get; set; }
    
            [SimpleField(IsFilterable = true, IsFacetable = true)]
            public double? BaseRate { get; set; }
    
            [SearchableField(IsFilterable = true, IsFacetable = true)]
            public string BedOptions { get; set; }
    
            [SimpleField(IsFilterable = true, IsFacetable = true)]
            public int SleepsCount { get; set; }
    
            [SimpleField(IsFilterable = true, IsFacetable = true)]
            public bool? SmokingAllowed { get; set; }
    
            [SearchableField(IsFilterable = true, IsFacetable = true)]
            public string[] Tags { get; set; }
        }
    }
    
  5. O último modelo que você criará neste tutorial é uma classe chamada SearchData e representa a entrada do usuário (searchText) e a saída da pesquisa (resultList). O tipo de saída é crítico, SearchResults<Hotel>, pois esse tipo corresponde exatamente aos resultados da pesquisa, e você precisa passar essa referência para a exibição. Substitua o modelo padrão pelo código a seguir.

    using Azure.Search.Documents.Models;
    
    namespace FirstAzureSearchApp.Models
    {
        public class SearchData
        {
            // The text to search for.
            public string searchText { get; set; }
    
            // The list of results.
            public SearchResults<Hotel> resultList;
        }
    }
    

Criar uma página Web

Os modelos de projeto vêm com várias visualizações de cliente localizadas na pasta Exibições . As exibições exatas dependem da versão do Core .NET que você está usando (a versão 3.1 é usada neste exemplo). Para este tutorial, você modificará Index.cshtml para incluir os elementos de uma página de pesquisa.

Exclua o conteúdo de Index.cshtml em sua totalidade e reconstrua o arquivo nas etapas a seguir.

  1. O tutorial usa duas pequenas imagens na exibição: um logotipo do Azure e um ícone de lupa de pesquisa (azure-logo.png e search.png). Copie as imagens do projeto GitHub para a pasta wwwroot/images em seu projeto.

  2. A primeira linha de Index.cshtml deve fazer referência ao modelo usado para comunicar dados entre o cliente (a exibição) e o servidor (o controlador), que é o modelo SearchData criado anteriormente. Adicione esta linha ao arquivo Index.cshtml.

    @model FirstAzureSearchApp.Models.SearchData
    
  3. É prática comum inserir um título para a exibição, portanto, as próximas linhas devem ser:

    @{
        ViewData["Title"] = "Home Page";
    }
    
  4. Após o título, insira uma referência a uma folha de estilo HTML, que você criará em breve.

    <head>
        <link rel="stylesheet" href="~/css/hotels.css" />
    </head>
    
  5. O corpo do modo de exibição lida com dois casos de uso. Primeiro, ele deve fornecer uma página vazia no primeiro uso, antes de qualquer texto de pesquisa ser inserido. Em segundo lugar, ele deve lidar com resultados, além da caixa de texto de pesquisa, para consultas repetidas.

    Para lidar com ambos os casos, você precisa verificar se o modelo fornecido para a exibição é nulo. Um modelo nulo indica o primeiro caso de uso (a execução inicial do aplicativo). Adicione o seguinte ao arquivo Index.cshtml e leia os comentários.

    <body>
    <h1 class="sampleTitle">
        <img src="~/images/azure-logo.png" width="80" />
        Hotels Search
    </h1>
    
    @using (Html.BeginForm("Index", "Home", FormMethod.Post))
    {
        // Display the search text box, with the search icon to the right of it.
        <div class="searchBoxForm">
            @Html.TextBoxFor(m => m.searchText, new { @class = "searchBox" }) <input class="searchBoxSubmit" type="submit" value="">
        </div>
    
        @if (Model != null)
        {
            // Show the result count.
            <p class="sampleText">
                @Model.resultList.TotalCount Results
            </p>
    
            var results = Model.resultList.GetResults().ToList();
    
            @for (var i = 0; i < results.Count; i++)
            {
                // Display the hotel name and description.
                @Html.TextAreaFor(m => results[i].Document.HotelName, new { @class = "box1" })
                @Html.TextArea($"desc{i}", results[i].Document.Description, new { @class = "box2" })
            }
        }
    }
    </body>
    
  6. Adicione a folha de estilo. No Visual Studio, em Arquivo>Novo>Arquivo, selecione Folha de Estilos (com Geral realçado).

    Substitua o código padrão pelo seguinte. Não entraremos neste arquivo com mais detalhes, os estilos são HTML padrão.

    textarea.box1 {
        width: 648px;
        height: 30px;
        border: none;
        background-color: azure;
        font-size: 14pt;
        color: blue;
        padding-left: 5px;
    }
    
    textarea.box2 {
        width: 648px;
        height: 100px;
        border: none;
        background-color: azure;
        font-size: 12pt;
        padding-left: 5px;
        margin-bottom: 24px;
    }
    
    .sampleTitle {
        font: 32px/normal 'Segoe UI Light',Arial,Helvetica,Sans-Serif;
        margin: 20px 0;
        font-size: 32px;
        text-align: left;
    }
    
    .sampleText {
        font: 16px/bold 'Segoe UI Light',Arial,Helvetica,Sans-Serif;
        margin: 20px 0;
        font-size: 14px;
        text-align: left;
        height: 30px;
    }
    
    .searchBoxForm {
        width: 648px;
        box-shadow: 0 0 0 1px rgba(0,0,0,.1), 0 2px 4px 0 rgba(0,0,0,.16);
        background-color: #fff;
        display: inline-block;
        border-collapse: collapse;
        border-spacing: 0;
        list-style: none;
        color: #666;
    }
    
    .searchBox {
        width: 568px;
        font-size: 16px;
        margin: 5px 0 1px 20px;
        padding: 0 10px 0 0;
        border: 0;
        max-height: 30px;
        outline: none;
        box-sizing: content-box;
        height: 35px;
        vertical-align: top;
    }
    
    .searchBoxSubmit {
        background-color: #fff;
        border-color: #fff;
        background-image: url(/images/search.png);
        background-repeat: no-repeat;
        height: 20px;
        width: 20px;
        text-indent: -99em;
        border-width: 0;
        border-style: solid;
        margin: 10px;
        outline: 0;
    }
    
  7. Salve o arquivo de folha de estilo como hotels.css, na pasta wwwroot/css , ao lado do arquivo site.css padrão.

Isso completa o nosso ponto de vista. Neste ponto, os modelos e visualizações estão concluídos. Resta apenas ao controlador amarrar tudo.

Definir métodos

Nesta etapa, modifique o conteúdo do Home Controller.

  1. Abra o arquivo HomeController.cs e substitua as instruções using pelo seguinte.

    using Azure;
    using Azure.Search.Documents;
    using Azure.Search.Documents.Indexes;
    using FirstAzureSearchApp.Models;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Configuration;
    using System;
    using System.Diagnostics;
    using System.Linq;
    using System.Threading.Tasks;
    

Adicionar métodos Index

Em um aplicativo MVC, o método Index() é um método de ação padrão para qualquer controlador. Ele abre a página HTML do índice. O método padrão, que não usa parâmetros, é usado neste tutorial para o caso de uso de inicialização do aplicativo: renderizar uma página de pesquisa vazia.

Nesta seção, estendemos o método para dar suporte a um segundo caso de uso: renderizar a página quando um usuário inseriu texto de pesquisa. Para dar suporte a esse caso, o método de índice é estendido para tomar um modelo como parâmetro.

  1. Adicione o seguinte método, após o método Index() padrão.

        [HttpPost]
        public async Task<ActionResult> Index(SearchData model)
        {
            try
            {
                // Ensure the search string is valid.
                if (model.searchText == null)
                {
                    model.searchText = "";
                }
    
                // Make the Azure Cognitive Search call.
                await RunQueryAsync(model);
            }
    
            catch
            {
                return View("Error", new ErrorViewModel { RequestId = "1" });
            }
            return View(model);
        }
    

    Observe a declaração async do método e a chamada await para RunQueryAsync. Essas palavras-chave cuidam de fazer chamadas assíncronas e, assim, evitam bloquear threads no servidor.

    O bloco catch usa o modelo de erro padrão que foi criado.

Observe o tratamento de erros e outros modos de exibição e métodos padrão

Dependendo da versão do .NET Core que você está usando, um conjunto ligeiramente diferente de modos de exibição padrão é criado. Para o .NET Core 3.1, os modos de exibição padrão são Índice, Privacidade e Erro. Você pode exibir essas páginas padrão ao executar o aplicativo e examinar como elas são tratadas no controlador.

Você irá testar a vista de erros mais adiante neste tutorial.

No exemplo do GitHub, as exibições não utilizadas e suas ações associadas são excluídas.

Adicionar o método RunQueryAsync

A chamada da Pesquisa Cognitiva do Azure é encapsulada em nosso método RunQueryAsync .

  1. Primeiro, adicione algumas variáveis estáticas para configurar o serviço do Azure e uma chamada para iniciá-las.

        private static SearchClient _searchClient;
        private static SearchIndexClient _indexClient;
        private static IConfigurationBuilder _builder;
        private static IConfigurationRoot _configuration;
    
        private void InitSearch()
        {
            // Create a configuration using appsettings.json
            _builder = new ConfigurationBuilder().AddJsonFile("appsettings.json");
            _configuration = _builder.Build();
    
            // Read the values from appsettings.json
            string searchServiceUri = _configuration["SearchServiceUri"];
            string queryApiKey = _configuration["SearchServiceQueryApiKey"];
    
            // Create a service and index client.
            _indexClient = new SearchIndexClient(new Uri(searchServiceUri), new AzureKeyCredential(queryApiKey));
            _searchClient = _indexClient.GetSearchClient("hotels");
        }
    
  2. Agora, adicione o próprio método RunQueryAsync .

    private async Task<ActionResult> RunQueryAsync(SearchData model)
    {
        InitSearch();
    
        var options = new SearchOptions() 
        { 
            IncludeTotalCount = true
        };
    
        // Enter Hotel property names into this list so only these values will be returned.
        // If Select is empty, all values will be returned, which can be inefficient.
        options.Select.Add("HotelName");
        options.Select.Add("Description");
    
        // For efficiency, the search call should be asynchronous, so use SearchAsync rather than Search.
        model.resultList = await _searchClient.SearchAsync<Hotel>(model.searchText, options).ConfigureAwait(false);          
    
        // Display the results.
        return View("Index", model);
    }
    

    Nesse método, primeiro verifique se nossa configuração do Azure foi iniciada e, em seguida, defina algumas opções de pesquisa. A opção Selecionar especifica quais campos devem ser retornados nos resultados e, portanto, correspondem aos nomes de propriedade na classe de hotel . Se você omitir Selecionar, todos os campos não ocultos serão retornados, o que pode ser ineficiente se você estiver interessado apenas em um subconjunto de todos os campos possíveis.

    A chamada assíncrona para pesquisar formula a solicitação (modelada como searchText) e a resposta (modelada como searchResult). Se você estiver depurando esse código, a classe SearchResult é um bom candidato para definir um ponto de interrupção se você precisar examinar o conteúdo de model.resultList. Você deve achar que é intuitivo, fornecendo apenas os dados que você solicitou, e não muito mais.

Testar a aplicação

Agora, vamos verificar se o aplicativo é executado corretamente.

  1. Selecione Depurar>Iniciar Sem Depuração ou pressione F5. Se o aplicativo for executado conforme o esperado, você deverá obter a visualização inicial do índice.

    Abrir a aplicação

  2. Insira uma seqüência de caracteres de consulta, como "praia" (ou qualquer texto que venha à mente), e clique no ícone de pesquisa para enviar a solicitação.

    À procura de *praia*

  3. Tente digitar "cinco estrelas". Observe que essa consulta não retorna nenhum resultado. Uma pesquisa mais sofisticada trataria "cinco estrelas" como sinônimo de "luxo" e devolveria esses resultados. O suporte para sinónimos está disponível na Pesquisa Cognitiva do Azure, mas não é abordado nesta série de tutoriais.

  4. Tente inserir "hot" como texto de pesquisa. Ele não retorna entradas com a palavra "hotel" neles. Nossa pesquisa está localizando apenas palavras inteiras, embora alguns resultados sejam retornados.

  5. Tente outras palavras: "piscina", "sol", "vista" e o que for. Você verá a Pesquisa Cognitiva do Azure funcionando em seu nível mais simples, mas ainda assim convincente.

Condições e erros de borda de teste

É importante verificar se nossos recursos de tratamento de erros funcionam como deveriam, mesmo quando as coisas estão funcionando perfeitamente.

  1. No método Index , após a chamada try { , digite a linha Throw new Exception(). Essa exceção forçará um erro quando você pesquisar no texto.

  2. Execute o aplicativo, digite "bar" como texto de pesquisa e clique no ícone de pesquisa. A exceção deve resultar na visualização de erro.

    Forçar um erro

    Importante

    É considerado um risco de segurança retornar números de erro internos em páginas de erro. Se a sua aplicação se destinar a utilização geral, siga as práticas recomendadas de segurança sobre o que devolver quando ocorrer um erro.

  3. Remover Throw new Exception() quando estiver satisfeito de que o tratamento de erros funciona como esperado.

Conclusões

Considere as seguintes conclusões deste projeto:

  • Uma chamada da Pesquisa Cognitiva do Azure é concisa e fácil de interpretar os resultados.
  • As chamadas assíncronas adicionam uma pequena quantidade de complexidade ao controlador, mas são uma prática recomendada que melhora o desempenho.
  • Este aplicativo realizou uma pesquisa de texto simples, definida pelo que está configurado em searchOptions. No entanto, esta classe pode ser preenchida com muitos membros que adicionam sofisticação a uma pesquisa. Com um pouco mais de trabalho, você pode tornar este aplicativo consideravelmente mais poderoso.

Próximos passos

Para melhorar a experiência do usuário, adicione mais recursos, principalmente paginação (usando números de página ou rolagem infinita) e preenchimento automático/sugestões. Você também pode considerar outras opções de pesquisa (por exemplo, pesquisas geográficas em hotéis dentro de um raio especificado de um determinado ponto) e ordenação dos resultados da pesquisa.

Essas próximas etapas são abordadas nos tutoriais restantes. Comecemos pela paginação.