Sitecore Azure Search Issues

As soon as Sitecore 8.2 came out with a PAAS option i adopted immediately for a client. The main driving factor was that the client was a Microsoft shop and the idea of having a java search tool (SOLR) was a hard thing for them to swallow. They loved the idea of Azure Search and bought into it immediately.

I had my concerns about using a new technology in Sitecore but i decided to give it a try anyway. I found a number of trouble spots, both with Sitecore’s implementation as well as some limitations of the tool in general.

Sitecore API bugs

Sitecore Search API unable to query by datetimes.

If you’re using Sitecore’s API to access the search index, which is Sitecore’s recommended way to go, you are unable to query by datetimes.  So if you’re making an event search tool, you might want to either reconsider using Sitecore’s search API or go with a direct to Azure Search solution.

Cannot query for ID right after an app pool recycle

Immediately following an app pool recycle the Sitecore search api is unable to query by item ID.  This however can be alleviated if you go direct to the index.

Azure Search shortcomings

 

Azure Search only facets with AND logic never OR logic

A very common search scenario is to have the logic be OR within a particular grouping then and between groups.  For example, if you are looking for a new PC you might want to search for a PC that has an I7 processor and is in the price range of 600 – 1200 dollars, if you’re give range facets of 600 – 800, 800 – 1000, and 1000 – 1200.  Logically you would want to select all 3 options to have the range and processor you want.  However the faceting in Azure Search makes it not possible to do this, as soon as you select 600 – 800 all the other options will disappear as there can’t be computers that fall under 2 separate price ranges.

Hypothetically it would be possible to overcome this by making multiple queries to the index, however it would be a quite complex solution and increase the load on your index by potentially many times.

There is no ability to use wild cards in filters

The only wild cards that are accepted are in the text search query, not for filters.  Say for example you’re creating a search for restaurants and you want to give the user the ability to search for a city and text search.  You need to assume that the user typed the entire city name and not just a fragment in order to get any results.

As far as i can figure there isn’t a reasonable way to overcome this issue.

Recommendation

As it stands i would certainly recommend using SOLR in the cloud if you want to do any amount of work with the index.  A good cloud set up i have used is to set up an IAAS VM running SOLR and a virtual network into your PAAS Sitecore environment for fast connectivity.  Strangely enough, this also seems to cost less money than Azure Search.

Direct To Azure Search API

While i don’t recommend it at this time, the tool itself was quite easy to work with directly. Take a look at the documentation  to get started.

Here is an example of taking the connection string Sitecore uses and creating an Azure Search API object.

			ConnectionStringSettings search = ConfigurationManager.ConnectionStrings["cloud.search"];
			if (search == null)
				throw new Exception("Missing connection string for Azure Search");
			Dictionary<string, string> connStringParts = search.ConnectionString.Split(';')
	.Select(t => t.Split(new char[] { '=' }, 2))
	.ToDictionary(t => t[0].Trim(), t => t[1].Trim(), StringComparer.InvariantCultureIgnoreCase);
			try
			{
				SearchServiceClient client = new SearchServiceClient(new Uri(connStringParts["serviceUrl"]),
					new SearchCredentials(connStringParts["apiKey"]));
			//use or cache client
			}
			catch (Exception e)
			{
				throw new Exception("Unable to use connection string values", e);
			}

This is an example of using the index to set up a search with faceting, pagination, and sorting.  Note that i’m using a constants class to abstract away string literals.

			SearchParameters parameters = new SearchParameters
			{
				QueryType = QueryType.Simple,
				Skip = page * 10,
				IncludeTotalResultCount = true,
				Top = 10,
				SearchFields = new List<string>
				{
					AzureSearchConstants.FirstName,
					AzureSearchConstants.LastName,
					AzureSearchConstants.GroupName,
					AzureSearchConstants.LocationName,
					AzureSearchConstants.Address,
					AzureSearchConstants.City,
					AzureSearchConstants.County,
					AzureSearchConstants.State,
					AzureSearchConstants.Zip
				},
				Filter = facetQuery.ToString(),
				Facets = new List<string> { AzureSearchConstants.TypeDescription }
				OrderBy = new List<string> { AzureSearchConstants.LastName }
			};
			var index = _client.Indexes.GetClient(AzureSearchConstants.IndexName);
			var results = index.Documents.Search(query.Trim().Replace(" ", "* ") + '*', parameters);