Partilhar via


Tutorial: Criar a sua primeira aplicação de pesquisa no Azure Cognitive Search com o SDK .NET

Este tutorial mostra-lhe como criar uma aplicação Web que consulta e devolve resultados de um índice de pesquisa com o Azure Cognitive Search e o Visual Studio.

Neste tutorial, irá aprender a:

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

Também irá aprender o quão simples é uma chamada de pesquisa. As instruções-chave 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 devolve resultados.

A procurar *conjunto*

Descrição Geral

Este tutorial utiliza o hotels-sample-index, que pode criar rapidamente no seu próprio serviço de pesquisa ao percorrer o início rápido Importar dados. O índice contém dados de hotel fictícios, disponíveis como uma origem de dados incorporada em todos os serviços de pesquisa.

A primeira lição neste tutorial cria uma estrutura de consulta básica e uma página de pesquisa, que irá melhorar nas lições subsequentes para incluir paginação, facetas e uma experiência de introdução.

Pode encontrar uma versão concluída do código no projeto seguinte:

Pré-requisitos

Instalar e executar o projeto a partir do GitHub

Se quiser avançar para uma aplicação de trabalho, siga os passos abaixo para transferir e executar o código concluído.

  1. Localize o exemplo no GitHub: Criar a primeira aplicação.

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

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

  4. Este é um índice de hotéis, por isso escreva algumas palavras que poderá utilizar para procurar hotéis (por exemplo, "wifi", "view", "bar", "parking"). Examine os resultados.

    A procurar *wi-fi*

Os componentes essenciais para pesquisas mais sofisticadas estão incluídos nesta única aplicação. Se não estiver familiarizado com o desenvolvimento da pesquisa, pode recriar esta aplicação passo a passo para conhecer o fluxo de trabalho. As secções seguintes mostram-lhe como.

Configurar um ambiente de desenvolvimento

Para criar este projeto de raiz e, assim, reforçar os conceitos de Azure Cognitive Search, comece com um projeto do Visual Studio.

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

    Criar um projeto na cloud

  2. Atribua um nome ao projeto, como "FirstSearchApp" e defina a localização. Selecione Seguinte.

  3. Aceite as predefinições para arquitetura de destino, tipo de autenticação e HTTPS. Selecione Criar.

  4. Instale a biblioteca de cliente. Em Ferramentas> Gestor > dePacotes NuGetGerir Pacotes NuGet para Solução..., selecione Procurar e, em seguida, procure "azure.search.documents". Instale Azure.Search.Documents (versão 11 ou posterior), aceitando os contratos de licença e as dependências.

    Utilizar o NuGet para adicionar bibliotecas do Azure

Neste passo, defina o ponto final e a chave de acesso para ligar ao serviço de pesquisa que fornece o índice de exemplo de hotéis.

  1. Abra appsettings.json e substitua as linhas predefinidas 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. Uma vez que não precisa de criar ou atualizar um índice, pode utilizar a chave de consulta para este tutorial.

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

    Copiar as definições da aplicação para a saída

Modelar estruturas de dados

