Samouczek: tworzenie pierwszej aplikacji wyszukiwania w Azure Cognitive Search przy użyciu zestawu SDK platformy .NET
W tym samouczku pokazano, jak utworzyć aplikację internetową, która wysyła zapytania i zwraca wyniki z indeksu wyszukiwania przy użyciu Azure Cognitive Search i programu Visual Studio.
Z tego samouczka dowiesz się, jak wykonywać następujące czynności:
- Konfigurowanie środowiska projektowego
- Struktury danych modelu
- Tworzenie strony internetowej w celu zbierania danych wejściowych zapytań i wyświetlania wyników
- Definiowanie metody wyszukiwania
- Testowanie aplikacji
Dowiesz się również, jak proste jest wywołanie wyszukiwania. Kluczowe instrukcje w kodzie są hermetyzowane w następujących kilku wierszach:
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();
Wystarczy jedno wywołanie wysyła zapytanie do indeksu wyszukiwania i zwraca wyniki.
Omówienie
W tym samouczku jest używany indeks hotels-sample-index, który można szybko utworzyć we własnej usłudze wyszukiwania, wykonując kroki z przewodnika Szybki start Importowanie danych. Indeks zawiera fikcyjne dane hotelowe dostępne jako wbudowane źródło danych w każdej usłudze wyszukiwania.
Pierwsza lekcja w tym samouczku tworzy podstawową strukturę zapytań i stronę wyszukiwania, którą ulepszysz podczas kolejnych lekcji, aby uwzględnić stronicowanie, aspekty i środowisko z wyprzedzeniem.
Gotową wersję kodu można znaleźć w następującym projekcie:
Wymagania wstępne
Przykładowy indeks (hotels-sample-index), hostowany w usłudze wyszukiwania.
Instalowanie i uruchamianie projektu z usługi GitHub
Jeśli chcesz przejść do działającej aplikacji, wykonaj poniższe kroki, aby pobrać i uruchomić gotowy kod.
Znajdź przykład w witrynie GitHub: Tworzenie pierwszej aplikacji.
W folderze głównym wybierz pozycję Kod, a następnie pozycję Klonuj lub Pobierz plik ZIP , aby uzyskać prywatną kopię lokalną projektu.
Za pomocą programu Visual Studio przejdź do strony wyszukiwania podstawowego i otwórz je ("1-basic-search-page"), a następnie wybierz pozycję Rozpocznij bez debugowania (lub naciśnij klawisz F5), aby skompilować i uruchomić program.
Jest to indeks hoteli, więc wpisz kilka słów, których można użyć do wyszukiwania hoteli (na przykład "wifi", "view", "bar", "parking"). Sprawdź wyniki.
Podstawowe składniki wyszukiwania bardziej zaawansowanego są zawarte w tej jednej aplikacji. Jeśli jesteś nowym użytkownikm do opracowywania wyszukiwania, możesz ponownie utworzyć tę aplikację krok po kroku, aby dowiedzieć się więcej o przepływie pracy. W poniższych sekcjach pokazano, jak to zrobić.
Konfigurowanie środowiska projektowego
Aby utworzyć ten projekt od podstaw, a tym samym wzmocnić koncepcje Azure Cognitive Search, zacznij od projektu programu Visual Studio.
W programie Visual Studio wybierz pozycję Nowy>projekt, a następnie ASP.NET Core aplikację internetową (Model-View-Controller).
Nadaj projektowi nazwę, taką jak "FirstSearchApp", i ustaw lokalizację. Wybierz opcję Dalej.
Zaakceptuj wartości domyślne platformy docelowej, typu uwierzytelniania i protokołu HTTPS. Wybierz przycisk Utwórz.
Zainstaluj bibliotekę klienta. W obszarze Narzędzia> Menedżer >pakietów NuGetZarządzaj pakietami NuGet dla rozwiązania..., wybierz pozycję Przeglądaj, a następnie wyszukaj ciąg "azure.search.documents". Zainstaluj plik Azure.Search.Documents (wersja 11 lub nowsza), akceptując umowy licencyjne i zależności.
Inicjowanie Azure Cognitive Search
W tym kroku ustaw punkt końcowy i klucz dostępu na potrzeby nawiązywania połączenia z usługą wyszukiwania, która udostępnia przykładowy indeks hoteli.
Otwórz plik appsettings.json i zastąp domyślne wiersze adresem URL usługi wyszukiwania (w formacie
https://<service-name>.search.windows.net
) oraz kluczem interfejsu API administratora lub zapytania usługi wyszukiwania. Ponieważ nie musisz tworzyć ani aktualizować indeksu, możesz użyć klucza zapytania na potrzeby tego samouczka.{ "SearchServiceUri": "<YOUR-SEARCH-SERVICE-URI>", "SearchServiceQueryApiKey": "<YOUR-SEARCH-SERVICE-API-KEY>" }
W Eksplorator rozwiązań wybierz plik, a następnie w obszarze Właściwości zmień ustawienie Kopiuj do katalogu wyjściowego na Kopiuj, jeśli jest nowsze.
Struktury danych modelu
Modele (klasy języka C#) są używane do komunikowania danych między klientem (widokiem), serwerem (kontrolerem), a także chmurą platformy Azure przy użyciu architektury MVC (model, widok, kontroler). Zazwyczaj te modele odzwierciedlają strukturę danych, do których uzyskuje się dostęp.
W tym kroku smodelujesz struktury danych indeksu wyszukiwania, a także ciąg wyszukiwania używany w komunikacji widoku/kontrolera. W indeksie hoteli każdy hotel ma wiele pokoi, a każdy hotel ma adres wieloczęściowy. Pełną reprezentacją hotelu jest hierarchiczna i zagnieżdżona struktura danych. Do utworzenia każdego składnika potrzebne są trzy klasy.
Zestaw klas Hotel, Address i Room jest znany jako typy złożone, co jest ważną cechą Azure Cognitive Search. Typy złożone mogą mieć wiele poziomów głębi klas i podklas i umożliwiają znacznie bardziej złożone struktury danych reprezentowane niż używanie typów prostych (klasa zawierająca tylko składowe pierwotne).
W Eksplorator rozwiązań kliknij prawym przyciskiem myszy pozycję Modele>Dodaj>nowy element.
Wybierz pozycję Klasa i nadaj elementowi nazwę Hotel.cs. Zastąp całą zawartość pliku Hotel.cs następującym kodem. Zwróć uwagę na to, że elementy członkowskie Address i Room klasy, te pola są klasami, więc będziesz też potrzebować modeli.
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; } } }
Powtórz ten sam proces tworzenia modelu dla klasy Address , nazewnictwa pliku Address.cs. Zastąp zawartość poniższym kodem.
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; } } }
I ponownie wykonaj ten sam proces, aby utworzyć klasę Room , nazewnictwa pliku 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; } } }
Ostatni model, który utworzysz w tym samouczku, to klasa o nazwie SearchData , która reprezentuje dane wejściowe użytkownika (searchText) oraz dane wyjściowe wyszukiwania (resultList). Typ danych wyjściowych jest krytyczny, SearchResults<Hotel>, ponieważ ten typ dokładnie pasuje do wyników wyszukiwania i musisz przekazać to odwołanie do widoku. Zastąp szablon domyślny następującym kodem.
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; } }
Tworzenie strony internetowej
Szablony projektów są wyposażone w wiele widoków klientów znajdujących się w folderze Widoki . Dokładne widoki zależą od używanej wersji platformy .NET (w tym przykładzie jest używana wersja 3.1). W tym samouczku zmodyfikujesz plik Index.cshtml , aby uwzględnić elementy strony wyszukiwania.
Usuń zawartość pliku Index.cshtml w całości i ponownie skompiluj plik w poniższych krokach.
W tym samouczku są używane dwa małe obrazy w widoku: logo platformy Azure i ikona lupy wyszukiwania (azure-logo.png i search.png). Skopiuj obrazy z projektu GitHub do folderu wwwroot/images w projekcie.
Pierwszy wiersz pliku Index.cshtml powinien odwoływać się do modelu używanego do komunikowania danych między klientem (widokiem) a serwerem (kontrolerem), który jest wcześniej utworzonym modelem SearchData . Dodaj ten wiersz do pliku Index.cshtml.
@model FirstAzureSearchApp.Models.SearchData
Standardową praktyką jest wprowadzenie tytułu widoku, więc następne wiersze powinny być następujące:
@{ ViewData["Title"] = "Home Page"; }
Po tytule wprowadź odwołanie do arkusza stylów HTML, który zostanie wkrótce utworzony.
<head> <link rel="stylesheet" href="~/css/hotels.css" /> </head>
Treść widoku obsługuje dwa przypadki użycia. Najpierw musi podać pustą stronę przy pierwszym użyciu, zanim zostanie wprowadzony dowolny tekst wyszukiwania. Po drugie, musi obsługiwać wyniki oprócz pola tekstowego wyszukiwania w przypadku powtarzających się zapytań.
Aby obsłużyć oba przypadki, należy sprawdzić, czy model podany w widoku ma wartość null. Model o wartości null wskazuje pierwszy przypadek użycia (początkowy uruchomienie aplikacji). Dodaj następujący kod do pliku Index.cshtml i przeczytaj komentarze.
<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>
Dodaj arkusz stylów. W programie Visual Studio w obszarze Plik>nowy>plik wybierz pozycję Arkusz stylów (z wyróżnioną pozycją Ogólne ).
Zastąp domyślny kod poniższym kodem. Nie będziemy przechodzić do tego pliku bardziej szczegółowo, style są standardowym kodem HTML.
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; }
Zapisz plik arkusza stylów jako hotels.css w folderze wwwroot/css obok domyślnego pliku site.css.
To kończy nasz widok. W tym momencie zarówno modele, jak i widoki są ukończone. Tylko kontroler jest pozostawiony, aby powiązać wszystko razem.
Definiowanie metod
W tym kroku zmodyfikuj zawartość narzędzia Home Controller.
Otwórz plik HomeController.cs i zastąp instrukcje using następującymi instrukcjami.
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;
Dodawanie metod indeksu
W aplikacji MVC metoda Index() jest domyślną metodą akcji dla dowolnego kontrolera. Spowoduje to otwarcie strony HTML indeksu. Domyślna metoda, która nie przyjmuje żadnych parametrów, jest używana w tym samouczku w przypadku użycia uruchamiania aplikacji: renderowanie pustej strony wyszukiwania.
W tej sekcji rozszerzymy metodę tak, aby obsługiwała drugi przypadek użycia: renderowanie strony po wprowadzeniu tekstu wyszukiwania przez użytkownika. Aby obsłużyć ten przypadek, metoda indeksu jest rozszerzona w celu podejmowania modelu jako parametru.
Dodaj następującą metodę po domyślnej metodzie Index().
[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); }
Zwróć uwagę na asynchronizjną deklarację metody i wywołanie await do metody RunQueryAsync. Te słowa kluczowe zajmują się wykonywaniem wywołań asynchronicznych, a tym samym unikają blokowania wątków na serwerze.
Blok catch używa domyślnego modelu błędów, który został utworzony.
Zwróć uwagę na obsługę błędów i inne domyślne widoki i metody
W zależności od używanej wersji platformy .NET Core tworzony jest nieco inny zestaw widoków domyślnych. W przypadku platformy .NET Core 3.1 widoki domyślne to Indeks, Prywatność i Błąd. Możesz wyświetlić te strony domyślne podczas uruchamiania aplikacji i sprawdzić, jak są one obsługiwane w kontrolerze.
W dalszej części tego samouczka przetestujesz widok Błąd.
W przykładzie usługi GitHub usuwane są nieużywane widoki i skojarzone z nimi akcje.
Dodawanie metody RunQueryAsync
Wywołanie Azure Cognitive Search jest hermetyzowane w metodzie RunQueryAsync.
Najpierw dodaj kilka zmiennych statycznych, aby skonfigurować usługę platformy Azure i wywołanie w celu ich zainicjowania.
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"); }
Teraz dodaj samą metodę 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); }
W tej metodzie najpierw upewnij się, że konfiguracja platformy Azure została zainicjowana, a następnie ustaw niektóre opcje wyszukiwania. Opcja Wybierz określa, które pola mają być zwracane w wynikach, a tym samym pasują do nazw właściwości w klasie hotelowej . W przypadku pominięcia opcji Wybierz zwracane są wszystkie niezakryte pola, co może być nieefektywne, jeśli interesuje Cię tylko podzbiór wszystkich możliwych pól.
Asynchroniczne wywołanie wyszukiwania formułuje żądanie (modelowane jako searchText) i odpowiedź (modelowane jako searchResult). Jeśli debugujesz ten kod, klasa SearchResult jest dobrym kandydatem do ustawiania punktu przerwania, jeśli musisz zbadać zawartość elementu model.resultList. Należy się dowiedzieć, że jest to intuicyjne, dostarczając tylko dane, o które prosiłeś, a nie wiele innych.
Testowanie aplikacji
Teraz sprawdźmy, czy aplikacja działa prawidłowo.
Wybierz pozycję Rozpocznij debugowanie>bez debugowania lub naciśnij klawisz F5. Jeśli aplikacja działa zgodnie z oczekiwaniami, powinien zostać wyświetlony początkowy widok indeksu.
Wprowadź ciąg zapytania, taki jak "plaża" (lub dowolny tekst, który przychodzi do głowy), a następnie kliknij ikonę wyszukiwania, aby wysłać żądanie.
Spróbuj wprowadzić wartość "pięć gwiazdek". Zwróć uwagę, że to zapytanie nie zwraca żadnych wyników. Bardziej wyrafinowane wyszukiwanie będzie traktować "pięć gwiazdek" jako synonim "luksus" i zwrócić te wyniki. Obsługa synonimów jest dostępna w Azure Cognitive Search, ale nie jest omówiona w tej serii samouczków.
Spróbuj wprowadzić ciąg "hot" jako tekst wyszukiwania. Nie zwraca wpisów ze słowem "hotel" w nich. Nasze wyszukiwanie wyszukuje tylko całe wyrazy, chociaż zwracane są tylko kilka wyników.
Spróbuj użyć innych słów: "basen", "słońce", "widok" i cokolwiek innego. Zobaczysz, Azure Cognitive Search pracować na najprostszym, ale nadal przekonującym poziomie.
Testowanie warunków brzegowych i błędów
Ważne jest, aby sprawdzić, czy nasze funkcje obsługi błędów działają tak, jak powinny, nawet jeśli wszystko działa doskonale.
W metodzie Index po wywołaniu try { wprowadź wiersz Throw new Exception(). Ten wyjątek wymusi błąd podczas wyszukiwania tekstu.
Uruchom aplikację, wprowadź ciąg "bar" jako tekst wyszukiwania i kliknij ikonę wyszukiwania. Wyjątek powinien spowodować wyświetlenie widoku błędu.
Ważne
Jest to uważane za zagrożenie bezpieczeństwa, aby zwrócić wewnętrzne numery błędów na stronach błędów. Jeśli aplikacja jest przeznaczona do użytku ogólnego, postępuj zgodnie z najlepszymi rozwiązaniami dotyczącymi zabezpieczeń, które mają być zwracane po wystąpieniu błędu.
Usuń pozycję Throw new Exception(), jeśli obsługa błędów działa zgodnie z wymaganiami.
Wnioski
Rozważ następujące wnioski z tego projektu:
- Wywołanie Azure Cognitive Search jest zwięzłe i można łatwo interpretować wyniki.
- Wywołania asynchroniczne zwiększają złożoność kontrolera, ale są najlepszym rozwiązaniem, które poprawia wydajność.
- Ta aplikacja wykonała proste wyszukiwanie tekstu zdefiniowane przez konfigurację funkcji searchOptions. Tę klasę można jednak wypełnić wieloma elementami członkowskimi, które dodają wyrafinowanie do wyszukiwania. Dzięki nieco większej pracy możesz znacznie zwiększyć możliwości tej aplikacji.
Następne kroki
Aby ulepszyć środowisko użytkownika, dodaj więcej funkcji, w szczególności stronicowanie (przy użyciu numerów stron lub nieskończone przewijanie) oraz autouzupełnianie/sugestie. Możesz również rozważyć inne opcje wyszukiwania (na przykład wyszukiwania geograficzne w hotelach w określonym promieniu danego punktu) i porządkowanie wyników wyszukiwania.
Te następne kroki zostały rozwiązane w pozostałych samouczkach. Zacznijmy od stronicowania.