четверг, 25 сентября 2014 г.

Работа с подсказками в SharePoint 2010

В поисковом сервисе SharePoint 2010 (не Foundation) присутствует механизм, позволяющий отображать подсказки при вводе текста в поисковую строку на странице центра поиска, как показано на рисунке ниже.

Подсказки накапливаются во встроенном словаре  поисковой службы SharePoint следующим образом:
если пользователи ввели в поисковую строку один и тот же запрос более шести раз, и на странице с результатами по этому запросу сделали переход  по более чем шести результатам, то данный запрос (слово или фраза) в дальнейшем будут добавлены в словарь подсказок.
Для того, чтобы это произошло, существует встроенный TimerJob, который называется «Prepare Query Suggestions». По умолчанию он запускается 1 раз в день.

Добавление подсказок

Используем Powershell

С помощью Powershell мы можем сами добавлять слова и фразы в словарь подсказок.
В начале получаем имя поисковой службы, которая будет использоваться для работы с подсказками:
Get-SPEnterpriseSearchServiceApplication


Теперь добавляем наши подсказки:
$searchSSA = Get-SPEnterpriseSearchServiceApplication "Приложение службы поиска"
New-SPEnterpriseSearchLanguageResourcePhrase -SearchApplication  $searchSSA -Language RU-RU -Type QuerySuggestionAlwaysSuggest -Name "Наша фраза"
Start-SPTimerJob -Identity "Prepare Query Suggestions"

С помощью командлета Start-SPTimerJob -Identity "Prepare Query Suggestions" мы запускаем  TimerJob для добавления подсказок в словарь.
После этого, можно выполнить следующий командлет, для получения всего списка подсказок:
Get-SPEnterpriseSearchQuerySuggestionCandidates -SearchApplication $searchSSA


Используем серверный код для непосредственного добавления подсказок в словарь

Здесь и далее в примерах для работы потребуется объявить референсы на сборку Microsoft.Office.Server.Search и использовать пространства имен:
  • Microsoft.Office.Server.Search.Administration
  • Microsoft.Office.Server.Search.Query
SearchServiceApplication searchApp = farm.Services.GetValue<SearchQueryAndSiteSettingsService>().Applications.GetValue<SearchServiceApplication>("Приложение службы поиска") as SearchServiceApplication;
  
Ranking ranking = new Ranking(searchApp);
LanguageResourcePhraseList suggestions = ranking.LanguageResources["RU-RU"].QuerySuggestionsAlwaysSuggestList;
suggestions.AddPhrase(“Ваша фраза”, String.Empty);

После этого нужно запустить “Prepare Query Suggestions” TimerJob и «Ваша фраза» гарантированно добавится в словарь подсказок.

Используем серверный код для добавления подсказок с использованием стандартного механизма

Описание работы стандартного механизма приведено в самом первом разделе. Чтобы им воспользоваться мы должны использовать  нативный метод  RecordClick.
Хотя этот метод присутсвует в списке доступных на странице веб-сервиса Searh.asmx, но воспользоваться им не удасться, т.к. на msdn явно указано, что: «This member is reserved for internal use and is not intended to be used directly from your code.»
Поэтому нам остается использовать только одноименный метод в службе поиска: SearchServiceApplicationProxy.RecordClick Method
private void setRecordClick(string queryStr, string clickedUrl, string ResultsUrl)
        {
            Guid siteGuid = SPContext.Current.Web.Site.ID;
            using (SPSite site = new SPSite(siteGuid))
            {
                SPServiceContext serviceContext = SPServiceContext.GetContext(site);
                SearchServiceApplicationProxy searchAppProxy =
                    ((SearchServiceApplicationProxy)SearchServiceApplicationProxy.GetProxy(serviceContext));

                string queryId = Guid.NewGuid().ToString();
                string sessionId = Guid.NewGuid().ToString();

                QueryInfo info = new QueryInfo();
                info.QueryGuid = queryId;
                info.SiteGuid = site.ID.ToString();
                info.SessionId = sessionId;
                info.UserName = System.Threading.Thread.CurrentPrincipal.Identity.Name;

                info.QueryString = queryStr;
                info.StartItem = 1;
                info.ClickTime = DateTime.Now;
                info.ClickedUrl = clickedUrl;
                info.ResultsUrl = ResultsUrl;
                info.ClientType = QueryLogClientType.ObjectModel;
                info.SearchTime = DateTime.Now;

                // Send a Click QueryInfo
                info.LogType = QueryLogType.Click;
                searchAppProxy.RecordClick(info);
            }
        }

В качестве аргументов нашего метода setRecordClick() используется три значения:
  1. queryStr – значение поискового запроса
  2. clickedUrl – значение URL адреса, по которому пользователь перешел, выбрав один из результатов  на странице результатов поиска
  3. ResultsUrl - значение URL адреса самой страницы результатов поиска
После выполнения нашего метода, вся информация накапливается в промежуточном словаре и обрабатывается внутренним механизмом SharePoint. Т.о. SharePoint «сам решит» нужно ли добавлять подсказки, сформированные из ваших «рекордкликов» или нет.