Os modelos (classes C#) são utilizados para comunicar dados entre o cliente (a vista), o servidor (o controlador) e também a cloud do Azure com a arquitetura MVC (modelo, vista, controlador). Normalmente, estes modelos refletem a estrutura dos dados que estão a ser acedidos.

Neste passo, vai modelar as estruturas de dados do índice de pesquisa, bem como a cadeia de pesquisa utilizada nas comunicações de visualização/controlador. No índice de hotéis, cada hotel tem muitos quartos, e cada hotel tem um endereço multi-peças. No total, a representação total de um hotel é uma estrutura de dados hierárquica e aninhada. Precisará de três classes para criar cada componente.

O conjunto de classes Hotel, Endereço e Quarto é conhecido como tipos complexos, uma funcionalidade importante do Azure Cognitive Search. Os tipos complexos podem ter muitos níveis de classes e subclasses profundas e permitir a representação de estruturas de dados muito mais complexas do que a utilização de tipos simples (uma classe que contém apenas membros primitivos).

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

  2. Selecione Classe e atribua um nome ao item Hotel.cs. Substitua todos os conteúdos do Hotel.cs pelo seguinte código. Repare nos membros do Endereço e da Sala da classe. Estes campos são as próprias classes, pelo que também irá precisar de modelos para os mesmos.

    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 Endereço , atribuindo um nome ao ficheiro 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, mais uma vez, siga o mesmo processo para criar a classe Sala , atribuindo um nome ao ficheiro 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 irá criar neste tutorial é uma classe chamada SearchData e representa a entrada do utilizador (searchText) e a saída da pesquisa (resultList). O tipo de saída é crítico, SearchResults<Hotel>, uma vez que este tipo corresponde exatamente aos resultados da pesquisa e tem de transmitir esta referência para a vista. Substitua o modelo predefinido pelo seguinte código.

    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 vistas de cliente localizadas na pasta Vistas . As vistas exatas dependem da versão do Core .NET que está a utilizar (a versão 3.1 é utilizada neste exemplo). Neste tutorial, irá modificar Index.cshtml para incluir os elementos de uma página de pesquisa.

Elimine o conteúdo de Index.cshtml na sua totalidade e recrie o ficheiro nos passos seguintes.

  1. O tutorial utiliza duas imagens pequenas na vista: um logótipo 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 no seu projeto.

  2. A primeira linha de Index.cshtml deve referenciar o modelo utilizado para comunicar dados entre o cliente (a vista) e o servidor (o controlador), que é o modelo SearchData criado anteriormente. Adicione esta linha ao ficheiro Index.cshtml.

    @model FirstAzureSearchApp.Models.SearchData
    
  3. É prática padrão introduzir um título para a vista, pelo que as linhas seguintes devem ser:

    @{
        ViewData["Title"] = "Home Page";
    }
    
  4. Seguindo o título, introduza uma referência a uma folha de estilos HTML, que irá criar em breve.

    <head>
        <link rel="stylesheet" href="~/css/hotels.css" />
    </head>
    
  5. O corpo da vista processa dois casos de utilização. Primeiro, tem de fornecer uma página vazia na primeira utilização, antes de ser introduzido qualquer texto de pesquisa. Em segundo lugar, tem de processar os resultados, para além da caixa de texto de pesquisa, para consultas repetidas.

    Para lidar com ambos os casos, tem de verificar se o modelo fornecido à vista é nulo. Um modelo nulo indica o primeiro caso de utilização (a execução inicial da aplicação). Adicione o seguinte ao ficheiro 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 estilos. No Visual Studio, em Ficheiro>Novo>Ficheiro, selecione Folha de Estilos (com Geral realçado).

    Substitua o código predefinido pelo seguinte. Não entraremos neste ficheiro mais detalhadamente. 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. Guarde o ficheiro de folha de estilos como hotels.css, na pasta wwwroot/css , juntamente com o ficheiro site.css predefinido.

Isto conclui a nossa vista. Neste momento, os modelos e as vistas estão concluídos. Só resta o comando para unir tudo.

Definir métodos

Neste passo, modifique para o conteúdo do Controlador Principal.

  1. Abra o ficheiro HomeController.cs e substitua as instruções de utilização 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 de Índice

Numa aplicação MVC, o método Index() é um método de ação predefinido para qualquer controlador. Abre a página HTML do índice. O método predefinido, que não utiliza parâmetros, é utilizado neste tutorial para o caso de utilização de arranque da aplicação: compor uma página de pesquisa vazia.

Nesta secção, vamos expandir o método para suportar um segundo caso de utilização: compor a página quando um utilizador introduzir texto de pesquisa. Para suportar este caso, o método de índice é expandido para utilizar um modelo como parâmetro.

  1. Adicione o seguinte método, após o método index() predefinido.

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

    Repare na declaração assíncrona do método e na chamada de espera para RunQueryAsync. Estas palavras-chave tratam de fazer chamadas assíncronas e, assim, evitam bloquear threads no servidor.

    O bloco catch utiliza o modelo de erro predefinido que foi criado.

Tenha em atenção o processamento de erros e outros métodos e vistas predefinidas

Dependendo da versão do .NET Core que está a utilizar, é criado um conjunto ligeiramente diferente de vistas predefinidas. Para o .NET Core 3.1, as vistas predefinidas são Índice, Privacidade e Erro. Pode ver estas páginas predefinidas ao executar a aplicação e examinar a forma como são processadas no controlador.

Irá testar a Vista de erro mais adiante neste tutorial.

No exemplo do GitHub, as vistas não utilizadas e as respetivas ações associadas são eliminadas.

Adicionar o método RunQueryAsync

A chamada de Azure Cognitive Search está encapsulada no nosso método RunQueryAsync.

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

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

    Neste método, primeiro certifique-se de que a nossa configuração do Azure é iniciada e, em seguida, defina algumas opções de pesquisa. A opção Selecionar especifica os campos a devolver nos resultados e, assim, corresponde aos nomes das propriedades na classe hoteleira . Se omitir Selecionar, todos os campos não vinculados são devolvidos, o que pode ser ineficiente se apenas estiver interessado num subconjunto de todos os campos possíveis.

    A chamada assíncrona para procurar formula o pedido (modelado como searchText) e a resposta (modelada como searchResult). Se estiver a depurar este código, a classe SearchResult é uma boa candidata para definir um ponto de interrupção se precisar de examinar os conteúdos de model.resultList. Deve achar que é intuitivo, fornecendo apenas os dados que pediu e pouco mais.

Testar a aplicação

Agora, vamos verificar se a aplicação é executada corretamente.

  1. Selecione Depurar>Iniciar Sem Depuração ou prima F5. Se a aplicação for executada conforme esperado, deverá obter a vista de Índice inicial.

    Abrir a aplicação

  2. Introduza uma cadeia de consulta, como "praia" (ou qualquer texto que venha à mente) e clique no ícone de pesquisa para enviar o pedido.

    A procurar *praia*

  3. Experimente introduzir "cinco estrelas". Repare que esta consulta não devolve resultados. Uma pesquisa mais sofisticada trataria "cinco estrelas" como um sinónimo de "luxo" e devolveria esses resultados. O suporte para sinónimos está disponível em Azure Cognitive Search, mas não está abrangido nesta série de tutoriais.

  4. Experimente introduzir "frequente" como texto de pesquisa. Não devolve entradas com a palavra "hotel" nelas. A nossa pesquisa está apenas a localizar palavras inteiras, embora sejam devolvidos alguns resultados.

  5. Experimente outras palavras: "pool", "sunshine", "view" e o que quer que seja. Verá Azure Cognitive Search a trabalhar no seu nível mais simples, mas ainda assim convincente.

Testar as condições e os erros do edge

É importante verificar se as nossas funcionalidades de processamento de erros funcionam como deviam, mesmo quando as coisas estão a funcionar perfeitamente.

  1. No método Índice , após a chamada try { , introduza a linha Lançar nova Exceção(). Esta exceção forçará um erro ao procurar texto.

  2. Execute a aplicação, introduza "barra" como texto de pesquisa e clique no ícone de pesquisa. A exceção deve resultar na vista de erro.

    Forçar um erro

    Importante

    Considera-se um risco de segurança devolver números de erro internos em páginas de erro. Se a sua aplicação se destinar a uma utilização geral, siga as melhores práticas de segurança do que devolver quando ocorrer um erro.

  3. Remova Lançar nova Exceção() quando estiver satisfeito, o processamento de erros funciona como deveria.

Conclusões

Considere as seguintes conclusões deste projeto:

  • Uma chamada Azure Cognitive Search é concisa e é fácil interpretar os resultados.
  • As chamadas assíncronas adicionam uma pequena complexidade ao controlador, mas são uma melhor prática que melhora o desempenho.
  • Esta aplicação 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, pode tornar esta aplicação consideravelmente mais poderosa.

Passos seguintes

Para melhorar a experiência do utilizador, adicione mais funcionalidades, nomeadamente paginação (utilizando números de página ou deslocamento infinito) e preenchimento automático/sugestões. Também pode considerar outras opções de pesquisa (por exemplo, pesquisas geográficas em hotéis num raio especificado de um determinado ponto) e ordenação de resultados de pesquisa.

Estes passos seguintes são abordados nos tutoriais restantes. Vamos começar com a paginação.