Kurz: Přidání automatického dokončování a návrhů pomocí sady .NET SDK

Naučte se, jak implementovat automatické dokončování (predikce zadávání a navrhované výsledky) ve chvíli, kdy uživatel začne psát do vyhledávacího pole. V tomto kurzu zobrazíme automaticky dokončené dotazy a navrhované výsledky samostatně a pak společně. Uživatel může zadat pouze dva nebo tři znaky a vyhledat tak všechny dostupné výsledky.

V tomto návodu se naučíte, jak:

  • Přidání návrhů
  • Přidání zvýraznění do návrhů
  • Přidejte automatické dokončování
  • Kombinování automatického dokončování a návrhů

Přehled

Tento kurz přidá automatické dokončování a navrhované výsledky do předchozího 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

  • 2a-add-paging (GitHub) řešení. Tento projekt může být buď vaše vlastní verze sestavená z předchozího kurzu, nebo kopie z GitHubu.

Přidání návrhů

Začněme nejjednodušším případem nabídky alternativ pro uživatele: rozevírací seznam navrhovaných výsledků.

  1. V souboru index.cshtml změňte @id příkaz TextBoxFor na azureautosuggest.

     @Html.TextBoxFor(m => m.searchText, new { @class = "searchBox", @id = "azureautosuggest" }) <input value="" class="searchBoxSubmit" type="submit">
    
  2. Po tomto příkazu, po uzavření </div>, zadejte tento skript. Tento skript využívá widget automatického dokončování z opensourcové knihovny uživatelského rozhraní jQuery k prezentaci rozevíracího seznamu navrhovaných výsledků.

    <script>
        $("#azureautosuggest").autocomplete({
            source: "/Home/SuggestAsync?highlights=false&fuzzy=false",
            minLength: 2,
            position: {
                my: "left top",
                at: "left-23 bottom+10"
            }
        });
    </script>
    

    ID "azureautosuggest" připojí výše uvedený skript k vyhledávacímu poli. Zdrojová možnost widgetu je nastavena na metodu Suggest, která volá rozhraní Suggest API se dvěma parametry dotazu: zvýraznění a fuzzy, přičemž oba jsou v této instanci nastaveny na false. K aktivaci hledání je také potřeba minimálně dva znaky.

Přidání odkazů na skripty jQuery do zobrazení

  1. Pokud chcete získat přístup k knihovně jQuery, změňte <hlavní> část souboru zobrazení na následující kód:

    <head>
        <meta charset="utf-8">
        <title>Typeahead</title>
        <link href="https://code.jquery.com/ui/1.12.1/themes/start/jquery-ui.css"
              rel="stylesheet">
        <script src="https://code.jquery.com/jquery-1.10.2.js"></script>
        <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
    
        <link rel="stylesheet" href="~/css/hotels.css" />
    </head>
    
  2. Vzhledem k tomu, že zavádíme nový odkaz jQuery, musíme také odebrat nebo okomentovat výchozí odkaz jQuery v souboru _Layout.cshtml (ve složce Views/Shared ). Vyhledejte následující řádky a okomentujte první řádek skriptu, jak je znázorněno. Tato změna zabraňuje kolidování odkazů na jQuery.

    <environment include="Development">
        <!-- <script src="~/lib/jquery/dist/jquery.js"></script> -->
        <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
        <script src="~/js/site.js" asp-append-version="true"></script>
    </environment>
    

    Teď můžeme použít předdefinované funkce automatického dokončování jQuery.

