البرنامج التعليمي: إضافة الإكمال التلقائي والاقتراحات باستخدام .NET SDK

تعرف على كيفية تنفيذ الإكمال التلقائي (استعلامات الكتابة والنتائج المقترحة) عندما يبدأ المستخدم في الكتابة في مربع البحث. في هذا البرنامج التعليمي، سنعرض الاستعلامات المكتملية تلقائيا والنتائج المقترحة بشكل منفصل، ثم معا. قد يتعين على المستخدم كتابة حرفين أو ثلاثة أحرف فقط لتحديد موقع جميع النتائج المتاحة.

في هذا البرنامج التعليمي، تتعلم كيفية:

  • إضافة اقتراحات
  • إضافة التمييز إلى الاقتراحات
  • إضافة الإكمال التلقائي
  • الجمع بين الإكمال التلقائي والاقتراحات

نظرة عامة

يضيف هذا البرنامج التعليمي الإكمال التلقائي والنتائج المقترحة إلى البرنامج التعليمي السابق إضافة ترحيل إلى نتائج البحث.

يمكن العثور على نسخة نهائية من التعليمة البرمجية في هذا البرنامج التعليمي في المشروع التالي:

المتطلبات الأساسية

  • حل 2a-add-paging (GitHub). يمكن أن يكون هذا المشروع إما نسختك الخاصة التي تم إنشاؤها من البرنامج التعليمي السابق أو نسخة من GitHub.

إضافة اقتراحات

لنبدأ بأبسط حالة لتقديم بدائل للمستخدم: قائمة منسدلة بالنتائج المقترحة.

  1. في ملف index.cshtml، قم بتغيير @id في عبارة TextBoxFor إلى azureautosuggest.

     @Html.TextBoxFor(m => m.searchText, new { @class = "searchBox", @id = "azureautosuggest" }) <input value="" class="searchBoxSubmit" type="submit">
    
  2. بعد هذه العبارة، بعد إغلاق <div/> ، أدخل هذا النص البرمجي. يستفيد هذا النص البرمجي من أداة Autocomplete من مكتبة jQuery UI مفتوحة المصدر لتقديم القائمة المنسدلة للنتائج المقترحة.

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

    المعرف "azureautosuggest" يربط البرنامج النصي أعلاه بمربع البحث. يتم تعيين خيار المصدر للأداة على طريقة "Suggest" التي تستدعي واجهة برمجة التطبيقات "Suggest" بمعاملتي طلب بحث: التحديدات وfuzzy، وكلاهما تم تعيينهما على "خطأ" في هذه الحالة. أيضاً، يلزم وجود حرفين على الأقل لبدء البحث.

أضف مراجع إلى نصوص jQuery إلى طريقة العرض

  1. للوصول إلى مكتبة jQuery، قم بتغيير قسم <head> في ملف العرض إلى الكود التالي:

    <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. نظرا لأننا نقدم مرجع jQuery جديدا، نحتاج أيضا إلى إزالة مرجع jQuery الافتراضي أو التعليق عليه في ملف _Layout.cshtml (في المجلد طرق العرض/المشتركة ). حدد موقع الأسطر التالية، وقم بالتعليق على السطر الأول من البرنامج النصي كما هو موضح. يتجنب هذا التغيير تضارب الإشارات إلى 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>
    

    يمكننا الآن استخدام وظائف jQuery للإكمال التلقائي المحددة مسبقاً.

أضف إجراء الاقتراح إلى وحدة التحكم

  1. في وحدة التحكم الرئيسية، أضف الإجراء SuggestAsync (بعد إجراء 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);
    }
    

    تحدد معلمة Size عدد النتائج المراد عرضها (إذا لم يتم تحديدها، يكون الافتراضي هو 5). يتم تحديد suggester في فهرس البحث عند إنشاء الفهرس. في نموذج فهرس الفنادق الذي تستضيفه Microsoft، يكون اسم المُقترح هو "sg"، ويبحث عن التطابقات المقترحة حصرياً في الحقل HotelName.

    تسمح المطابقة الغامضة بتضمين "الأخطاء الوشيكة" في الإخراج، حتى مسافة تعديل واحدة. إذا تم تعيين معلمة features على "صواب"، فستتم إضافة علامات HTML الغامقة إلى الإخراج. سنضبط كلا المعلمتين على true في القسم التالي.

  2. قد تحصل على بعض الأخطاء النحوية. إذا كان الأمر كذلك، فأضف العبارتين التاليتين باستخدام في أعلى الملف.

    using System.Collections.Generic;
    using System.Linq;
    
  3. شغّل التطبيق. هل تحصل على مجموعة من الخيارات عند إدخال "po"، على سبيل المثال؟ جرب الآن "pa".

    تؤدي كتابة *po* إلى إظهار اقتراحين

    لاحظ أن الأحرف التي تدخلها يجب أن تبدأ كلمة، ولا يتم تضمينها ببساطة في الكلمة.

  4. في نص العرض، اضبط & fuzzy على true، ثم شغّل التطبيق مرة أخرى. الآن أدخل "po". لاحظ أن البحث يفترض أنك حصلت على حرف واحد بشكل خاطئ.

     كتابة *pa* مع ضبط الغموض على

    إذا كنت مهتما، فإن بناء جملة استعلام Lucene في Azure Cognitive Search يصف المنطق المستخدم في عمليات البحث الغامضة بالتفصيل.

