8

With regard to spatial searching capabilities of Azure Search in Sitecore. How do you go about customising your index configuration so that you can perform spatial searching using the OData geospatial data types?

The actual data type is EDM.GeographyPoint and seems to be the only data type officially not supported by the Sitecore Azure Search Provider. Or it has been left off the documentation of supported types.

The required storage format is supposed to conform to GeoJson.

1 Answer 1

9

Crawling (getting data into Azure Search)

On the indexing side of things I was able to achieve this in Sitecore 9 by taking the following steps:

  • Create a custom index configuration for my customer Index. I didn't want to disrupt the standard out the box indexes.
  • Defined a computed field that read in a Lat Long from my Sitecore Items. The computed field returned a GeoJson object:

using System.Collections.Generic;
using Newtonsoft.Json;
public class GeoJson
{
    [JsonProperty(PropertyName = "coordinates")]
    public List<double> Coordinates { get; set; }
    [JsonProperty(PropertyName = "type")]
    public string Type { get; set; }
}
  • In your index configuration override the standard indexFieldStorageValueFormatter with your own implementation. Your implementation will override CloudIndexFieldStorageValueFormatter.cs and the method FormatValueForIndexStorage:

public override object FormatValueForIndexStorage(object value, string fieldName)
{
    object obj = value;
    if (!string.IsNullOrWhiteSpace(fieldName) && 
        fieldName.ToLower().StartsWith("geo_"))
          return obj;
    return base.FormatValueForIndexStorage(value, fieldName);
}

This is necessary because EDM.GeographyPoint is not supported and native EDM data type by Sitecore. Without this Sitecore's code will throw an exception when indexing.

  • Added a new map to the custom index configuration.

<cloudTypeMapper ref="contentSearch/indexConfigurations/defaultCloudIndexConfiguration/cloudTypeMapper">
  <maps hint="raw:AddMap">
    <map type="AAA.Foundation.Geo.Models.GeoJson, AAA.Foundation.Geo" cloudType="Edm.GeographyPoint"/>
  </maps>
</cloudTypeMapper>
  • Added a new cloudTypeConfiguration for my custom index

<cloudTypeConfiguration ref="contentSearch/indexConfigurations/defaultCloudIndexConfiguration/cloudTypeConfiguration">
  <types hint="raw:AddType">
    <type cloudType="Edm.GeographyPoint" cloudFieldNameFormat="{0}_g"/>
  </types>
</cloudTypeConfiguration>
  • Add in a field map to your custom index configuration. This must match the computed field name added in an earlier step.

<fieldMap ref="contentSearch/indexConfigurations/defaultCloudIndexConfiguration/fieldMap">
  <fieldNames hint="raw:AddFieldByFieldName">
    <field fieldName="geo_location" cloudFieldName="geo_location" searchable="NO" retrievable="YES" facetable="NO" filterable="YES" sortable="YES" boost="1f" type="AAA.Foundation.Geo.Models.GeoJson, AAA.Foundation.Geo" settingType="Sitecore.ContentSearch.Azure.CloudSearchFieldConfiguration, Sitecore.ContentSearch.Azure" />
  </fieldNames>
</fieldMap>

Searching (getting data out of Azure Search)

Although I did find a way to extend the Sitecore Azure Search Provider it did not support the OrderBy clause which is very useful for fast queries in spatial searches.

The best solution I found was the use the Azure Search DLL library directly (Microsoft.Azure.Search).

With this you can connect directly to your index and use the syntax as follows:

$"geo.distance({fieldName}, geography'POINT({coordinate.Longitude} {coordinate.Latitude})') le {settingsSearchRadius}"

This will find all results from a particular location up to a given radius.

A full searching example can be found here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.