Suggestive Search with Sitecore 7
If you’ve used Sitecore 7 search with the Solr provider you may know that suggestive search functionality comes pretty much out-of-the-box. However if you’re using the Lucene provider there’s a bit more work to be done. Here’s how.
The Solr way
For users of the Solr provider there’s a good post here on how to get a suggestive search running:
http://www.norconex.com/serving-autocomplete-suggestions-fast/
Solr has an HTTP API which you can call directly using JavaScript, but has no concept of security so you’ll want to make sure you lock down requests made by your Sitecore site to Solr by using a reverse proxy. More info here:
http://opensourceconnections.com/blog/2013/06/17/lockdown-solr-with-iis-as-a-reverse-proxy/
The Lucene way
Firstly decide what field you’ll search on. As you’ll probably be surfacing pages rather than Sitecore data items from the search box it’s sensible to use a field that will be specific to a Sitecore page. I normally use a Navigation Title for a page.
Next setup an endpoint for your javascript autocomplete to call.
For this example I’ve setup a WCF service but you could also setup a Restful Web API service. Great article on this here: http://nttdatasitecore.com/Blog/2014/August/Create-a-RESTful-web-service-in-Sitecore-with-Web-API.
The service will have one method that will accept the term and return a list of suggestions based on the term.
using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Web;
using Coreblimey.Entities.Search;
namespace Coreblimey.WebApplication.Services
{
[ServiceContract]
public interface ISearch
{
[OperationContract]
[WebInvoke(Method = "GET",BodyStyle = WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json)]
[return: MessageParameter(Name = "suggestions")]
List<AutoCompleteSuggestion> AutoCompleteTerm()
}
}
The magic that makes the auto suggest work is the GetTermsByFieldName method that is part of the Sitecore.ContentSearch.IProviderSearchContext.
The method allows you to specify the prefix of the word and the field name you are searching on and it will squirt out results based on the criteria.
using System;
using System;
using System.Collections.Generic;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using Coreblimey.Entities.Search;
namespace Coreblimey.WebApplication.Services
{
[AspNetCompatibilityRequirements(RequirementsMode =AspNetCompatibilityRequirementsMode.Allowed)]
public class Search : ISearch
{
public List<AutoCompleteSuggestion> AutoCompleteTerm()
{
var list = new List<AutoCompleteSuggestion>();
if (WebOperationContext.Current == null)
return list;
var term = WebOperationContext.Current.IncomingRequest.UriTemplateMatch.QueryParameters[Enumerators.Settings.Global.QueryStringNames.Term];
if (String.IsNullOrEmpty(term))
return list;
var index = Sitecore.ContentSearch.ContentSearchManager.GetIndex(Sitecore.Configuration.Settings.GetSetting("SearchIndex.Index"));
using (var context = index.CreateSearchContext())
{
// You need to specifiy the field name as it is stored in the index
var suggestions = context.GetTermsByFieldName("navigation_title", term);
foreach (var suggestion in suggestions)
{
list.Add(new AutoCompleteSuggestion { Suggestion = suggestion.Term});
}
}
}
return list;
}
}
using System;
using System.Runtime.Serialization;
namespace Coreblimey.Entities.Search
{
[DataContract]
public class AutoCompleteSuggestion
{
[DataMember(Name="suggestion")]
public String Suggestion { get; set; }
}
}
Make sure you’ve registered an endpoint in your web.config ….
<services>
<service behaviorConfiguration="Coreblimey.WebApplication.Services.SearchServiceBehavior" name="Coreblimey.WebApplication.Services.Search">
<endpoint address="" behaviorConfiguration="restBehavior" binding="webHttpBinding" contract="Coreblimey.WebApplication.Services.ISearch" />
</service>
</services>
</system.serviceModel>
And you’ll want to add .svc to the list of allowed extensions in your web.config so that Sitecore will not interupt any requests.
<processor type="Sitecore.Pipelines.PreprocessRequest.FilterUrlExtensions, Sitecore.Kernel">
<param desc="Allowed extensions (comma separated)">aspx, ashx, asmx, svc</param>
<param desc="Blocked extensions (comma separated)">*</param>
<param desc="Blocked extensions that stream files (comma separated)">*</param>
<param desc="Blocked extensions that do not stream files (comma separated)" />
</processor>
All being well, you’ll be able to call the WCF using get requests like this:
/Search.svc/AutoCompleteTerm?term=about
You can hook this up to your favourite autocomplete library
https://twitter.github.io/typeahead.js
http://jqueryui.com/autocomplete
Apply some colouring-in and you’ll have something like this!
Anyway, hope this has helped someone.
Happy Sitecoring!
Ian