Sdílet prostřednictvím


Kurz: Řazení výsledků hledání pomocí sady .NET SDK

V rámci této série 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 seřadit výsledky na základě vlastního bodovacího profilu. Podíváme se také trochu hlouběji na zobrazení složitých typů.

V tomto kurzu se naučíte:

  • Řazení výsledků na základě jedné vlastnosti
  • Řazení výsledků na základě více vlastností
  • Řazení výsledků na základě bodovacího profilu

Přehled

Tento kurz rozšiřuje projekt nekonečného posouvání vytvořený v kurzu Přidání stránkování do výsledků hledání .

Dokončenou verzi kódu v tomto kurzu najdete v následujícím projektu:

Požadavky

Řazení výsledků na základě jedné vlastnosti

Při objednávání výsledků na základě jedné vlastnosti, jako je hodnocení hotelu, chceme nejen objednané výsledky, ale také potvrzení, že je objednávka správná. Přidání pole Hodnocení do výsledků nám umožní potvrdit, že výsledky jsou správně seřazené.

V tomto cvičení také přidáme o něco více k zobrazení výsledků: nejlevnější pokojovou sazbu a nejdražší pokojovou sazbu pro každý hotel.

Abyste umožnili řazení, není nutné upravovat žádný z modelů. Aktualizace vyžadují jenom zobrazení a kontroler. Začněte otevřením domácího ovladače.

Přidání vlastnosti OrderBy do parametrů hledání

  1. V souboru HomeController.cs přidejte možnost OrderBy a zahrňte vlastnost Rating se sestupným pořadím řazení. V metodě Index(Model SearchData) přidejte do parametrů hledání následující řádek.

    options.OrderBy.Add("Rating desc");
    

    Poznámka

    Výchozí pořadí je vzestupné, i když to můžete přidat asc do vlastnosti, aby to bylo jasné. Sestupné pořadí je určeno přidáním descpříkazu .

  2. Teď aplikaci spusťte a zadejte libovolný běžný hledaný termín. Výsledky můžou nebo nemusí být ve správném pořadí, protože ani vy jako vývojář, ani uživatel nemáte snadný způsob ověření výsledků!

  3. Pojďme si ujasnit, ž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é třídy, které potřebujeme pro tento kurz).

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

    Tip

    Prohlížeče obvykle ukládají soubory CSS do mezipaměti, což může vést k použití starého souboru css a k ignorování úprav. Dobrým způsobem je přidat do odkazu řetězec dotazu s parametrem verze. Příklad:

      <link rel="stylesheet" href="~/css/hotels.css?v1.1" />
    

    Pokud si myslíte, že prohlížeč používá starý soubor CSS, aktualizujte číslo verze.

  4. Do metody Index(Model SearchData) přidejte vlastnost Rating do parametru Select, aby výsledky obsahovaly následující tři pole:

    options.Select.Add("HotelName");
    options.Select.Add("Description");
    options.Select.Add("Rating");
    
  5. Otevřete zobrazení (index.cshtml) a nahraďte vykreslovací smyčku (<!-- Zobrazit hotelová data. -->) 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" })
    }
    
  6. Hodnocení musí být k dispozici jak na první zobrazené stránce, tak na dalších stránkách, které jsou volány prostřednictvím nekonečného posouvání. V případě druhé z těchto dvou situací musíme aktualizovat akci Další v kontroleru i posunovanou funkci 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);
    }
    
  7. Teď aktualizujte posunutou 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>
    
  8. Teď aplikaci spusťte znovu. Vyhledejte libovolný běžný termín, například "wifi", a ověřte, že jsou výsledky seřazené podle sestupného pořadí podle hodnocení hotelu.

    Řazení na základě hodnocení

    Všimněte si, že několik hotelů má stejné hodnocení, takže jejich vzhled na displeji je opět pořadí, ve kterém se data nacházejí, což je libovolné.

    Než se podíváme na přidání druhé úrovně řazení, přidáme kód, který zobrazí rozsah cen za pokoj. Tento kód přidáváme tak, aby zobrazoval extrahování dat ze složitého typu a také abychom mohli probrat výsledky řazení na základě ceny (možná nejdříve nejlevnější).

