Självstudie: Lägga till automatisk komplettering och förslag med hjälp av .NET SDK
Lär dig hur du implementerar automatisk komplettering (typeahead-frågor och föreslagna resultat) när en användare börjar skriva i en sökruta. I den här självstudien visar vi automatiskt kompletterade frågor och föreslagna resultat separat och sedan tillsammans. En användare kanske bara behöver skriva två eller tre tecken för att hitta alla tillgängliga resultat.
I den här guiden får du lära dig att:
- Lägg till förslag
- Lägg till markeringar i förslagen
- Lägg till automatisk komplettering
- Kombinera automatisk komplettering och förslag
Översikt
Den här självstudien lägger till automatisk komplettering och föreslagna resultat i den tidigare självstudien Lägg till sidindelning i sökresultat .
En färdig version av koden i den här självstudien finns i följande projekt:
Förutsättningar
- 2a-add-paging-lösning (GitHub). Det här projektet kan antingen vara din egen version som skapats från föregående självstudie eller en kopia från GitHub.
Lägg till förslag
Vi börjar med det enklaste fallet med att erbjuda alternativ till användaren: en listruta med föreslagna resultat.
I filen index.cshtml ändrar du
@id
TextBoxFor-instruktionen till azureautosuggest.@Html.TextBoxFor(m => m.searchText, new { @class = "searchBox", @id = "azureautosuggest" }) <input value="" class="searchBoxSubmit" type="submit">
Efter den här instruktionen efter den avslutande </div> anger du det här skriptet. Det här skriptet använder widgeten Komplettera automatiskt från jQuery UI-biblioteket med öppen källkod för att visa listrutan med föreslagna resultat.
<script> $("#azureautosuggest").autocomplete({ source: "/Home/SuggestAsync?highlights=false&fuzzy=false", minLength: 2, position: { my: "left top", at: "left-23 bottom+10" } }); </script>
ID
"azureautosuggest"
:t ansluter ovanstående skript till sökrutan. Källalternativet för widgeten är inställt på en Suggest-metod som anropar suggest-API:et med två frågeparametrar: markeringar och fuzzy, båda inställda på false i den här instansen. Dessutom krävs minst två tecken för att utlösa sökningen.
Lägga till referenser till jQuery-skript i vyn
Om du vill komma åt jQuery-biblioteket ändrar du <huvudavsnittet> i vyfilen till följande kod:
<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>
Eftersom vi introducerar en ny jQuery-referens måste vi också ta bort, eller kommentera ut, standardreferensen för jQuery i filen _Layout.cshtml (i mappen Vyer/delad ). Leta upp följande rader och kommentera ut den första skriptraden enligt nedan. Den här ändringen förhindrar motstridiga referenser till 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>
Nu kan vi använda de fördefinierade jQuery-funktionerna för automatisk komplettering.
Lägg till åtgärden Föreslå i kontrollanten
I startkontrollanten lägger du till åtgärden SuggestAsync (efter åtgärden 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); }
Parametern Storlek anger hur många resultat som ska returneras (om det är ospecificerat är standardvärdet 5). En förslagsspelare anges i sökindexet när indexet skapas. I exempelindexet för hotell som hanteras av Microsoft är förslagslämnarens namn "sg" och söker efter föreslagna matchningar exklusivt i fältet HotelName .
Fuzzy-matchning gör att "nära missar" kan inkluderas i utdata, upp till ett redigeringsavstånd. Om parametern highlights är inställd på true läggs HTML-taggar i fetstil till i utdata. Vi anger båda parametrarna till true i nästa avsnitt.
Du kan få vissa syntaxfel. I så fall lägger du till följande två using-instruktioner överst i filen.
using System.Collections.Generic; using System.Linq;
Kör appen. Får du ett antal alternativ när du till exempel anger "po"? Prova nu "pa".
Observera att de bokstäver du anger måste starta ett ord och inte bara inkluderas i ordet.
I visningsskriptet anger du&fuzzy till true och kör appen igen. Ange nu "po". Observera att sökningen förutsätter att du fick ett brev fel.
Om du är intresserad beskriver Lucene-frågesyntaxen i Azure Cognitive Search logiken som används i fuzzy-sökningar i detalj.
Lägg till markeringar i förslagen
Vi kan förbättra utseendet på förslagen för användaren genom att ange parametern highlights till true. Först måste vi dock lägga till kod i vyn för att visa den fetstilade texten.
I vyn (index.cshtml) lägger du till följande skript efter skriptet
"azureautosuggest"
som beskrevs tidigare.<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>
Ändra nu ID:t för textrutan så att den ser ut så här.
@Html.TextBoxFor(m => m.searchText, new { @class = "searchBox", @id = "azuresuggesthighlights" }) <input value="" class="searchBoxSubmit" type="submit">
Kör appen igen så bör du se den angivna texten fetstilt i förslagen. Prova att skriva "pa".
Logiken som används i markeringsskriptet ovan är inte idiotsäker. Om du anger en term som visas två gånger i samma namn är de fetstilade resultaten inte riktigt vad du vill. Prova att skriva "mo".
En av de frågor som en utvecklare behöver besvara är när är ett skript som fungerar "tillräckligt bra" och när bör dess egenheter åtgärdas. Vi kommer inte att gå vidare med markering i den här självstudien, men att hitta en exakt algoritm är något att tänka på om markering inte är effektivt för dina data. Mer information finns i Träffmarkering.
Lägg till automatisk komplettering
En annan variant, som skiljer sig något från förslag, är automatisk komplettering (kallas ibland "type-ahead") som slutför en frågeterm. Återigen börjar vi med den enklaste implementeringen innan vi förbättrar användarupplevelsen.
Ange följande skript i vyn efter dina tidigare skript.
<script> $("#azureautocompletebasic").autocomplete({ source: "/Home/Autocomplete", minLength: 2, position: { my: "left top", at: "left-23 bottom+10" } }); </script>
Ändra nu ID:t för textrutan så att den ser ut så här.
@Html.TextBoxFor(m => m.searchText, new { @class = "searchBox", @id = "azureautocompletebasic" }) <input value="" class="searchBoxSubmit" type="submit">
I startkontrollanten anger du åtgärden AutocompleteAsync efter åtgärden 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); }
Observera att vi använder samma förslagsfunktion , som kallas "sg", i den automatiska kompletteringssökningen som vi gjorde för förslag (så vi försöker bara komplettera hotellnamnen automatiskt).
Det finns ett antal inställningar för AutocompleteMode och vi använder OneTermWithContext. Se API:et för automatisk komplettering för en beskrivning av ytterligare alternativ.
Kör appen. Observera att de olika alternativ som visas i listrutan är enkla ord. Prova att skriva ord som börjar med "re". Observera hur antalet alternativ minskar när fler bokstäver skrivs.
Som det ser ut nu är förslagsskriptet som du körde tidigare förmodligen mer användbart än det här skriptet för automatisk komplettering. Om du vill göra automatisk komplettering mer användarvänligt kan du använda det med föreslagna resultat.
Kombinera automatisk komplettering och förslag
Att kombinera automatisk komplettering och förslag är det mest komplexa av våra alternativ och ger förmodligen den bästa användarupplevelsen. Vad vi vill är att visa, infogat med texten som skrivs, är det första valet av Azure Cognitive Search för automatisk komplettering av texten. Vi vill också ha ett antal förslag som en listruta.
Det finns bibliotek som erbjuder den här funktionen , som ofta kallas "infogad automatisk komplettering" eller ett liknande namn. Vi kommer dock att implementera den här funktionen internt så att du kan utforska API:erna. Vi börjar arbeta med kontrollanten först i det här exemplet.
Lägg till en åtgärd till kontrollanten som bara returnerar ett resultat för automatisk komplettering, tillsammans med ett angivet antal förslag. Vi anropar den här åtgärden AutoCompleteAndSuggestAsync. Lägg till följande åtgärd i startkontrollanten efter dina andra nya åtgärder.
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); }
Ett alternativ för automatisk komplettering returneras överst i resultatlistan , följt av alla förslag.
I vyn implementerar vi först ett trick så att ett ljusgrå automatiskt kompletteringsord återges direkt under fetare text som anges av användaren. HTML innehåller relativ positionering för detta ändamål. Ändra TextBoxFor-instruktionen (och dess omgivande <div-instruktioner> ) till följande, och notera att en andra sökruta som identifieras som under finns precis under vår vanliga sökruta, genom att dra den här sökrutan 39 bildpunkter från dess standardplats!
<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>
Observera att vi ändrar ID:t igen till azureautocomplete i det här fallet.
Ange även följande skript i vyn, efter alla skript som du har angett hittills. Skriptet är långt och komplext på grund av de olika indatabeteenden som det hanterar.
<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>
Observera hur funktionen Interval används för att både rensa den underliggande texten när den inte längre matchar vad användaren skriver, och även för att ange samma skiftläge (övre eller nedre) som användaren skriver (som "pa" matchar "PA", "pA", "Pa" vid sökning), så att den överlagrade texten är snygg.
Läs igenom kommentarerna i skriptet för att få en bättre förståelse.
Slutligen måste vi göra en mindre justering av två HTML-klasser för att göra dem transparenta. Lägg till följande rad i searchBoxForm - och searchBox-klasserna i filen hotels.css.
background: rgba(0,0,0,0);
Kör nu appen. Ange "pa" i sökrutan. Får du "palace" som autocomplete-förslag, tillsammans med två hotell som innehåller "pa"?
Prova att tabbing för att acceptera förslaget om automatisk komplettering och försök att välja förslag med hjälp av piltangenterna och tabbtangenten och försök igen med musen och ett enda klick. Kontrollera att skriptet hanterar alla dessa situationer på ett snyggt sätt.
Du kan välja att det är enklare att läsa in i ett bibliotek som erbjuder den här funktionen åt dig, men nu vet du minst ett sätt att få infogad automatisk komplettering att fungera.
Lärdomar
Överväg följande lärdomar från det här projektet:
- Automatisk komplettering (kallas även "type-ahead") och förslag kan göra det möjligt för användaren att bara skriva några få nycklar för att hitta exakt vad de vill.
- Automatisk komplettering och förslag som fungerar tillsammans kan ge en omfattande användarupplevelse.
- Testa alltid funktioner för automatisk komplettering med alla former av indata.
- Det kan vara användbart att använda funktionen setInterval för att verifiera och korrigera användargränssnittselement.
Nästa steg
I nästa självstudie tar vi en titt på ett annat sätt att förbättra användarupplevelsen genom att använda faser för att begränsa sökningar med ett enda klick.