إضافة التمييز إلى الاقتراحات

يمكننا تحسين مظهر الاقتراحات للمستخدم عن طريق تعيين معلمة التحديدات على "صواب". ومع ذلك، نحتاج أولاً إلى إضافة بعض التعليمات البرمجية إلى طريقة العرض لعرض النص الغامق.

  1. في العرض (index.cshtml)، أضف البرنامج النصي التالي بعد البرنامج النصي "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. الآن قم بتغيير معرف مربع النص بحيث يصبح كالتالي.

    @Html.TextBoxFor(m => m.searchText, new { @class = "searchBox", @id = "azuresuggesthighlights" }) <input value="" class="searchBoxSubmit" type="submit">
    
  3. قم بتشغيل التطبيق مرة أخرى، وسترى النص الذي أدخلته بخط غامق في الاقتراحات. جرب كتابة "pa".

    كتابة *pa* مع التمييز

    المنطق المستخدم في البرنامج النصي المميز أعلاه ليس مضمونا. إذا أدخلت مصطلحا يظهر مرتين بنفس الاسم، فلن تكون النتائج الغامق تماما كما تريد. حاول كتابة "mo".

    أحد الأسئلة التي يحتاج المطور إلى الإجابة عنها هو، متى يعمل البرنامج النصي "بشكل جيد بما فيه الكفاية"، ومتى يجب معالجة المراوغات الخاصة به. لن نسلط الضوء أكثر في هذا البرنامج التعليمي، ولكن العثور على خوارزمية دقيقة أمر يجب مراعاته إذا لم يكن التمييز فعالا لبياناتك. لمزيد من المعلومات، راجع تمييز النتائج.

إضافة الإكمال التلقائي

هناك شكل آخر يختلف قليلاً عن الاقتراحات، وهو الإكمال التلقائي (يُسمى أحياناً "الكتابة المسبقة") الذي يكمل مصطلح طلب البحث. مرة أخرى، سنبدأ بأبسط تنفيذ، قبل تحسين تجربة المستخدم.

  1. أدخل النص التالي في طريقة العرض، باتباع البرامج النصية السابقة.

    <script>
        $("#azureautocompletebasic").autocomplete({
            source: "/Home/Autocomplete",
            minLength: 2,
            position: {
                my: "left top",
                at: "left-23 bottom+10"
            }
        });
    </script>
    
  2. الآن قم بتغيير معرف مربع النص، بحيث يصبح كالتالي.

    @Html.TextBoxFor(m => m.searchText, new { @class = "searchBox", @id = "azureautocompletebasic" }) <input value="" class="searchBoxSubmit" type="submit">
    
  3. في وحدة التحكم الرئيسية، أدخل إجراء AutocompleteAsync بعد إجراء 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);
    }
    

    لاحظ أننا نستخدم نفس دالة المقترح ، المسماة "sg"، في بحث الإكمال التلقائي كما فعلنا للاقتراحات (لذلك نحن نحاول فقط الإكمال التلقائي لأسماء الفنادق).

    هناك مجموعة من إعدادات AutocompleteMode ، ونحن نستخدم OneTermWithContext. راجع Autocomplete API للحصول على وصف للخيارات الإضافية.

  4. شغّل التطبيق. لاحظ كيف أن نطاق الخيارات المعروضة في القائمة المنسدلة عبارة عن كلمات فردية. حاول كتابة الكلمات التي تبدأ بحرف "re". لاحظ كيف يقل عدد الخيارات كلما تمت كتابة المزيد من الأحرف.

    الكتابة باستخدام الإكمال التلقائي الأساسي

    كما هو الحال، من المحتمل أن يكون نص الاقتراحات الذي قمت بتشغيله مسبقاً أكثر فائدة من نص الإكمال التلقائي هذا. لجعل الإكمال التلقائي أكثر سهولة في الاستخدام، ضع في اعتبارك استخدامه مع النتائج المقترحة.

الجمع بين الإكمال التلقائي والاقتراحات

يعد الجمع بين الإكمال التلقائي والاقتراحات أكثر خياراتنا تعقيداً، وربما يوفر أفضل تجربة للمستخدم. ما نريده هو أن نعرضه، بما يتماشى مع النص الذي تتم كتابته، هو الخيار الأول لـ Azure Cognitive Search لإكمال النص تلقائياً. أيضاً، نريد مجموعة من الاقتراحات كقائمة منسدلة.

هناك مكتبات تقدم هذه الوظيفة - تسمى غالباً "الإكمال التلقائي المضمّن" أو اسماً مشابهاً. ومع ذلك، سننفذ هذه الميزة في الأصل حتى تتمكن من استكشاف واجهات برمجة التطبيقات. سنبدأ العمل على وحدة التحكم أولا في هذا المثال.

  1. أضف إجراءً إلى وحدة التحكم يعرض نتيجة إكمال تلقائي واحدة فقط، إلى جانب عدد محدد من الاقتراحات. سنسمي هذا الإجراء AutoCompleteAndSuggestAsync. في وحدة التحكم الرئيسية، أضف الإجراء التالي، متبوعاً بإجراءاتك الجديدة الأخرى.

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

    يتم عرض أحد خيارات الإكمال التلقائي أعلى قائمة results، متبوعة بجميع الاقتراحات.

  2. في طريقة العرض، نقوم أولاً بتنفيذ خدعة بحيث يتم عرض كلمة تكميل تلقائي باللون الرمادي الفاتح أسفل نص أكثر جرأة يتم إدخاله بواسطة المستخدم. يتضمن HTML تحديد الموقع النسبي لهذا الغرض. قم بتغيير عبارة TextBoxFor (وعبارات <div> المحيطة بها) إلى ما يلي، مع ملاحظة أن مربع البحث الثاني المحدد على أنه أسفل يقع مباشرة أسفل مربع البحث العادي، عن طريق سحب مربع البحث هذا 39 بكسل من موقعه الافتراضي!

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

    لاحظ أننا نقوم بتغيير المعرف مرة أخرى، إلى azureautocomplete في هذه الحالة.

  3. في طريقة العرض أيضا، أدخل البرنامج النصي التالي، بعد جميع البرامج النصية التي أدخلتها حتى الآن. النص طويل ومعقد بسبب تنوع سلوكيات الإدخال التي يتعامل معها.

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

    لاحظ كيف تُستخدم وظيفة interval لمسح النص الأساسي عندما لا يتطابق مع ما يكتبه المستخدم، وكذلك لتعيين الحالة نفسها (العلوية أو السفلية) التي يكتبها المستخدم (مثل " pa "يطابق" PA "و" pA "و" Pa "عند البحث)، بحيث يكون النص المتراكب أنيقاً.

    اقرأ التعليقات في البرنامج النصي للحصول على فهم أكمل.

  4. أخيراً، نحتاج إلى إجراء تعديل طفيف على صفي HTML لجعلهما شفافين. أضف السطر التالي إلى الفئتين searchBoxForm وsearchBox، في ملف hotels.css.

    background: rgba(0,0,0,0);
    
  5. الآن قم بتشغيل التطبيق. أدخل "pa" في مربع البحث. هل تحصل على "قصر" كاقتراح الإكمال التلقائي، إلى جانب فندقين يحتويان على "pa"؟

    الكتابة باستخدام الإكمال التلقائي المضمّن والاقتراحات

  6. حاول استخدام الجدولة لقبول اقتراح الإكمال التلقائي، وحاول تحديد الاقتراحات باستخدام مفاتيح الأسهم ومفتاح الجدولة، وحاول مرة أخرى باستخدام الماوس ونقرة واحدة. تحقق من أن البرنامج النصي يعالج كل هذه المواقف بدقة.

    قد تقرر أنه من الأسهل التحميل في مكتبة توفر لك هذه الميزة، ولكنك تعرف الآن طريقة واحدة على الأقل لتشغيل الإكمال التلقائي المضمن.

التعاليم الرئيسية

ضع في اعتبارك النقاط التالية من هذا المشروع:

  • يمكن للإكمال التلقائي (المعروف أيضاً باسم "الكتابة المسبقة") والاقتراحات تمكين المستخدم من كتابة بضعة مفاتيح فقط لتحديد موقع ما يريده بالضبط.
  • يمكن أن يوفر الإكمال التلقائي والاقتراحات التي تعمل معاً تجربة مستخدم ثرية.
  • اختبر دائماً وظائف الإكمال التلقائي بجميع أشكال المدخلات.
  • يمكن أن يكون استخدام الوظيفة setInterval مفيداً في التحقق من عناصر واجهة المستخدم وتصحيحها.

الخطوات التالية

في البرنامج التعليمي التالي، ألقينا نظرة على طريقة أخرى لتحسين تجربة المستخدم، وذلك باستخدام الأوجه لتضييق عمليات البحث بنقرة واحدة.