Přidání rozsahu cen za pokoj do zobrazení

  1. Přidejte do modelu Hotel.cs vlastnosti obsahující nejlevnější a nejdražší sazbu za pokoj.

    // Room rate range
    public double cheapest { get; set; }
    public double expensive { get; set; }
    
  2. Vypočítejte sazby místnosti na konci akce Index(Model SearchData) v domovském kontroleru. 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;
    }
    
  3. Přidejte vlastnost Rooms do parametru Select v metodě akce Index(SearchData model) kontroleru.

    options.Select.Add("Rooms");
    
  4. Změňte smyčku vykreslování v zobrazení tak, aby se zobrazil 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" })
    }
    
  5. Změňte metodu Next na domovském kontroleru tak, aby komunikujte rozsah rychlosti 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);
    }
    
  6. Aktualizujte posunovanou funkci v zobrazení tak, aby zpracovávala text cen místností.

    <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>
    
  7. Spusťte aplikaci a ověřte, že se zobrazují rozsahy pokojových sazeb.

    Zobrazení rozsahů pokojových sazeb

Vlastnost OrderBy parametrů vyhledávání nepřijme položku, jako je Rooms.BaseRate , která poskytuje nejlevnější sazbu za pokoj, a to ani v případě, že již byly pokoje seřazeny podle sazby. V tomto případě nejsou pokoje seřazené podle sazby. Pokud chcete zobrazit hotely v ukázkové sadě dat seřazené podle ceny za pokoj, museli byste výsledky seřadit na domácím ovladači a odeslat je do zobrazení v požadovaném pořadí.

Řazení výsledků na základě více hodnot

Otázkou teď je, jak rozlišovat mezi hotely se stejným hodnocením. Jedním z přístupů může být sekundární objednávka založená na poslední rekonstrukci hotelu tak, že novější rekonstruované hotely se zobrazují vyšší ve výsledcích.

  1. Pokud chcete přidat druhou úroveň řazení, přidejte lastRenovationDate do výsledků hledání a do OrderBy v metodě Index(Model SearchData).

    options.Select.Add("LastRenovationDate");
    
    options.OrderBy.Add("LastRenovationDate desc");
    

    Tip

    Do seznamu OrderBy lze zadat libovolný počet vlastností. Pokud by hotely měly stejné hodnocení a datum renovace, bylo by možné zadat třetí vlastnost, která by je odlišovala.

  2. Opět musíme vidět datum renovace v zobrazení, jen abychom si byli jistí, že pořadí je správné. Pro takovou věc, jako je renovace, pravděpodobně stačí jen rok. 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" })
    }
    
  3. Změňte metodu Next v domovském ovladači tak, aby přeposílala rok komponenty data poslední 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);
        }
    
  4. Změňte posunovanou 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>
    
  5. Spustit aplikaci. Vyhledejte běžný termín, například "bazén" nebo "zobrazení", a ověřte, že hotely se stejným hodnocením se teď zobrazují v sestupném pořadí podle data renovace.

    Objednávání v den renovace

Řazení výsledků na základě bodovacího profilu

Příklady uvedené v tomto kurzu ukazují, jak uspořádat číselné hodnoty (hodnocení a datum renovace) a poskytnout tak přesnou sekvenci řazení. Některá vyhledávání a některá data se však k tak snadnému porovnání mezi dvěma datovými prvky nehodí. U fulltextových vyhledávacích dotazů zahrnuje Cognitive Search koncept řazení. Profily hodnocení je možné zadat tak, aby ovlivnily způsob řazení výsledků, což poskytuje složitější a kvalitativní porovnání.

Profily bodování jsou definovány ve schématu indexu. U dat o hotelech bylo nastaveno několik profilů bodování. Podívejme se na to, jak je definován profil bodování, a pak zkuste napsat kód pro vyhledávání.

Jak se definují profily hodnocení

Profily bodování jsou definovány ve vyhledávacím indexu v době návrhu. Index hotelů jen pro čtení, který hostuje Microsoft, má tři profily hodnocení. Tato část prozkoumá profily bodování a ukáže vám, jak používat v kódu.

  1. Níže je výchozí bodovací profil pro sadu dat hotelů, který se použije, 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, že 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. Je zřejmé, že čím vyšší je skóre, tím vyšší je výsledek v zobrazení.

    {
       "name": "boostByField",
       "text": {
           "weights": {
               "Tags": 3,
               "HotelName": 2,
               "Description": 1.5,
               "Description_fr": 1.5,
           }
       }
    }
    
  2. Následující alternativní profil bodování výrazně zvýší skóre, pokud zadaný parametr obsahuje jednu nebo více značek v seznamu značek (kterému říká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í zadán, 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
    },
    
  3. V tomto třetím profilu hodnocení hotelu výrazně zvyšuje skóre. Datum poslední renovace také zvýší skóre, ale pouze v případě, že tato data spadají do 730 dnů (2 let) od 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íváme, jestli tyto profily fungují tak, jak si myslíme, že by měly.

Přidání kódu do zobrazení pro porovnání profilů

  1. 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>&nbsp;Order:&nbsp;</b>
                        @Html.RadioButtonFor(m => m.scoring, "Default") Default&nbsp;&nbsp;
                        @Html.RadioButtonFor(m => m.scoring, "RatingRenovation") By numerical Rating&nbsp;&nbsp;
                        @Html.RadioButtonFor(m => m.scoring, "boostAmenities") By Amenities&nbsp;&nbsp;
                        @Html.RadioButtonFor(m => m.scoring, "renovatedAndHighlyRated") By Renovated date/Rating profile&nbsp;&nbsp;
                    </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>
    
  2. 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; }       
    }
    
  3. 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í profilu bodování

  1. Otevřete soubor domovského ovladače. Přidejte následující příkaz using (který vám pomůže při vytváření seznamů).

    using System.Linq;
    
  2. V tomto příkladu potřebujeme, aby počáteční volání indexu udělalo o něco víc, než jen vrátilo počáteční zobrazení. Metoda teď hledá až 20 zařízení, která se mají zobrazit 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);
        }
    
  3. K uložení omezujících znaků do dočasného úložiště a k jejich obnovení z dočasného úložiště a naplnění modelu potřebujeme dvě privátní metody.

        // 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()];
                }
            }
        }
    
  4. Podle potřeby musíme nastavit parametry OrderBy a ScoringProfile . Nahraďte existující metodu Index(model SearchData) 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 ke každému výběru přepínače .

  5. Pokud jste dokončili další kód pro předchozí část o řazení na základě více vlastností, nemusíme provádět žádné změny akce Další .

Spuštění a testování aplikace

  1. Spustit aplikaci. V zobrazení by se měla zobrazit kompletní sada vybavení.

  2. Při objednávání vám výběrem možnosti "Podle číselného hodnocení" získáte číselné pořadí, které jste už v tomto kurzu implementovali, přičemž datum renovace se rozhoduje mezi hotely se stejným hodnocením.

    Řazení

  3. Teď vyzkoušejte profil Podle vybavení. Vyberte různé možnosti vybavení a ověřte, že hotely s těmito vybaveními jsou v seznamu výsledků povýšené.

    Objednávání

  4. Vyzkoušejte si profil "Podle data renovace nebo hodnocení", abyste zjistili, jestli získáte to, co očekáváte. Pouze nedávno zrenovované hotely by měly získat svěžesti .

Zdroje informací

Další informace najdete v následujícím článku Přidání profilů bodování do indexu Azure Cognitive Search.

Shrnutí

Vezměte v úvahu následující poznatky z tohoto projektu:

  • Uživatelé budou očekávat, že výsledky hledání budou seřazené, nejrelevantní jako první.
  • Data je potřeba strukturovat, aby bylo řazení snadné. Nepodařilo se nám nejprve snadno seřadit "nejlevnější" data, protože data nejsou strukturovaná tak, aby bylo možné provádět řazení bez 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í.
  • Je přirozené, že některé výsledky jsou seřazené 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 pro sadu dat nejsou k dispozici číselné porovnání nebo nejsou dostatečně inteligentní. Vyhodnocení každého výsledku pomůže inteligentně uspořádat a zobrazit výsledky.

Další kroky

Dokončili jste tuto sérii kurzů jazyka C# – měli jste získat cenné znalosti o Azure Cognitive Search rozhraní API.

Další referenční informace a kurzy najdete v katalogu školení Microsoft Learn nebo v dalších kurzech v Azure Cognitive Search dokumentaci.