Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
V této sérii kurzů byly výsledky vráceny a zobrazeny ve výchozím pořadí. V tomto kurzu přidáte primární a sekundární kritéria řazení. Jako alternativu k řazení na základě číselných hodnot ukazuje poslední příklad, jak uspořádat výsledky na základě vlastního hodnoticího profilu. Podrobněji se také podíváme na zobrazení složitých typů.
V tomto návodu se naučíte, jak:
- Seřazení výsledků na základě jedné vlastnosti
- Seřazení výsledků na základě více vlastností
- Seřazení výsledků na základě hodnoticího profilu
Přehled
Tento kurz rozšiřuje projekt nekonečného posouvání vytvořený ve kurzu Přidání stránkování k výsledkům hledání.
Dokončenou verzi kódu v tomto kurzu najdete v následujícím projektu:
Požadavky
- 2b-add-infinite-scroll (GitHub) řešení. Tento projekt může být buď vaše vlastní verze sestavená z předchozího kurzu, nebo kopie z GitHubu.
Seřazení výsledků na základě jedné vlastnosti
Při řazení výsledků podle jedné vlastnosti, jako je například hodnocení hotelu, chceme nejen uspořádané výsledky, ale také chceme potvrzení, že pořadí je správné. Přidáním pole Hodnocení do výsledků můžeme ověřit, že jsou výsledky seřazené správně.
V tomto cvičení přidáme ještě něco navíc ke zobrazení výsledků: nejlevnější cena pokoje a nejdražší cena pokoje, pro každý hotel.
Není nutné žádné modely upravovat, aby bylo možné řazení povolit. Pouze zobrazení a kontroler vyžadují aktualizace. Začněte otevřením domácího ovladače.
Přidání vlastnosti OrderBy do parametrů hledání
V souboru HomeController.cs přidejte možnost OrderBy a zahrňte vlastnost Rating v sestupném pořadí. Do metody Index(SearchData model) přidejte do parametrů hledání následující řádek.
options.OrderBy.Add("Rating desc");Poznámka:
Výchozí pořadí je vzestupné, ale můžete ho přidat
ascdo vlastnosti, aby bylo jasné. Sestupné pořadí je určeno přidánímdesc.Teď spusťte aplikaci a zadejte libovolný běžný hledaný termín. Výsledky mohou nebo nemusí být ve správném pořadí, protože ani vy jako vývojář, ne uživatel, nemáte snadný způsob ověření výsledků!
Pojďme se ujistit, že výsledky jsou seřazené podle hodnocení. Nejprve nahraďte třídy box1 a box2 v souboru hotels.css následujícími třídami (tyto třídy jsou všechny nové, které pro tento kurz potřebujeme).
textarea.box1A { width: 324px; height: 32px; border: none; background-color: azure; font-size: 14pt; color: blue; padding-left: 5px; text-align: left; } textarea.box1B { width: 324px; height: 32px; border: none; background-color: azure; font-size: 14pt; color: blue; text-align: right; padding-right: 5px; } textarea.box2A { width: 324px; height: 32px; border: none; background-color: azure; font-size: 12pt; color: blue; padding-left: 5px; text-align: left; } textarea.box2B { width: 324px; height: 32px; border: none; background-color: azure; font-size: 12pt; color: blue; text-align: right; padding-right: 5px; } textarea.box3 { width: 648px; height: 100px; border: none; background-color: azure; font-size: 12pt; padding-left: 5px; margin-bottom: 24px; }Návod
Prohlížeče obvykle ukládají soubory css do mezipaměti, což může vést k tomu, že se používá starý soubor CSS a vaše úpravy budou ignorovány. Dobrým způsobem, jak to vyřešit, je přidat k odkazu dotazový řetězec s parametrem verze. Například:
<link rel="stylesheet" href="~/css/hotels.css?v1.1" />Pokud si myslíte, že váš prohlížeč používá starý soubor CSS, aktualizujte číslo verze.
Do parametru Select v metodě Index(SearchData model) přidejte vlastnost Rating, aby výsledky obsahovaly následující tři pole:
options.Select.Add("HotelName"); options.Select.Add("Description"); options.Select.Add("Rating");Otevřete zobrazení (index.cshtml) a nahraďte smyčku vykreslování (<-- Zobrazit data hotelu. -->) následujícím kódem.
<!-- Show the hotel data. --> @for (var i = 0; i < result.Count; i++) { var ratingText = $"Rating: {result[i].Document.Rating}"; // Display the hotel details. @Html.TextArea($"name{i}", result[i].Document.HotelName, new { @class = "box1A" }) @Html.TextArea($"rating{i}", ratingText, new { @class = "box1B" }) @Html.TextArea($"desc{i}", fullDescription, new { @class = "box3" }) }Ohodnocení musí být k dispozici jak na první zobrazené stránce, tak i na dalších stránkách, které se volají prostřednictvím nekonečného rolování. Pro druhou z těchto dvou situací musíme aktualizovat Next v kontroleru a scrolled v zobrazení. Počínaje kontrolerem změňte metodu Next na následující kód. Tento kód vytvoří a sdělí text hodnocení.
public async Task<ActionResult> Next(SearchData model) { // Set the next page setting, and call the Index(model) action. model.paging = "next"; await Index(model); // Create an empty list. var nextHotels = new List<string>(); // Add a hotel details to the list. await foreach (var result in model.resultList.GetResultsAsync()) { var ratingText = $"Rating: {result.Document.Rating}"; var rateText = $"Rates from ${result.Document.cheapest} to ${result.Document.expensive}"; string fullDescription = result.Document.Description; // Add strings to the list. nextHotels.Add(result.Document.HotelName); nextHotels.Add(ratingText); nextHotels.Add(fullDescription); } // Rather than return a view, return the list of data. return new JsonResult(nextHotels); }Teď aktualizujte posunovanou funkci v zobrazení, aby se zobrazil text hodnocení.
<script> function scrolled() { if (myDiv.offsetHeight + myDiv.scrollTop >= myDiv.scrollHeight) { $.getJSON("/Home/Next", function (data) { var div = document.getElementById('myDiv'); // Append the returned data to the current list of hotels. for (var i = 0; i < data.length; i += 3) { div.innerHTML += '\n<textarea class="box1A">' + data[i] + '</textarea>'; div.innerHTML += '\n<textarea class="box1B">' + data[i + 1] + '</textarea>'; div.innerHTML += '\n<textarea class="box3">' + data[i + 2] + '</textarea>'; } }); } } </script>Teď aplikaci spusťte znovu. Vyhledejte jakýkoli běžný termín, například "wifi", a ověřte, že výsledky jsou seřazené sestupně podle hodnocení hotelů.
Všimnete si, že několik hotelů má stejné hodnocení, a proto jejich vzhled v zobrazení je opět pořadí, ve kterém jsou nalezena data, což je libovolné.
Než se podíváme na přidání druhé úrovně seřazení, přidejme kód na zobrazení rozsahu cen místností. Tento kód přidáváme k zobrazení extrahování dat z komplexního typu a také proto, abychom mohli probrat řazení výsledků na základě ceny (nejlevnější možná jako první).
Přidání rozsahu cen pokojů do zobrazení
Přidejte do modelu Hotel.cs vlastnosti obsahující nejlevnější a nejdražší cenu za pokoj.
// Room rate range public double cheapest { get; set; } public double expensive { get; set; }Vypočítejte ceny za pokoje na konci akce Index (model SearchData) v domovském řadiči. Přidejte výpočty po uložení dočasných dat.
// Ensure TempData is stored for the next call. TempData["page"] = page; TempData["searchfor"] = model.searchText; // Calculate the room rate ranges. await foreach (var result in model.resultList.GetResultsAsync()) { var cheapest = 0d; var expensive = 0d; foreach (var room in result.Document.Rooms) { var rate = room.BaseRate; if (rate < cheapest || cheapest == 0) { cheapest = (double)rate; } if (rate > expensive) { expensive = (double)rate; } } model.resultList.Results[n].Document.cheapest = cheapest; model.resultList.Results[n].Document.expensive = expensive; }Přidejte vlastnost Rooms do parametru Select v metodě akce Index(SearchData model) kontroleru.
options.Select.Add("Rooms");Změňte smyčku vykreslování v zobrazení tak, aby zobrazovala rozsah rychlosti pro první stránku výsledků.
<!-- Show the hotel data. --> @for (var i = 0; i < result.Count; i++) { var rateText = $"Rates from ${result[i].Document.cheapest} to ${result[i].Document.expensive}"; var ratingText = $"Rating: {result[i].Document.Rating}"; string fullDescription = result[i].Document.Description; // Display the hotel details. @Html.TextArea($"name{i}", result[i].Document.HotelName, new { @class = "box1A" }) @Html.TextArea($"rating{i}", ratingText, new { @class = "box1B" }) @Html.TextArea($"rates{i}", rateText, new { @class = "box2A" }) @Html.TextArea($"desc{i}", fullDescription, new { @class = "box3" }) }Změňte metodu Next v domovském kontroleru, aby komunikovala rozsah sazeb pro další stránky výsledků.
public async Task<ActionResult> Next(SearchData model) { // Set the next page setting, and call the Index(model) action. model.paging = "next"; await Index(model); // Create an empty list. var nextHotels = new List<string>(); // Add a hotel details to the list. await foreach (var result in model.resultList.GetResultsAsync()) { var ratingText = $"Rating: {result.Document.Rating}"; var rateText = $"Rates from ${result.Document.cheapest} to ${result.Document.expensive}"; string fullDescription = result.Document.Description; // Add strings to the list. nextHotels.Add(result.Document.HotelName); nextHotels.Add(ratingText); nextHotels.Add(rateText); nextHotels.Add(fullDescription); } // Rather than return a view, return the list of data. return new JsonResult(nextHotels); }Aktualizujte scrollovanou funkci v zobrazení, aby zpracovala text ceny pokojů.
<script> function scrolled() { if (myDiv.offsetHeight + myDiv.scrollTop >= myDiv.scrollHeight) { $.getJSON("/Home/Next", function (data) { var div = document.getElementById('myDiv'); // Append the returned data to the current list of hotels. for (var i = 0; i < data.length; i += 4) { div.innerHTML += '\n<textarea class="box1A">' + data[i] + '</textarea>'; div.innerHTML += '\n<textarea class="box1B">' + data[i + 1] + '</textarea>'; div.innerHTML += '\n<textarea class="box2A">' + data[i + 2] + '</textarea>'; div.innerHTML += '\n<textarea class="box3">' + data[i + 4] + '</textarea>'; } }); } } </script>Spusťte aplikaci a ověřte, že se zobrazují cenová rozmezí pokojů.
Vlastnost OrderBy parametrů hledání nepřijímá položku, jako je Rooms.BaseRate , aby poskytovala nejlevnější sazbu pokoje, i když byly pokoje již seřazeny podle sazby. V takovém případě nejsou pokoje seřazené podle sazby. Pokud chcete zobrazit hotely v ukázkové sadě dat seřazené podle ceny místnosti, museli byste výsledky seřadit ve svém domovském ovladači a odeslat tyto výsledky do zobrazení v požadovaném pořadí.
Seřazení výsledků na základě více hodnot
Otázkou je, jak rozlišovat mezi hotely se stejným hodnocením. Jedním z přístupů může být sekundární objednávání založené na posledním období, kdy byl hotel rekonstruován, takže nedávno rekonstruované hotely se zdají být vyšší ve výsledcích.
Pokud chcete přidat druhou úroveň řazení, přidejte LastRenovationDate do výsledků hledání a OrderBy v metodě Index(SearchData model) .
options.Select.Add("LastRenovationDate"); options.OrderBy.Add("LastRenovationDate desc");Návod
Do seznamu OrderBy lze zadat libovolný počet vlastností. Pokud hotely měly stejné hodnocení a datum renovace, může být zadána třetí nemovitost, aby bylo možné rozlišovat mezi nimi.
Opět potřebujeme vidět datum renovace v zobrazení, jen abychom si byli jistí, že objednávka je správná. Pro takovou věc jako renovace, pravděpodobně jen rok je dostačující. Změňte smyčku vykreslování v zobrazení na následující kód.
<!-- Show the hotel data. --> @for (var i = 0; i < result.Count; i++) { var rateText = $"Rates from ${result[i].Document.cheapest} to ${result[i].Document.expensive}"; var lastRenovatedText = $"Last renovated: { result[i].Document.LastRenovationDate.Value.Year}"; var ratingText = $"Rating: {result[i].Document.Rating}"; string fullDescription = result[i].Document.Description; // Display the hotel details. @Html.TextArea($"name{i}", result[i].Document.HotelName, new { @class = "box1A" }) @Html.TextArea($"rating{i}", ratingText, new { @class = "box1B" }) @Html.TextArea($"rates{i}", rateText, new { @class = "box2A" }) @Html.TextArea($"renovation{i}", lastRenovatedText, new { @class = "box2B" }) @Html.TextArea($"desc{i}", fullDescription, new { @class = "box3" }) }Změňte metodu Next na domovském ovladači tak, aby předála rok součásti posledního data renovace.
public async Task<ActionResult> Next(SearchData model) { // Set the next page setting, and call the Index(model) action. model.paging = "next"; await Index(model); // Create an empty list. var nextHotels = new List<string>(); // Add a hotel details to the list. await foreach (var result in model.resultList.GetResultsAsync()) { var ratingText = $"Rating: {result.Document.Rating}"; var rateText = $"Rates from ${result.Document.cheapest} to ${result.Document.expensive}"; var lastRenovatedText = $"Last renovated: {result.Document.LastRenovationDate.Value.Year}"; string fullDescription = result.Document.Description; // Add strings to the list. nextHotels.Add(result.Document.HotelName); nextHotels.Add(ratingText); nextHotels.Add(rateText); nextHotels.Add(lastRenovatedText); nextHotels.Add(fullDescription); } // Rather than return a view, return the list of data. return new JsonResult(nextHotels); }Změňte posunenou funkci v zobrazení tak, aby se zobrazil text renovace.
<script> function scrolled() { if (myDiv.offsetHeight + myDiv.scrollTop >= myDiv.scrollHeight) { $.getJSON("/Home/Next", function (data) { var div = document.getElementById('myDiv'); // Append the returned data to the current list of hotels. for (var i = 0; i < data.length; i += 5) { div.innerHTML += '\n<textarea class="box1A">' + data[i] + '</textarea>'; div.innerHTML += '\n<textarea class="box1B">' + data[i + 1] + '</textarea>'; div.innerHTML += '\n<textarea class="box2A">' + data[i + 2] + '</textarea>'; div.innerHTML += '\n<textarea class="box2B">' + data[i + 3] + '</textarea>'; div.innerHTML += '\n<textarea class="box3">' + data[i + 4] + '</textarea>'; } }); } } </script>Spustit aplikaci. Vyhledejte běžný termín, například "bazén" nebo "view", a ověřte, jestli se teď hotely se stejným hodnocením zobrazují sestupně v sestupném pořadí data renovace.
Seřazení výsledků na základě hodnoticího profilu
Příklady uvedené v tomto kurzu zatím ukazují, jak uspořádat číselné hodnoty (datum hodnocení a renovace), které poskytují přesnou posloupnost objednávek. Některá hledání a některá data se ale nevyrovnají tak snadnému porovnání mezi dvěma datovými prvky. Pro dotazy fulltextového vyhledávání zahrnuje Cognitive Search koncept řazení. Profily bodování lze zadat tak, aby ovlivnily pořadí výsledků a poskytovaly složitější a kvalitativní porovnání.
Profily bodování jsou definovány ve schématu indexu. Pro data hotelů bylo nastaveno několik profilů bodování. Pojďme se podívat, jak je definovaný bodovací profil, a zkuste na ně napsat kód pro vyhledávání.
Jak jsou definovány hodnoticí profily
Profily bodování jsou definovány v indexu vyhledávání v době návrhu. Index hotelů jen pro čtení hostovaný Microsoftem má tři profily bodování. V této části se seznámíte s profily bodování a dozvíte se, jak používat kód.
Níže je výchozí profil bodování pro datovou sadu hotelů, který se používá, když nezadáte žádný parametr OrderBy nebo ScoringProfile . Tento profil zvýší skóre pro hotel, pokud je hledaný text v názvu hotelu, popisu nebo seznamu značek (vybavení). Všimněte si, jak váhy bodování upřednostňují určitá pole. Pokud se hledaný text zobrazí v jiném poli, které není uvedené níže, bude mít váhu 1. Samozřejmě, čím vyšší je skóre, tím výše se ve zobrazení objeví výsledek.
{ "name": "boostByField", "text": { "weights": { "Tags": 3, "HotelName": 2, "Description": 1.5, "Description_fr": 1.5, } } }Následující alternativní bodovací profil výrazně zvýší skóre, pokud zadaný parametr obsahuje jeden či více ze seznamu štítků (které nazýváme "vybavení"). Klíčovým bodem tohoto profilu je, že musí být zadán parametr obsahující text. Pokud je parametr prázdný nebo není zadaný, vyvolá se chyba.
{ "name":"boostAmenities", "functions":[ { "fieldName":"Tags", "freshness":null, "interpolation":"linear", "magnitude":null, "distance":null, "tag":{ "tagsParameter":"amenities" }, "type":"tag", "boost":5 } ], "functionAggregation":0 },V tomto třetím profilu hodnocení hotelu výrazně zvýší skóre. Poslední renovované datum také zvýší skóre, ale pouze v případě, že tato data spadají do 730 dnů (2 roky) aktuálního data.
{ "name":"renovatedAndHighlyRated", "functions":[ { "fieldName":"Rating", "freshness":null, "interpolation":"linear", "magnitude":{ "boostingRangeStart":0, "boostingRangeEnd":5, "constantBoostBeyondRange":false }, "distance":null, "tag":null, "type":"magnitude", "boost":20 }, { "fieldName":"LastRenovationDate", "freshness":{ "boostingDuration":"P730D" }, "interpolation":"quadratic", "magnitude":null, "distance":null, "tag":null, "type":"freshness", "boost":10 } ], "functionAggregation":0 }Teď se podívejme, jestli tyto profily fungují tak, jak si myslíme, že by měly.
Přidání kódu do zobrazení pro porovnání profilů
Otevřete soubor index.cshtml a nahraďte <část textu> následujícím kódem.
<body> @using (Html.BeginForm("Index", "Home", FormMethod.Post)) { <table> <tr> <td></td> <td> <h1 class="sampleTitle"> <img src="~/images/azure-logo.png" width="80" /> Hotels Search - Order Results </h1> </td> </tr> <tr> <td></td> <td> <!-- 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> <div class="searchBoxForm"> <b> Order: </b> @Html.RadioButtonFor(m => m.scoring, "Default") Default @Html.RadioButtonFor(m => m.scoring, "RatingRenovation") By numerical Rating @Html.RadioButtonFor(m => m.scoring, "boostAmenities") By Amenities @Html.RadioButtonFor(m => m.scoring, "renovatedAndHighlyRated") By Renovated date/Rating profile </div> </td> </tr> <tr> <td valign="top"> <div id="facetplace" class="facetchecks"> @if (Model != null && Model.facetText != null) { <h5 class="facetheader">Amenities:</h5> <ul class="facetlist"> @for (var c = 0; c < Model.facetText.Length; c++) { <li> @Html.CheckBoxFor(m => m.facetOn[c], new { @id = "check" + c.ToString() }) @Model.facetText[c] </li> } </ul> } </div> </td> <td> @if (Model != null && Model.resultList != null) { // Show the total result count. <p class="sampleText"> @Html.DisplayFor(m => m.resultList.Count) Results <br /> </p> <div id="myDiv" style="width: 800px; height: 450px; overflow-y: scroll;" onscroll="scrolled()"> <!-- Show the hotel data. --> @for (var i = 0; i < Model.resultList.Results.Count; i++) { var rateText = $"Rates from ${Model.resultList.Results[i].Document.cheapest} to ${Model.resultList.Results[i].Document.expensive}"; var lastRenovatedText = $"Last renovated: { Model.resultList.Results[i].Document.LastRenovationDate.Value.Year}"; var ratingText = $"Rating: {Model.resultList.Results[i].Document.Rating}"; string amenities = string.Join(", ", Model.resultList.Results[i].Document.Tags); string fullDescription = Model.resultList.Results[i].Document.Description; fullDescription += $"\nAmenities: {amenities}"; // Display the hotel details. @Html.TextArea($"name{i}", Model.resultList.Results[i].Document.HotelName, new { @class = "box1A" }) @Html.TextArea($"rating{i}", ratingText, new { @class = "box1B" }) @Html.TextArea($"rates{i}", rateText, new { @class = "box2A" }) @Html.TextArea($"renovation{i}", lastRenovatedText, new { @class = "box2B" }) @Html.TextArea($"desc{i}", fullDescription, new { @class = "box3" }) } </div> <script> function scrolled() { if (myDiv.offsetHeight + myDiv.scrollTop >= myDiv.scrollHeight) { $.getJSON("/Home/Next", function (data) { var div = document.getElementById('myDiv'); // Append the returned data to the current list of hotels. for (var i = 0; i < data.length; i += 5) { div.innerHTML += '\n<textarea class="box1A">' + data[i] + '</textarea>'; div.innerHTML += '<textarea class="box1B">' + data[i + 1] + '</textarea>'; div.innerHTML += '\n<textarea class="box2A">' + data[i + 2] + '</textarea>'; div.innerHTML += '<textarea class="box2B">' + data[i + 3] + '</textarea>'; div.innerHTML += '\n<textarea class="box3">' + data[i + 4] + '</textarea>'; } }); } } </script> } </td> </tr> </table> } </body>Otevřete soubor SearchData.cs a nahraďte třídu SearchData následujícím kódem.
public class SearchData { public SearchData() { } // Constructor to initialize the list of facets sent from the controller. public SearchData(List<string> facets) { facetText = new string[facets.Count]; for (int i = 0; i < facets.Count; i++) { facetText[i] = facets[i]; } } // Array to hold the text for each amenity. public string[] facetText { get; set; } // Array to hold the setting for each amenitity. public bool[] facetOn { get; set; } // The text to search for. public string searchText { get; set; } // Record if the next page is requested. public string paging { get; set; } // The list of results. public DocumentSearchResult<Hotel> resultList; public string scoring { get; set; } }Otevřete soubor hotels.css a přidejte následující třídy HTML.
.facetlist { list-style: none; } .facetchecks { width: 250px; display: normal; color: #666; margin: 10px; padding: 5px; } .facetheader { font-size: 10pt; font-weight: bold; color: darkgreen; }
Přidání kódu do kontroleru pro určení hodnoticího profilu
Otevřete soubor domovského kontroleru. Přidejte následující příkaz using (který vám pomůže s vytvářením seznamů).
using System.Linq;V tomto příkladu potřebujeme počáteční volání indexu , aby se provedlo něco víc, než jen vrácení počátečního zobrazení. Metoda teď hledá až 20 vybavení, které se zobrazí v zobrazení.
public async Task<ActionResult> Index() { InitSearch(); // Set up the facets call in the search parameters. SearchOptions options = new SearchOptions(); // Search for up to 20 amenities. options.Facets.Add("Tags,count:20"); SearchResults<Hotel> searchResult = await _searchClient.SearchAsync<Hotel>("*", options); // Convert the results to a list that can be displayed in the client. List<string> facets = searchResult.Facets["Tags"].Select(x => x.Value.ToString()).ToList(); // Initiate a model with a list of facets for the first view. SearchData model = new SearchData(facets); // Save the facet text for the next view. SaveFacets(model, false); // Render the view including the facets. return View(model); }Potřebujeme dvě privátní metody pro uložení facetů do dočasného úložiště, jejich obnovu z něj a naplnění modelu.
// Save the facet text to temporary storage, optionally saving the state of the check boxes. private void SaveFacets(SearchData model, bool saveChecks = false) { for (int i = 0; i < model.facetText.Length; i++) { TempData["facet" + i.ToString()] = model.facetText[i]; if (saveChecks) { TempData["faceton" + i.ToString()] = model.facetOn[i]; } } TempData["facetcount"] = model.facetText.Length; } // Recover the facet text to a model, optionally recoving the state of the check boxes. private void RecoverFacets(SearchData model, bool recoverChecks = false) { // Create arrays of the appropriate length. model.facetText = new string[(int)TempData["facetcount"]]; if (recoverChecks) { model.facetOn = new bool[(int)TempData["facetcount"]]; } for (int i = 0; i < (int)TempData["facetcount"]; i++) { model.facetText[i] = TempData["facet" + i.ToString()].ToString(); if (recoverChecks) { model.facetOn[i] = (bool)TempData["faceton" + i.ToString()]; } } }Podle potřeby musíme nastavit parametry OrderBy a ScoringProfile . Nahraďte existující metodu Index(SearchData model) následujícím kódem.
public async Task<ActionResult> Index(SearchData model) { try { InitSearch(); int page; if (model.paging != null && model.paging == "next") { // Recover the facet text, and the facet check box settings. RecoverFacets(model, true); // Increment the page. page = (int)TempData["page"] + 1; // Recover the search text. model.searchText = TempData["searchfor"].ToString(); } else { // First search with text. // Recover the facet text, but ignore the check box settings, and use the current model settings. RecoverFacets(model, false); // First call. Check for valid text input, and valid scoring profile. if (model.searchText == null) { model.searchText = ""; } if (model.scoring == null) { model.scoring = "Default"; } page = 0; } // Setup the search parameters. var options = new SearchOptions { SearchMode = SearchMode.All, // Skip past results that have already been returned. Skip = page * GlobalVariables.ResultsPerPage, // Take only the next page worth of results. Size = GlobalVariables.ResultsPerPage, // Include the total number of results. IncludeTotalCount = true, }; // Select the data properties to be returned. options.Select.Add("HotelName"); options.Select.Add("Description"); options.Select.Add("Tags"); options.Select.Add("Rooms"); options.Select.Add("Rating"); options.Select.Add("LastRenovationDate"); List<string> parameters = new List<string>(); // Set the ordering based on the user's radio button selection. switch (model.scoring) { case "RatingRenovation": // Set the ordering/scoring parameters. options.OrderBy.Add("Rating desc"); options.OrderBy.Add("LastRenovationDate desc"); break; case "boostAmenities": { options.ScoringProfile = model.scoring; // Create a string list of amenities that have been clicked. for (int a = 0; a < model.facetOn.Length; a++) { if (model.facetOn[a]) { parameters.Add(model.facetText[a]); } } if (parameters.Count > 0) { options.ScoringParameters.Add($"amenities-{ string.Join(',', parameters)}"); } else { // No amenities selected, so set profile back to default. options.ScoringProfile = ""; } } break; case "renovatedAndHighlyRated": options.ScoringProfile = model.scoring; break; default: break; } // For efficiency, the search call should be asynchronous, so use SearchAsync rather than Search. model.resultList = await _searchClient.SearchAsync<Hotel>(model.searchText, options); // Ensure TempData is stored for the next call. TempData["page"] = page; TempData["searchfor"] = model.searchText; TempData["scoring"] = model.scoring; SaveFacets(model, true); // Calculate the room rate ranges. await foreach (var result in model.resultList.GetResultsAsync()) { var cheapest = 0d; var expensive = 0d; foreach (var room in result.Document.Rooms) { var rate = room.BaseRate; if (rate < cheapest || cheapest == 0) { cheapest = (double)rate; } if (rate > expensive) { expensive = (double)rate; } } result.Document.cheapest = cheapest; result.Document.expensive = expensive; } } catch { return View("Error", new ErrorViewModel { RequestId = "1" }); } return View("Index", model); }Přečtěte si komentáře pro každý výběr přepínače .
Pokud jste dokončili další kód předchozí části pro řazení na základě více vlastností, nemusíme provádět žádné změny akce Další .
Spuštění a otestování aplikace
Spustit aplikaci. Měli byste vidět celou sadu vybavení na displeji.
Pro řazení vám výběr možnosti "Podle číselného hodnocení" poskytne numerické pořadí, které jste již v tomto kurzu implementovali, přičemž rozhodujícím faktorem mezi hotely se stejným hodnocením je datum renovace.
Teď vyzkoušejte profil "Podle vybavení". Vyberte různé vybavení a ověřte, že hotely s těmito vybaveními jsou upřednostněny v seznamu výsledků.
Vyzkoušejte "podle data rekonstrukce/profily hodnocení", abyste zjistili, zda získáte očekávané výsledky. Teprve nedávno zrekonstruované hotely by měly získat čerstvost .
Prostředky
Další informace najdete v následujícím dokumentu Přidání profilů bodování do indexu služby Azure Cognitive Search.
Klíčové poznatky
Vezměte v úvahu následující poznatky z tohoto projektu:
- Uživatelé budou očekávat, že se výsledky hledání budou řadit, nejrelevantnější nejprve.
- Data jsou strukturovaná tak, aby řazení bylo snadné. Nemohli jsme snadno řadit podle "nejlevnějších" na první místo, protože data nejsou strukturovaná tak, aby umožňovala řazení bez použití dalšího kódu.
- Řazení může mít mnoho úrovní, aby bylo možné rozlišovat mezi výsledky, které mají stejnou hodnotu na vyšší úrovni řazení.
- Některé výsledky se dají řadit vzestupně (například vzdálenost od bodu) a některé v sestupném pořadí (například hodnocení hostů).
- Profily bodování je možné definovat, pokud číselné porovnání nejsou k dispozici nebo nejsou dostatečně inteligentní, pro datovou sadu. Vyhodnocení každého výsledku vám pomůže uspořádat a zobrazit výsledky inteligentně.
Další kroky
Dokončili jste tuto řadu kurzů jazyka C# – měli byste získat cenné znalosti o rozhraních API služby Azure Cognitive Search.
Další reference a kurzy najdete v dokumentaci ke službě Azure Cognitive Search v katalogu školení Microsoft Learn nebo v dalších kurzech.