Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In dieser Lernprogrammreihe wurden Ergebnisse zurückgegeben und in einer Standardreihenfolge angezeigt. In diesem Lernprogramm fügen Sie primäre und sekundäre Sortierkriterien hinzu. Als Alternative zur Sortierung basierend auf numerischen Werten zeigt das letzte Beispiel, wie Ergebnisse basierend auf einem benutzerdefinierten Bewertungsprofil bewertet werden. Wir werden auch etwas tiefer in die Anzeige komplexer Typen gehen.
In diesem Tutorial lernen Sie Folgendes:
- Sortieren von Ergebnissen basierend auf einer Eigenschaft
- Sortieren von Ergebnissen basierend auf mehreren Eigenschaften
- Sortieren von Ergebnissen basierend auf einem Bewertungsprofil
Überblick
Dieses Lernprogramm erweitert das Projekt für unendliches Scrollen, das im Lernprogramm 'Paging zu Suchergebnissen hinzufügen' erstellt wurde.
Eine fertige Version des Codes in diesem Tutorial finden Sie im folgenden Projekt:
Voraussetzungen
- 2b-add-infinite-scroll (GitHub)- Lösung. Dieses Projekt kann entweder Ihre eigene Version sein, die aus dem vorherigen Lernprogramm erstellt wurde, oder eine Kopie von GitHub.
Sortieren von Ergebnissen basierend auf einer Eigenschaft
Bei der Bestellung von Ergebnissen basierend auf einer Immobilie, z. B. hotelbewertung, möchten wir nicht nur die bestellten Ergebnisse, wir möchten auch bestätigen, dass die Bestellung korrekt ist. Wenn Sie das Feld "Bewertung" zu den Ergebnissen hinzufügen, können wir bestätigen, dass die Ergebnisse richtig sortiert sind.
In dieser Übung werden wir auch ein bisschen mehr zur Anzeige der Ergebnisse hinzufügen: die billigste Zimmerrate und den teuersten Zimmerpreis für jedes Hotel.
Es ist nicht erforderlich, eines der Modelle zu ändern, um die Sortierung zu aktivieren. Nur die Ansicht und der Controller erfordern Updates. Öffnen Sie zunächst den Home-Controller.
Hinzufügen der OrderBy-Eigenschaft zu den Suchparametern
Fügen Sie in HomeController.cs die Option "OrderBy " hinzu, und fügen Sie die Eigenschaft "Rating" mit einer absteigenden Sortierreihenfolge hinzu. Fügen Sie in der Methode Index(SearchData-Modell) die folgende Zeile zu den Suchparametern hinzu.
options.OrderBy.Add("Rating desc");
Hinweis
Die Standardreihenfolge ist aufsteigend, aber Sie können der Eigenschaft hinzufügen
asc
, um dies klar zu machen. Absteigende Reihenfolge wird durch Hinzufügendesc
angegeben.Führen Sie nun die App aus, und geben Sie einen beliebigen allgemeinen Suchbegriff ein. Die Ergebnisse können oder nicht in der richtigen Reihenfolge sein, da weder Sie als Entwickler noch der Benutzer eine einfache Möglichkeit haben, die Ergebnisse zu überprüfen!
Lassen Sie uns klarstellen, dass die Ergebnisse nach der Bewertung sortiert sind. Ersetzen Sie zunächst die Klassen box1 und box2 in der datei hotels.css durch die folgenden Klassen (diese Klassen sind alle neuen Klassen, die wir für dieses Lernprogramm benötigen).
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; }
Tipp
Browser speichern css-Dateien in der Regel zwischen, und dies kann zu einer alten CSS-Datei führen, die verwendet wird, und Ihre Bearbeitungen werden ignoriert. Eine gute Möglichkeit besteht darin, eine Abfragezeichenfolge mit einem Versionsparameter zum Link hinzuzufügen. Beispiel:
<link rel="stylesheet" href="~/css/hotels.css?v1.1" />
Aktualisieren Sie die Versionsnummer, wenn Sie glauben, dass eine alte CSS-Datei von Ihrem Browser verwendet wird.
Fügen Sie die Rating-Eigenschaft zum Select-Parameter in der Methode Index(SearchData-Modell) hinzu, sodass die Ergebnisse die folgenden drei Felder enthalten:
options.Select.Add("HotelName"); options.Select.Add("Description"); options.Select.Add("Rating");
Öffnen Sie die Ansicht (index.cshtml), und ersetzen Sie die Renderingschleife (<-- Hoteldaten anzeigen. -->) durch den folgenden Code.
<!-- 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" }) }
Die Bewertung muss sowohl auf der ersten angezeigten Seite als auch auf den nachfolgenden Seiten verfügbar sein, die durch den unendlichen Bildlauf aufgerufen werden. Für die letztere dieser beiden Situationen müssen wir sowohl die Weiter-Aktion im Controller als auch die Scrolled-Funktion in der Ansicht aktualisieren. Ändern Sie beginnend mit dem Controller die Next-Methode in den folgenden Code. Dieser Code erstellt und kommuniziert den Bewertungstext.
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); }
Aktualisieren Sie nun die scrolled-Funktion im View, um den Bewertungstext anzuzeigen.
<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>
Führen Sie nun die App erneut aus. Suchen Sie nach einem beliebigen gängigen Begriff, z. B. "WIFI", und überprüfen Sie, ob die Ergebnisse nach absteigender Reihenfolge der Hotelbewertung sortiert werden.
Sie werden feststellen, dass mehrere Hotels eine identische Bewertung haben, und ihre Darstellung in der Anzeige ist also wieder die Reihenfolge, in der die Daten gefunden werden, was willkürlich ist.
Bevor wir uns mit dem Hinzufügen einer zweiten Ebene der Sortierung befassen, fügen wir Code hinzu, um den Bereich der Raumpreise anzuzeigen. Wir fügen diesen Code hinzu, um sowohl das Extrahieren von Daten aus einem komplexen Typ anzuzeigen, als auch, damit wir die Bestellergebnisse basierend auf dem Preis besprechen können (am günstigsten zuerst vielleicht).
Fügen Sie den Bereich der Zimmerpreise zur Anzeige hinzu
Fügen Sie dem Hotel.cs-Modell Eigenschaften hinzu, die den günstigsten und teuersten Zimmerpreis enthalten.
// Room rate range public double cheapest { get; set; } public double expensive { get; set; }
Berechnen Sie die Raumpreise am Ende der Index-Aktion (SearchData-Modell) im Heimcontroller. Fügen Sie die Berechnungen nach dem Speichern temporärer Daten hinzu.
// 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; }
Fügen Sie die Rooms-Eigenschaft zum Select-Parameter in der Aktionsmethode Index(SearchData-Modell) des Controllers hinzu.
options.Select.Add("Rooms");
Ändern Sie die Renderingschleife in der Ansicht, um den Ratebereich für die erste Seite der Ergebnisse anzuzeigen.
<!-- 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" }) }
Ändern Sie die Next-Methode im Home-Controller, um den Zinsbereich für nachfolgende Seiten von Ergebnissen zu kommunizieren.
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); }
Aktualisieren Sie die Scroll-Funktion in der Ansicht, um den Raumpreistext zu verarbeiten.
<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>
Führen Sie die App aus, und überprüfen Sie, ob die Raumratebereiche angezeigt werden.
Die OrderBy-Eigenschaft der Suchparameter akzeptiert keinen Eintrag wie "Rooms.BaseRate ", um den günstigsten Zimmertarif bereitzustellen, auch wenn die Zimmer bereits zum Preis sortiert wurden. In diesem Fall werden die Räume nicht nach Rate sortiert. Um Hotels im Beispieldatensatz anzuzeigen, sortiert nach Raumrate, müssten Sie die Ergebnisse in Ihrem Heimcontroller sortieren und diese Ergebnisse in der gewünschten Reihenfolge an die Ansicht senden.
Sortieren von Ergebnissen basierend auf mehreren Werten
Die Frage ist nun, wie man zwischen Hotels mit der gleichen Bewertung unterscheidet. Ein Ansatz könnte eine sekundäre Sortierung sein, basierend auf der letzten Renovierung des Hotels, so dass kürzlich renovierte Hotels in den Ergebnissen höher erscheinen.
Um eine zweite Sortierebene hinzuzufügen, fügen Sie LastRenovationDate zu den Suchergebnissen und zu OrderBy in der Index(SearchData-Modell)- Methode hinzu.
options.Select.Add("LastRenovationDate"); options.OrderBy.Add("LastRenovationDate desc");
Tipp
Eine beliebige Anzahl von Eigenschaften kann in die OrderBy-Liste eingegeben werden. Wenn Hotels dasselbe Bewertungs- und Renovierungsdatum hatten, könnte eine dritte Immobilie eingegeben werden, um zwischen ihnen zu unterscheiden.
Auch hier müssen wir das Renovierungsdatum in der Ansicht sehen, nur um sicher zu sein, dass die Bestellung korrekt ist. Für so etwas wie eine Renovierung reicht wahrscheinlich nur das Jahr aus. Ändern Sie die Renderingschleife in der Ansicht in den folgenden Code.
<!-- 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" }) }
Ändern Sie die Nächste Methode im Hauscontroller, um die Jahreskomponente des letzten Renovierungsdatums weiterzuleiten.
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); }
Ändern Sie die Funktion für das Scrollen in der Ansicht, um den Renovierungstext anzuzeigen.
<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>
Führen Sie die App aus. Suchen Sie nach einem gemeinsamen Begriff, z. B. "Pool" oder "Ansicht", und überprüfen Sie, ob Hotels mit derselben Bewertung jetzt in absteigender Reihenfolge des Renovierungsdatums angezeigt werden.
Sortieren von Ergebnissen basierend auf einem Bewertungsprofil
Die im Tutorial gegebenen Beispiele zeigen, wie man nach numerischen Werten (Bewertung und Renovierungsdatum) ordnet und eine genaue Reihenfolge angibt. Einige Suchvorgänge und einige Daten eignen sich jedoch nicht für einen so einfachen Vergleich zwischen zwei Datenelementen. Bei Volltext-Suchabfragen enthält cognitive Search das Konzept der Rangfolge. Bewertungsprofile können angegeben werden, um zu beeinflussen, wie Ergebnisse bewertet werden, was komplexere und qualitative Vergleiche ermöglicht.
Bewertungsprofile werden im Indexschema definiert. Es wurden mehrere Bewertungsprofile für die Hoteldaten eingerichtet. Sehen wir uns an, wie ein Bewertungsprofil definiert ist, und versuchen Sie dann, Code zu schreiben, um nach ihnen zu suchen.
Wie Bewertungsprofile definiert werden
Bewertungsprofile werden zur Entwurfszeit in einem Suchindex definiert. Der schreibgeschützte Hotelindex, der von Microsoft gehostet wird, verfügt über drei Bewertungsprofile. In diesem Abschnitt werden die Bewertungsprofile erläutert und gezeigt, wie Sie den Code verwenden.
Unten sehen Sie das Standardbewertungsprofil für die Hotelsdatensätze, die verwendet werden, wenn Sie keinen Parameter "OrderBy" oder "ScoringProfile " angeben. Dieses Profil erhöht die Bewertung für ein Hotel, wenn der Suchtext im Hotelnamen, der Beschreibung oder der Liste der Tags (Annehmlichkeiten) vorhanden ist. Beachten Sie, wie die Gewichtungen der Bewertung bestimmte Felder bevorzugen. Wenn der Suchtext in einem anderen Feld angezeigt wird, nicht unten aufgeführt, hat er eine Gewichtung von 1. Offensichtlich gilt: Je höher die Bewertung, desto höher erscheint ein Ergebnis in der Anzeige.
{ "name": "boostByField", "text": { "weights": { "Tags": 3, "HotelName": 2, "Description": 1.5, "Description_fr": 1.5, } } }
Das folgende alternative Bewertungsprofil erhöht die Bewertung erheblich, wenn ein bereitgestellter Parameter mindestens eine Liste der Tags enthält (die wir als "Annehmlichkeiten" bezeichnen). Der Hauptpunkt dieses Profils ist, dass ein Parameter angegeben werden muss , der Text enthält. Wenn der Parameter leer ist oder nicht angegeben wird, wird ein Fehler ausgelöst.
{ "name":"boostAmenities", "functions":[ { "fieldName":"Tags", "freshness":null, "interpolation":"linear", "magnitude":null, "distance":null, "tag":{ "tagsParameter":"amenities" }, "type":"tag", "boost":5 } ], "functionAggregation":0 },
In diesem dritten Profil gibt die Hotelbewertung einen signifikanten Schub für die Bewertung. Das letzte renovierte Datum erhöht auch die Bewertung, aber nur, wenn diese Daten innerhalb von 730 Tagen (2 Jahre) des aktuellen Datums fallen.
{ "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 }
Lassen Sie uns nun sehen, ob diese Profile funktionieren, wie wir denken, dass sie sollten.
Hinzufügen von Code zur Ansicht zum Vergleichen von Profilen
Öffnen Sie die Datei index.cshtml, und ersetzen Sie den <Textabschnitt> durch den folgenden Code.
<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>
Öffnen Sie die SearchData.cs Datei, und ersetzen Sie die SearchData-Klasse durch den folgenden Code.
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; } }
Öffnen Sie die hotels.css Datei, und fügen Sie die folgenden HTML-Klassen hinzu.
.facetlist { list-style: none; } .facetchecks { width: 250px; display: normal; color: #666; margin: 10px; padding: 5px; } .facetheader { font-size: 10pt; font-weight: bold; color: darkgreen; }
Hinzufügen von Code zum Controller zum Angeben eines Bewertungsprofils
Öffnen Sie die Datei des Home-Controllers. Fügen Sie die folgende using-Anweisung hinzu (um das Erstellen von Listen zu unterstützen).
using System.Linq;
In diesem Beispiel wird der anfängliche Aufruf von Index benötigt, um etwas mehr zu tun als nur die anfängliche Ansicht zurückzugeben. Die Methode sucht nun nach bis zu 20 Annehmlichkeiten, die in der Ansicht angezeigt werden sollen.
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); }
Wir benötigen zwei private Methoden, um die Facets im temporären Speicher zu speichern und sie aus dem temporären Speicher wiederherzustellen und ein Modell aufzufüllen.
// 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()]; } } }
Die Parameter "OrderBy " und "ScoringProfile " müssen bei Bedarf festgelegt werden. Ersetzen Sie die vorhandene Index(SearchData-Modell) -Methode durch Folgendes.
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); }
Lesen Sie die Kommentare zu jeder Schalterauswahl.
Wir müssen keine Änderungen an der Nächsten-Aktion vornehmen, wenn Sie den zusätzlichen Code für den vorherigen Abschnitt basierend auf der Sortierung basierend auf mehreren Eigenschaften abgeschlossen haben.
Ausführen und Testen der App
Führen Sie die App aus. In der Ansicht sollte ein vollständiges Set an Annehmlichkeiten angezeigt werden.
Für die Sortierung nach der Option "Nach numerischer Bewertung" erhalten Sie die numerische Sortierung, die Sie bereits in diesem Tutorial implementiert haben; bei gleichen Bewertungen entscheidet das Renovierungsdatum zwischen den Hotels.
Probieren Sie nun das Profil "Nach Annehmlichkeiten" aus. Wählen Sie verschiedene Annehmlichkeiten aus, und überprüfen Sie, ob Hotels mit diesen Annehmlichkeiten an die Spitze der Ergebnisliste gesetzt werden.
Probieren Sie das Profil "Nach renoviertem Datum oder Bewertung" aus, um zu sehen, ob Sie die Erwartungen erfüllen. Erst kürzlich renovierte Hotels sollten einen Frischeschub bekommen.
Ressourcen
Weitere Informationen finden Sie im folgenden Hinzufügen von Bewertungsprofilen zu einem Azure Cognitive Search-Index.
Erkenntnisse
Berücksichtigen Sie die folgenden Erkenntnisse aus diesem Projekt:
- Benutzer erwarten, dass die Suchergebnisse so sortiert sind, dass die relevantesten zuerst angezeigt werden.
- Die Daten müssen so strukturiert sein, dass die Sortierung einfach ist. Wir konnten nicht einfach nach "billigsten" sortieren, da die Daten nicht strukturiert sind, um die Sortierung ohne zusätzlichen Code zu ermöglichen.
- Es kann viele Ebenen zur Sortierung geben, um zwischen Ergebnissen zu unterscheiden, die denselben Wert auf einer höheren Sortierebene aufweisen.
- Es ist natürlich, dass einige Ergebnisse in aufsteigender Reihenfolge (z. B. Entfernung von einem Punkt) und einige in absteigender Reihenfolge (z. B. Bewertung des Gasts) sortiert werden.
- Bewertungsprofile können definiert werden, wenn numerische Vergleiche für einen Datensatz nicht verfügbar oder nicht intelligent genug sind. Die Bewertung jedes Ergebnisses trägt dazu bei, die Ergebnisse intelligent zu sortieren und anzuzeigen.
Nächste Schritte
Sie haben diese Reihe von C#-Lernprogrammen abgeschlossen – Sie sollten wertvolle Kenntnisse der Azure Cognitive Search-APIs gewonnen haben.
Weitere Informationen und Lernprogramme finden Sie im Microsoft Learn-Schulungskatalog oder in den anderen Lernprogrammen in der Dokumentation zur Azure Cognitive Search.