At my current customer we recently deployed SharePoint 2013 search, but we don’t seem to get any search suggestions in the search box, thus search-as-you-type in the search box never show anything.
Before diving into the reason behind it all, the solution is to add &clienttype=ContentSearchRegular to all search REST/API calls where you know you will do custom rendering of the result and have no intention to implement the RecordPageClick event when users click on of the result items.
The scenario
When users run search queries and click results, those clicks are recorded back to SharePoint. Once a certain query term have been ran at least six times where an item is clicked, the term is added to the list of query suggestions served by the search box on a search center.These suggestions help future users to formulate better queries and to get better search results.
The problem
By default a SharePoint tenant will be able to log result clicks for 65.000 items per day. This can be found by the following PowerShell command:(Get-SPEnterpriseSearchServiceApplication).QueryLogSettings
which will yield the following output:
QLogEnabled : True CleanupDays : 365 LoggingPercent : 100 TenantDailyLimit : 65000
Here you see the 65.000 daily limit and the logging percent means it will log all queries coming in. If you set it to 50%, about half of the requests will not be made available for logging.
So what do I mean by made available for logging? When you run a search query a property is returned in the result set named piPageImpression. The value of this property is essential for RecordPageClick to work. If it’s missing no result clicks are logged.
In our SharePoint solution we have in addition to 2013 search also delivered a highly customized search driven intranet. The front page itself have at least five search queries going, and renders the result in a custom UI using JavaScript. There is and was never no intention to feed the clicks of results back from the front page, and it wouldn’t make sense either as the queries are all programmed – not user queries. Being good citizens we have actually added clientype=MyCustomer to all REST calls, but this only allows stats to differentiate the calls, it will not impact using id’s from the piPageImpression daily pool of 65.000 items.
With five calls on the home page alone and 10.000 employees hitting the intranet every time they open their browser, those 65.000 id’s are quickly spent before a single user manage to navigate to the search page and record a proper search click. By the time coffee kicks in for a random employee the FAST search engine is no longer service out piPageImpression id’s and any clicks on results is moot (from a record query suggestion perspective).
The hacky solution
Tell your SP admin to crank up the value of QueryLogSettings to be able to generate more piPageImpression id’s per day.The proper solution
I first noticed the piPageImpression value was missing for some queries. Next I reflected some SharePoint dll’s and figured piPageImpression was required to record page clicks. So what piece of code generated this value for the search result set? And why did I miss it in the production environment, but was seeing the value in stage, test and development environments? Some more digging led me to the internal Microsoft.Office.Server.Search.Query.QueryProcessor.RecordPageImpression method. A bit down in the function SharePoint checks if client type is 14, 15 or 25, and in those three cases it will NOT generate a piPageImpression id, which is what we want.If you have used the SharePoint 2013 Query tool you might have noticed a drop down list for Client Type.
But how do these names correlate to 14, 15 and 25? Open SQL Management studio, point it to your Search DB and run the following SQL command
select id, name from dbo.MSQLogClientType order by id
and you will get a list of all the names with associated id’s. The description of each one can be found at https://msdn.microsoft.com/en-us/library/ff386740%28v=office.12%29.aspx
- 14 = ContentSearchHigh
The search query is sent from a Content Search Web Part where the priority is set to "high". - 15 = ContentSearchRegular
The search query is sent from a Content Search Web Part where the priority is set to "regular". - 25 = Monitoring
This value MUST NOT be used.
Since the doc says NOT to use Monitoring, I figured using ContentSearchRegular as your default client type value is the way to go. When you are using the API to search you are in many ways mimicking the CSWP and thus this is the client value to use. If you are creating a custom search result page, then my all means send in something smart like MyCustomer, but then it’s your responsibility to also implement RecordPageClick when a user clicks a result.