Přidejte akci Navrhnout do řadiče

  1. Na domovském řadiči přidejte akci SuggestAsync (za akci PageAsync ).

    public async Task<ActionResult> SuggestAsync(bool highlights, bool fuzzy, string term)
    {
        InitSearch();
    
        // Setup the suggest parameters.
        var options = new SuggestOptions()
        {
            UseFuzzyMatching = fuzzy,
            Size = 8,
        };
    
        if (highlights)
        {
            options.HighlightPreTag = "<b>";
            options.HighlightPostTag = "</b>";
        }
    
        // Only one suggester can be specified per index. It is defined in the index schema.
        // The name of the suggester is set when the suggester is specified by other API calls.
        // The suggester for the hotel database is called "sg", and simply searches the hotel name.
        var suggestResult = await _searchClient.SuggestAsync<Hotel>(term, "sg", options).ConfigureAwait(false);
    
        // Convert the suggested query results to a list that can be displayed in the client.
        List<string> suggestions = suggestResult.Value.Results.Select(x => x.Text).ToList();
    
        // Return the list of suggestions.
        return new JsonResult(suggestions);
    }
    

    Parametr Size určuje, kolik výsledků se má vrátit (pokud není zadáno, výchozí hodnota je 5). Při vytváření indexu vyhledávání je určen navrhovací modul. V indexu ukázkových hotelů hostovaných Microsoftem je název navrhovatele "sg" a hledá navrhované shody výhradně v poli HotelName.

    Přibližné porovnávání umožňuje zahrnout do výstupu "téměř zmeškané" až jednu vzdálenost úprav. Pokud je parametr zvýraznění nastavený na hodnotu true, pak se do výstupu přidají tučné značky HTML. Oba parametry nastavíme na true v další části.

  2. Může se zobrazit několik chyb syntaxe. Pokud ano, přidejte následující dva příkazy using na začátek souboru.

    using System.Collections.Generic;
    using System.Linq;
    
  3. Spustit aplikaci. Získáte například řadu možností, když zadáte "po"? Teď zkuste "pa".

    Při psaní *po* se zobrazí dva návrhy.

    Všimněte si, že zadaná písmena musí začínat slovo, a ne jenom být zahrnuta do slova.

  4. Ve skriptu zobrazení nastavte hodnotu &fuzzy na true a spusťte aplikaci znovu. Nyní zadejte "po". Všimněte si, že hledání předpokládá, že je jedno písmeno chybné.

    Psaní *pa* s neostrým režimem nastaveným na pravda

    Pokud vás zajímá, syntaxe dotazů Lucene ve službě Azure Cognitive Search podrobně popisuje logiku použitou v přibližných vyhledáváních.

Přidání zvýraznění do návrhů

Vzhled návrhů pro uživatele můžeme vylepšit nastavením parametru zvýraznění na true. Nejdřív ale musíme do zobrazení přidat nějaký kód, aby se zobrazil tučný text.

  1. Do zobrazení (index.cshtml) přidejte následující skript za dříve popsaný skript "azureautosuggest".

    <script>
        var updateTextbox = function (event, ui) {
            var result = ui.item.value.replace(/<\/?[^>]+(>|$)/g, "");
            $("#azuresuggesthighlights").val(result);
            return false;
        };
    
        $("#azuresuggesthighlights").autocomplete({
            html: true,
            source: "/home/suggest?highlights=true&fuzzy=false&",
            minLength: 2,
            position: {
                my: "left top",
                at: "left-23 bottom+10"
            },
            select: updateTextbox,
            focus: updateTextbox
        }).data("ui-autocomplete")._renderItem = function (ul, item) {
            return $("<li></li>")
                .data("item.autocomplete", item)
                .append("<a>" + item.label + "</a>")
                .appendTo(ul);
        };
    </script>
    
  2. Teď změňte ID textového pole tak, aby se četlo následovně.

    @Html.TextBoxFor(m => m.searchText, new { @class = "searchBox", @id = "azuresuggesthighlights" }) <input value="" class="searchBoxSubmit" type="submit">
    
  3. Spusťte aplikaci znovu a v návrzích byste měli vidět zadaný text tučným písmem. Zkuste zadat "pa".

    Psaní *pa* se zvýrazněním

    Logika použitá ve zvýrazňujícím skriptu výše není neomylná. Pokud zadáte termín, který se zobrazí dvakrát ve stejném názvu, tučné výsledky nejsou úplně to, co byste chtěli. Zkuste napsat "mo".

    Jednou z otázek, na které musí vývojář odpovědět, je, když skript funguje "dostatečně dobře", a kdy by se měly řešit jeho vychytáky. V tomto kurzu nebudeme dále zvýrazňovat, ale nalezení přesného algoritmu je něco, co byste měli zvážit, pokud zvýraznění není pro vaše data efektivní. Další informace najdete v tématu Zvýraznění hitů.