Получение подсказок

В стандартном поисковом веб-сервисе Search.asmx присутствует метод GetQuerySuggestions, который позволяет получать подсказки. 
Ниже привожу примеры как это делать через клиентский и серверный код.

Работаем «на клиенте» (JavaScript)

Для примера я воспользуюсь js-библиотекой SPServices. На странице проекта в документации приведена информация о поддержке работы с методом GetQuerySuggestions:  http://spservices.codeplex.com/wikipage?title=Search 

Для работы (помимо подключения js-библиотеки SPServices) потребуется подключить на страницу еще и jQuery (см.рекомендации по используемой версии jQuery на странице http://spservices.codeplex.com/documentation).
Напишем функцию получения подсказок:
function getSuggestions(input) {
    var queryText = "<QueryPacket xmlns='urn:Microsoft.Search.Query' Revision='1000'>"
    queryText += "<Query>"
    queryText += "<PreQuerySuggestions>"
    queryText += "true"
    queryText += "</PreQuerySuggestions>"
    queryText += "<Context>"
    queryText += "<QueryText language='RU-RU' type='STRING'>"
    queryText += input
    queryText += "</QueryText>"
    queryText += "</Context>"
    queryText += "<Range>"
    queryText += "<Count>"
    queryText += "20"
    queryText += "</Count>"
    queryText += "</Range>"
    queryText += "</Query>"
    queryText += "</QueryPacket>";

    $().SPServices({
        operation: "GetQuerySuggestions",
        queryXml: queryText,
        completefunc: function (xData, Status) {
            var outTxt = "";
            $(xData.responseXML).find("GetQuerySuggestionsResult").each(function () {
                //т.к. ответ от веб-сервиса приходит в формате XML, то его нужно преобразовать             
                var xmlDoc = $.parseXML($(this)[0].xml);
                var x = $(xmlDoc);
                x.find("string").each(function () {
                    outTxt += $(this).text() + ',';
                });
            });
            alert(outTxt);
        }
    });
}

В качестве аргумента функции передаем фразу, по которой хотим получить подсказки.
Например:
getSuggestions(“влади”);
В результате получаем набор подсказок, см. рисунок ниже.

Работаем на стороне сервера (C#)

Сам метод получения подсказок выглядит следующим образом:

        private static List<string> getSuggestionsList(string input)
        {
            List<string> result = new List<string>();
            Guid siteGuid = SPContext.Current.Web.Site.ID;
            using (SPSite site = new SPSite(siteGuid))
            {
                SPServiceContext serviceContext = SPServiceContext.GetContext(site);
                SearchServiceApplicationProxy searchAppProxy =
                    ((SearchServiceApplicationProxy)SearchServiceApplicationProxy.GetProxy(serviceContext));

                string queryId = Guid.NewGuid().ToString();
                string sessionId = Guid.NewGuid().ToString();
                KeywordQueryProperties info = new KeywordQueryProperties();
                info.RowLimit = 10;
                info.Culture = System.Globalization.CultureInfo.CreateSpecificCulture("RU-RU");
                info.QueryText = input;
                System.Collections.Specialized.StringCollection sugg = searchAppProxy.GetQuerySuggestions(info, 8, true, false, false);
                foreach (string s in sugg)
                {
                    result.Add(s);
                }
            }
            return result;
        }
Описание входных параметров метода GetQuerySuggestions приведены на msdn.

Получение исправлений (SpellingSuggestion)

Всем известен функционал предложения исправлений поискового запроса пользователя, который мы часто видим на странице результатов центра поиска в виде подсказки «Возможно, Вы имели ввиду: …»  или “Did you mean:…”

Ниже я привел метод, который позволяет получать такие подсказки:
  
private static string getSpellCheck(string input)
        {
            string result = "";
            Guid siteGuid = SPContext.Current.Web.Site.ID;
            using (SPSite site = new SPSite(siteGuid))
            {
                SPServiceContext serviceContext = SPServiceContext.GetContext(site);
                SearchServiceApplicationProxy searchAppProxy =
                    ((SearchServiceApplicationProxy)SearchServiceApplicationProxy.GetProxy(serviceContext));

                string queryId = Guid.NewGuid().ToString();
                string sessionId = Guid.NewGuid().ToString();
                KeywordQueryProperties info = new KeywordQueryProperties();
                info.RowLimit = 10;
                info.Culture = System.Globalization.CultureInfo.CreateSpecificCulture("RU-RU");
                info.QueryText = input;
                var sugg = searchAppProxy.Execute(info);
                result = sugg.SpellingSuggestion;
                if (!string.IsNullOrEmpty(result)&&result == input)
                    result = "";                
            }
            return result;
        }   
В результатах запроса Microsoft.Office.Server.Search.Query.ResultTableCollection  есть свойство SpellingSuggestion, которое как раз и выводит исправления. Чтобы его получить, нам достаточно выполнить сам запрос Execute(), и считать данное свойство. Таким образом, передавая в качестве аргумента текст «ивонов», мы получаем исправленное «иванов»:


Полезные ссылки: