Building a SharePoint 2013 Search Refiner with Custom Intervals


Introduction

SharePoint 2013 Search has really improved over its SharePoint 2010 predecessor. These improvements are down to the integration of the FAST search feature set into SharePoint 2013.

One of the nice features is the slider graph refiner which gives a visual representation of the results that can be filtered. However, unfortunately it doesn’t work well for custom managed properties.

Here is the refiner using the out of the box Last Modified Managed Property

clip_image002

Here is the refiner using a custom Date Time Managed Property called Timeline (this is the date of the document).

clip_image004

As you can see the date range is only for the last year, the numbers have commas in them and as the following image shows the descriptions for refining the data between the different intervals does not really make sense.

clip_image006

In a recent project this led to the decision to use a normal text refiner over the slider bar graph. However, the user base asked for the refinement options to be changed to a custom set of values. The out of the box date time refinement has the following options:-

· Last Year

· Last Six Months

· Last Month

· Last Week

· Last day

However the requirement was to have a custom set of refinements as shown below:-

timeline_datetime_refiner

Investigation

So to achieve the requirement above we need be able to do two things:-

· Configure how the refiner web part calculates the additional refiners

· Configure the text being used to display the refinement options to the user

How to configure the refinement calculations

The first thing that I did was have a look and see if there was anyone else who had tackled this issue and unfortunately I didn’t come up with much on MSDN or out there on the web.

The next step was to start looking at the customisation options for the web part.

By editing the web part properties and clicking on the “Choose Refiners” button you can decide which managed properties are going to be refinement options. Microsoft have given quite a lot of flexibility to custom the refiners but these options are not available for date/time data types . There are more options for the other data types such as text or number.

For example a managed property which is based on a number gives you the opportunity to create manual intervals to refine by.

clip_image007

However, a refiner based on a date/time data type doesn’t have much flexibility. This is probably easier to see via a screenshot.

clip_image009

There is an option to define the dates in the search schema but when that option is select then you get the following error message.

clip_image011

So this leads to the question what do I do now?

Quite often with web parts I start looking at the actual web part xml definition to try and workout if there are any appropriately named properties or values. So I exported the web part and opened up the web part in notepad.

After a lot of looking about I found the following web part property, “SelectedRefinementControlsJson”:-

clip_image013

This property contains a JSON string which defines the refinement control configuration. For each refiner that is selected a set of properties are stored within this string, these include properties such as

· sortBy

· sortOrder

· maxNumberOfRefinementItems

· DisplayTemplate

· etc

However, there were two properties which has interesting names and they were:-

clip_image015

clip_image017

I presumed that I could change the useDefaultDateIntervals to false and then provide some sort of JSON object for the intervals property. However, the difficult was trying to work out what the intervals structure would look like!

I started to debug the refiners using the Internet Explorer Developer Toolbar but didn’t really find much to help reverse engineer the process.

The approach that I quite often take is to examine the .NET code using a tool like Reflector. So it was time to reflect the appropriate web part. The refinement web part is of type:-

· Microsoft.Office.Server.Search.WebControls.RefinementScriptWebPart

After some searching I found the appropriate code.

The ResultScriptWebPart has a private method called GetRefinementControls() this instatiates another class called RefinementControl. A RefinementControl object is created for each Refinement Control JSON object and part of that object looks at the useDefaultDateIntervals property and if this has been set then the GetDefaultDateIntervalSpecString() is loaded.

clip_image019

The function GetDefaultDateIntervalSpecString() gives the clue of how the intervals parameter should be formatted.

clip_image021

So the intervals are basically an array of integers so the representation of this in JSON is the following:-

clip_image023

And of course to ensure that the custom intervals are loaded we need to change the useDefaultDateIntervals property to false.

clip_image025

So just to go back the intervals that have been set for the refiners are the number of days that should be removed from todays date to create the interval. The intervals -1065,-730,-365,-183,-30,-7, 0 translates to the less than 3+ years, 2-3 years, 1-2 years, 6 months to 1 year, 1-6 months, 1 week – 1 month and today.

So now we are able to control the refinement calculations, the next step is how to configure the labels displayed to the user.

If we don’t configure the labels we get the following being displayed to the user, which is obviously not good enough.

How to configure the refinement labels

Now I haven’t found a simpler solution for this but if anyone finds an alternative solution which for example overrides a particular web part property then please let me know.

The approach that I took in the end was to create my own filter display template. I haven’t covered display templates in my blog as yet. I am planning a post to discuss my findings with SharePoint 2013 Search development soon. However, the following articles provide some good information.

Anyway, display templates are found in the master page catalog document library which can be found at http://sharepoint/_catalogs/masterpage/displaytemplates. An alternate method to browse to this list is by going to the SharePoint site collection, click Site settings cog icon -> Site Settings->Master Pages and Page Layouts (under the Web Designer Galleries section).

All the out of box refinement filters can be found under the DisplayTemplates/Filters folder. I downloaded the Filter_Default.html file which is used as the standard out of the box text refinement filter. The file was renamed the file to Filter_CustomDateTime.html and edited in Visual Studio.

Here is an example of the contents of the Display Template

clip_image027

The <head> tag was updated to give a new title and then the following script was added which will go and set the labels presented to the end user. The JavaScript was added after all the default label data has been loaded, this was to ensure the custom configuration was not overwritten.

clip_image029

The display template was loaded back into SharePoint, I suggest that you put it in a custom folder and use a Module to deploy the file. In my example I am putting the filter in the following directory, Display Templates/iThinkSharePoint/.

Now we have the custom display template and we have configured our web part to use custom intervals there is one last step.

Can you guess what it is?

So we need to tell the web part to use our custom filter display template, this is another modification of the web part property, SelectedRefinementControlsJson. With some care look through the JSON string and find the refinement configuration for our custom Managed Property.

clip_image031

Now the web part configuration can be saved and uploaded into SharePoint as a new web part in the web part gallery.

Solution

So to recap the final solution has the following components:-

· Custom Web Part Configuration which includes the custom intervals, references the custom display template

· Custom Display Template for the Refinement control

This creates the following refiner:-

timeline_datetime_refiner

You can download the example Display Template and Web Part Configuration XML file from here:-

ITSPSearchRefineCustomIntervals.zip

If you find this useful please let me know and please ask if you need some more clarification.

SharePoint 2013 Search: Keep getting Search Results even when there is no query made


Introduction

This is a quick one which caused me some problems on a project I have been working on.

So a quick introduction to SharePoint 2013 Search. SharePoint 2010 had a feature in search called “Search Scopes” this provided a way to select the content that you wanted to return results from based on certain criteria. For example if it had a certain Content Type or was found in a particular location.

In SharePoint 2013 Scopes have been replaced by Result Sources which provide the same feature plus some much more powerful selection criteria using tokens. For example you can retrieve the user performing the search and return content where the user is the author.

Problem

The problem is that I have a search page which has both the search query web part and a search results web part.

After setting up a custom Result Source query to refine the results down I would always get results displaying, even before a query had been submitted search.

The Result Source is configured by:-

  • Browsing to the Site Collection
  • Click on the Site Settings Icon
  • Choose Site Settings->Site Collection Administration->Search Result Sources
  • Create a New Result Source
  • Part of the setup is to create the Query Transform, this brings up the window below

Here is what was setup:-ThisQueryAlwaysReturnsResults

The query always returns search results. Normally results only appear when you click on the Test tab, providing the search query and click Test Query.

This is a problem as because the search will always execute as the user goes on the page and is just plain messy.

So I spent sometime trying to work out what was going on.

Solution

I have to say the solution took sometime and it was only after re-reading the following Technet article http://technet.microsoft.com/en-us/library/dn186229.aspx#BKMK_How_does_query_transform_affect_query the section at the bottom “Narrowing search results by using a Query Transform” gave me the answer.

The key to all of this is that my query is not waiting for the search term before executing the search, it just always executes the search.

The example that the article provides is this:-

{?{searchTerms} ContentClass=urn:content-class:SPSPeople}

So that gave me the solution, the important thing is that if you want the query to wait for search terms to be filled in then wrap your query with curly brackets.

So the problem query goes from this:-

{searchTerms} (IsDocument=True AND (ContentTypeId:0x0101009CA89B0104F04692A106A1F88E847F7D*))

to this:-

{?{searchTerms} (IsDocument=True AND (ContentTypeId:0x0101009CA89B0104F04692A106A1F88E847F7D*))}

When I use the query above with the Query Transform this is the result, note the query returns no results.

ThisQueryWaitsforQueryBeforeReturnsResults

The query that I have will take any query and ensure that only search results that are documents that have a ContentTypeId which starts with a particular value.

I hope that helps someone!