Přidejte automatické dokončování

Další varianta, mírně odlišná od návrhů, je automatické dokončování (někdy označované jako "během psaní"), které dokončí termín dotazu. Znovu začneme nejjednodušší implementací před vylepšením uživatelského prostředí.

  1. Do zobrazení zadejte následující skript, který následuje za předchozími skripty.

    <script>
        $("#azureautocompletebasic").autocomplete({
            source: "/Home/Autocomplete",
            minLength: 2,
            position: {
                my: "left top",
                at: "left-23 bottom+10"
            }
        });
    </script>
    
  2. Teď změňte ID textového pole, aby se četlo takto.

    @Html.TextBoxFor(m => m.searchText, new { @class = "searchBox", @id = "azureautocompletebasic" }) <input value="" class="searchBoxSubmit" type="submit">
    
  3. V domovském ovladači zadejte akci AutocompleteAsync po akci SuggestAsync.

    public async Task<ActionResult> AutoCompleteAsync(string term)
    {
        InitSearch();
    
        // Setup the autocomplete parameters.
        var ap = new AutocompleteOptions()
        {
            Mode = AutocompleteMode.OneTermWithContext,
            Size = 6
        };
        var autocompleteResult = await _searchClient.AutocompleteAsync(term, "sg", ap).ConfigureAwait(false);
    
        // Convert the autocompleteResult results to a list that can be displayed in the client.
        List<string> autocomplete = autocompleteResult.Value.Results.Select(x => x.Text).ToList();
    
        return new JsonResult(autocomplete);
    }
    

    Všimněte si, že ve vyhledávání automatického dokončování používáme stejnou funkci suggester s názvem "sg", stejně jako při návrzích (takže se snažíme dokončovat názvy hotelů).

    Existuje řada nastavení AutocompleteMode a používáme OneTermWithContext. Další možnosti jsou popsány v rozhraní API automatického dokončování.

  4. Spustit aplikaci. Všimněte si, že rozsah možností zobrazených v rozevíracím seznamu jsou jednoduchá slova. Zkuste psát slova začínající slovem "re". Všimněte si, že počet možností se snižuje při psaní více písmen.

    Psaní pomocí základního automatického dokončování

    Jak je uvedeno, skript návrhů, který jste spustili dříve, je pravděpodobně užitečnější než tento skript automatického dokončování. Pokud chcete, aby automatické dokončování bylo uživatelsky přívětivější, zvažte jeho použití s navrhovanými výsledky.

Kombinování automatického dokončování a návrhů

Kombinace automatického dokončování a návrhů je nejsložitější z našich možností a pravděpodobně poskytuje nejlepší uživatelské prostředí. Co chceme, je zobrazit první volbu služby Azure Cognitive Search pro automatické dokončování textu přímo v řádku s psaným textem. Jako rozevírací seznam chceme také vytvořit celou řadu návrhů.

Existují knihovny, které tuto funkci nabízejí – často označované jako "automatické dokončování v řádku" nebo podobným názvem. Tuto funkci ale nativně implementujeme, abyste mohli prozkoumat rozhraní API. V tomto příkladu začneme pracovat na kontroleru.

  1. Přidejte akci do kontroleru, která vrací pouze jeden výsledek automatického dokončování, spolu se zadaným počtem návrhů. Zavoláme tuto akci AutoCompleteAndSuggestAsync. Do domovského kontroleru přidejte následující akci, která následuje za dalšími novými akcemi.

    public async Task<ActionResult> AutoCompleteAndSuggestAsync(string term)
    {
        InitSearch();
    
        // Setup the type-ahead search parameters.
        var ap = new AutocompleteOptions()
        {
            Mode = AutocompleteMode.OneTermWithContext,
            Size = 1,
        };
        var autocompleteResult = await _searchClient.AutocompleteAsync(term, "sg", ap);
    
        // Setup the suggest search parameters.
        var sp = new SuggestOptions()
        {
            Size = 8,
        };
    
        // Only one suggester can be specified per index. The name of the suggester is set when the suggester is specified by other API calls.
        // The suggester for the hotel database is called "sg" and simply searches the hotel name.
        var suggestResult = await _searchClient.SuggestAsync<Hotel>(term, "sg", sp).ConfigureAwait(false);
    
        // Create an empty list.
        var results = new List<string>();
    
        if (autocompleteResult.Value.Results.Count > 0)
        {
            // Add the top result for type-ahead.
            results.Add(autocompleteResult.Value.Results[0].Text);
        }
        else
        {
            // There were no type-ahead suggestions, so add an empty string.
            results.Add("");
        }
    
        for (int n = 0; n < suggestResult.Value.Results.Count; n++)
        {
            // Now add the suggestions.
            results.Add(suggestResult.Value.Results[n].Text);
        }
    
        // Return the list.
        return new JsonResult(results);
    }
    

    V horní části seznamu výsledků se vrátí jedna možnost automatického dokončování, za kterou následují všechny návrhy.

  2. V zobrazení nejprve implementujeme trik, aby se světle šedé slovo automatického dokončování vykreslilo přímo pod tučnějším textem, který uživatel právě zadává. HTML obsahuje relativní umístění pro tento účel. Změňte příkaz TextBoxFor (a okolní <příkazy div>) na následující. Druhé vyhledávací pole, identifikované jako pod, je umístěno přímo pod naším běžným vyhledávacím polem, přičemž toto pole je posunuto o 39 pixelů od jeho výchozího umístění.

    <div id="underneath" class="searchBox" style="position: relative; left: 0; top: 0">
    </div>
    
    <div id="searchinput" class="searchBoxForm" style="position: relative; left: 0; top: -39px">
        @Html.TextBoxFor(m => m.searchText, new { @class = "searchBox", @id = "azureautocomplete" }) <input value="" class="searchBoxSubmit" type="submit">
    </div>
    

    Všimněte si, že v tomto případě znovu měníme ID na azureautocomplete .

  3. Také v zobrazení zadejte následující skript po všech skriptech, které jste zatím zadali. Skript je zdlouhavý a složitý kvůli různým chováním vstupu, které zpracovává.

    <script>
        $('#azureautocomplete').autocomplete({
            delay: 500,
            minLength: 2,
            position: {
                my: "left top",
                at: "left-23 bottom+10"
            },
    
            // Use Ajax to set up a "success" function.
            source: function (request, response) {
                var controllerUrl = "/Home/AutoCompleteAndSuggestAsync?term=" + $("#azureautocomplete").val();
                $.ajax({
                    url: controllerUrl,
                    dataType: "json",
                    success: function (data) {
                        if (data && data.length > 0) {
    
                            // Show the autocomplete suggestion.
                            document.getElementById("underneath").innerHTML = data[0];
    
                            // Remove the top suggestion as it is used for inline autocomplete.
                            var array = new Array();
                            for (var n = 1; n < data.length; n++) {
                                array[n - 1] = data[n];
                            }
    
                            // Show the drop-down list of suggestions.
                            response(array);
                        } else {
    
                            // Nothing is returned, so clear the autocomplete suggestion.
                            document.getElementById("underneath").innerHTML = "";
                        }
                    }
                });
            }
        });
    
        // Complete on TAB.
        // Clear on ESC.
        // Clear if backspace to less than 2 characters.
        // Clear if any arrow key hit as user is navigating the suggestions.
        $("#azureautocomplete").keydown(function (evt) {
    
            var suggestedText = document.getElementById("underneath").innerHTML;
            if (evt.keyCode === 9 /* TAB */ && suggestedText.length > 0) {
                $("#azureautocomplete").val(suggestedText);
                return false;
            } else if (evt.keyCode === 27 /* ESC */) {
                document.getElementById("underneath").innerHTML = "";
                $("#azureautocomplete").val("");
            } else if (evt.keyCode === 8 /* Backspace */) {
                if ($("#azureautocomplete").val().length < 2) {
                    document.getElementById("underneath").innerHTML = "";
                }
            } else if (evt.keyCode >= 37 && evt.keyCode <= 40 /* Any arrow key */) {
                document.getElementById("underneath").innerHTML = "";
            }
        });
    
        // Character replace function.
        function setCharAt(str, index, chr) {
            if (index > str.length - 1) return str;
            return str.substr(0, index) + chr + str.substr(index + 1);
        }
    
        // This function is needed to clear the "underneath" text when the user clicks on a suggestion, and to
        // correct the case of the autocomplete option when it does not match the case of the user input.
        // The interval function is activated with the input, blur, change, or focus events.
        $("#azureautocomplete").on("input blur change focus", function (e) {
    
            // Set a 2 second interval duration.
            var intervalDuration = 2000, 
                interval = setInterval(function () {
    
                    // Compare the autocorrect suggestion with the actual typed string.
                    var inputText = document.getElementById("azureautocomplete").value;
                    var autoText = document.getElementById("underneath").innerHTML;
    
                    // If the typed string is longer than the suggestion, then clear the suggestion.
                    if (inputText.length > autoText.length) {
                        document.getElementById("underneath").innerHTML = "";
                    } else {
    
                        // If the strings match, change the case of the suggestion to match the case of the typed input.
                        if (autoText.toLowerCase().startsWith(inputText.toLowerCase())) {
                            for (var n = 0; n < inputText.length; n++) {
                                autoText = setCharAt(autoText, n, inputText[n]);
                            }
                            document.getElementById("underneath").innerHTML = autoText;
    
                        } else {
                            // The strings do not match, so clear the suggestion.
                            document.getElementById("underneath").innerHTML = "";
                        }
                    }
    
                    // If the element loses focus, stop the interval checking.
                    if (!$input.is(':focus')) clearInterval(interval);
    
                }, intervalDuration);
        });
    </script>
    

    Všimněte si, jak se funkce intervalu používá k vymazání základního textu, když už neodpovídá tomu, co uživatel píše, a také k nastavení stejného písmena (horní nebo dolní), jako uživatel píše (jako "pa" odpovídá "PA", "pA", "Pa" při hledání), aby překryvný text byl přehledný.

    Přečtěte si komentáře ve skriptu, abyste lépe porozuměli.

  4. Nakonec musíme provést menší úpravy dvou tříd HTML, aby byly transparentní. Do třídy searchBoxForm a searchBox v souboru hotels.css přidejte následující řádek.

    background: rgba(0,0,0,0);
    
  5. Teď spusťte aplikaci. Do vyhledávacího pole zadejte "pa". Dostanete "palác" jako návrh automatického dokončování spolu se dvěma hotely, které obsahují "pa"?

    Psaní pomocí vloženého automatického dokončování a návrhů

  6. Zkuste použít klávesu Tabbing, abyste přijali návrh automatického dokončování, a zkuste vybrat návrhy pomocí kláves se šipkami a klávesou Tab a zkuste to znovu pomocí myši a jediného kliknutí. Ověřte, že skript zpracovává všechny tyto situace přehledně.

    Můžete se rozhodnout, že je jednodušší načíst do knihovny, která vám tuto funkci nabízí, ale teď víte alespoň jeden způsob, jak získat vložené automatické dokončování, aby fungovalo.

Klíčové poznatky

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

  • Automatické dokončování (označované také jako "type-ahead") a návrhy můžou uživateli umožnit, aby zadal jenom několik klíčů, aby vyhledali přesně to, co chce.
  • Automatické dokončování a návrhy, které společně spolupracují, mohou vytvořit bohaté uživatelské prostředí.
  • Funkce automatického dokončování vždy testujte se všemi formuláři vstupu.
  • Použití funkce setInterval může být užitečné při ověřování a opravě prvků uživatelského rozhraní.

Další kroky

V dalším kurzu se podíváme na jiný způsob, jak zlepšit uživatelské prostředí pomocí omezujících vlastností a zúžit vyhledávání jediným kliknutím.