Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
W tym samouczku pokazano, jak utworzyć aplikację internetową, która wysyła zapytania i zwraca wyniki z indeksu wyszukiwania przy użyciu usługi Azure Cognitive Search i programu Visual Studio.
W tym poradniku dowiesz się, jak:
- 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 łatwe jest wykonanie wywołania wyszukiwania. Kluczowe instrukcje w kodzie są zawarte w następujących linijkach.
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.
Przegląd
W tym samouczku użyto 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ń oraz stronę wyszukiwania, którą rozbudujesz w kolejnych lekcjach, aby uwzględnić stronicowanie, facety i funkcjonalność z podpowiedziami.
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: Utwórz pierwszą aplikację.
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 i otwórz rozwiązanie dla strony wyszukiwania podstawowego ("1-basic-search-page"), a następnie wybierz pozycję Rozpocznij bez debugowania (lub naciśnij 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 bardziej zaawansowanych wyszukiwań są zawarte w tej jednej aplikacji. Jeśli dopiero zaczynasz wyszukiwać, 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 usługi Azure Cognitive Search, zacznij od projektu programu Visual Studio.
W programie Visual Studio wybierz pozycję Nowy>projekt, a następnie ASP.NET Core Web App (model-View-Controller).
Nadaj projektowi nazwę, taką jak "FirstSearchApp" i ustaw lokalizację. Wybierz Dalej.
Zaakceptuj wartości domyślne dla platformy docelowej, typu uwierzytelniania i protokołu HTTPS. Wybierz Utwórz.
Zainstaluj bibliotekę klienta. W Narzędzia>Menedżer Pakietów NuGet>Zarządzaj pakietami NuGet dla rozwiązania..., wybierz opcję Przeglądaj, a następnie wyszukaj "azure.search.documents". Zainstaluj plik Azure.Search.Documents (wersja 11 lub nowsza), akceptując umowy licencyjne i zależności.
Inicjowanie usługi 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 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 Eksploratorze rozwiązań wybierz plik, a następnie w obszarze Właściwości zmień ustawienie Kopiuj na katalog wyjściowy na Kopiuj, jeśli jest nowsze.
Struktury danych modelu
Modele (klasy języka C#) służą 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. Ogółem, pełna reprezentacja hotelu to hierarchiczna i zagnieżdżona struktura danych. Do utworzenia każdego składnika potrzebne będą trzy klasy.
Zestaw klas Hotel, Address i Room jest nazywany typami złożonymi, ważną funkcją usługi Azure Cognitive Search. Typy złożone mogą osiągać wiele poziomów w klasach i podklasach, umożliwiając reprezentację znacznie bardziej złożonych struktur danych niż przy wykorzystaniu typów prostych (klasy zawierające tylko składowe pierwotne).
W Eksploratorze rozwiązań kliknij prawym przyciskiem myszy pozycję Modele>Dodaj>nowy element.
Wybierz Klasa i nadaj elementowi nazwę Hotel.cs. Zastąp całą zawartość Hotel.cs następującym kodem. Zwróć uwagę na członków klasy Adres i Pokój; te pola są same w sobie klasami, więc będziesz potrzebować również modeli dla nich.
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, nazywając plik Address.cs. Zastąp zawartość następującym 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, nazywając plik 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 i reprezentuje dane wejściowe użytkownika (searchText) oraz dane wyjściowe wyszukiwania (resultList). Typ danych wyjściowych ma krytyczne znaczenie, hotel SearchResults<>, 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 mają wiele widoków klientów znajdujących się w folderze Widoki . Dokładne widoki zależą od używanej wersji platformy .NET Core (w tym przykładzie jest używana wersja 3.1). Na potrzeby tego samouczka 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 wkrótce utworzysz.
<head> <link rel="stylesheet" href="~/css/hotels.css" /> </head>
Treść widoku obsługuje dwa przypadki użycia. Najpierw należy podać pustą stronę w 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 udostępniony 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 menu Plik, wybierz Nowy>Plik, a następnie wybierz opcję Arkusz stylów (z zaznaczoną opcją Ogólne).
Zastąp domyślny kod poniższym kodem. Nie będziemy w tym 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 wraz z domyślnym plikiem site.css.
To kończy nasz przegląd. 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ść kontrolera domu.
Otwórz plik HomeController.cs i zastąp instrukcje using poniższymi 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 parametrów, jest używana w tym samouczku dla 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 użycia 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 deklarację asynchronicznych metody i wywołanie await do elementu 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 zostanie utworzony nieco inny zestaw widoków domyślnych. W przypadku platformy .NET Core 3.1 domyślne widoki to Indeks, Prywatność i Błąd. Te strony domyślne można wyświetlić podczas uruchamiania aplikacji i sprawdzić, jak są one obsługiwane w kontrolerze.
W dalszej części tego samouczka będziesz testować widok błędów.
W przykładzie usługi GitHub usunięte są nieużywane widoki i skojarzone z nimi akcje.
Dodawanie metody RunQueryAsync
Wywołanie usługi Azure Cognitive Search jest zawarte w naszej metodzie RunQueryAsync.
Najpierw dodaj kilka zmiennych statycznych, aby skonfigurować usługę Azure, oraz dodaj wywołanie, aby je zainicjować.
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 . Jeśli pominięto opcję Wybierz, zostaną zwrócone wszystkie niezaszyfrowane 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 ustawienia punktu przerwania, jeśli chcesz sprawdzić zawartość elementu model.resultList. Powinno się okazać, ż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 poprawnie.
Wybierz pozycję Debuguj>rozpocznij bez debugowania lub naciśnij 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 na myśl), 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 traktuje "pięć gwiazdek" jako synonim "luksusu" i zwraca te wyniki. Obsługa synonimów jest dostępna w usłudze Azure Cognitive Search, ale nie jest omówiona w tej serii samouczków.
Spróbuj wprowadzić "hot" jako tekst wyszukiwania. Nie zwraca wpisów zawierających słowo "hotel". Nasze wyszukiwanie wyszukuje tylko całe wyrazy, choć zwracane są kilka wyników.
Spróbuj użyć innych słów: "basen", "słońce", "widok" i cokolwiek innego. Zobaczysz, że usługa Azure Cognitive Search działa na najprostszym poziomie, ale nadal przekonująca.
Testowanie warunków skrajnych 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 przeszukiwania 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
Uważa się, że zwracanie wewnętrznych numerów błędów na stronach błędów stanowi zagrożenie dla bezpieczeństwa. Jeśli aplikacja jest przeznaczona do użytku ogólnego, postępuj zgodnie z najlepszymi rozwiązaniami w zakresie zabezpieczeń, które należy zwrócić po wystąpieniu błędu.
Usuń Throw new Exception(), jeśli obsługa błędów działa tak, jak powinna.
Wnioski
Rozważ następujące wnioski z tego projektu:
- Wywołanie usługi Azure Cognitive Search jest zwięzłe i wyniki są łatwe do interpretacji.
- Wywołania asynchroniczne zwiększają niewielką 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 członkami, którzy wnoszą wyrafinowanie do wyszukiwania. Dzięki nieco większej pracy możesz znacznie zwiększyć możliwości tej aplikacji.
Dalsze kroki
Aby ulepszyć środowisko użytkownika, dodaj więcej funkcji, zwłaszcza 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.