This content is retired. See latest version here.

Last updated: Jun 10 2014

The REST API supports geo search, searching based on geographical coordinates and distances, in a number of ways. For the server to recognize that a certain pair of numbers are coordinates the field needs to be mapped as a geo point. However, through conventions, both on the server side and in the .NET API no mapping is needed as long as geographical locations are exposed as instance of the GeoLocation class. In other words, to utilize the geo search functionality indexed objects should either have a property of type GeoLocation or a custom mapping, such as an extension method, that returns a GeoLocation.

Once objects with locations have been indexed they can be filtered using the Within and WithinDistanceFrom extension methods in a filter expression.

Finding documents within a certain distance from a location

Assume we have the following class:

C#
using EPiServer.Find;

public class Restaurant
{
    public string Name { get; set; }

    public GeoLocation Location { get; set; }
}

And we create and index three instances of it with locations in Stockholm:

var closeToSergelsTorg = new Restaurant()
    {
        Name = "City steakhouse",
        Location = new GeoLocation(59.33265, 18.06468)
    };

var atSlussen = new Restaurant()
{
    Name = "Vegetarian place",
    Location = new GeoLocation(59.32067, 18.07294)
};

var atSkanstull = new Restaurant()
{
    Name = "Food and beer inn",
    Location = new GeoLocation(59.30792, 18.07672)
};

client.Index(closeToSergelsTorg,
                atSlussen,
                atSkanstull);

In the example above we created three restaurants, one close to Sergels torg in the centre of Stockholm and two in another part of Stockholm, Sdermalm.

We can now find restaurants close to Sergels torg by searching for the Restaurant type and filter out documents whose Location property are not within a kilometers distance from Sergels torg:

var sergelsTorg = new GeoLocation(59.33234, 18.06291);

var result = client.Search<Restaurant>()
    .Filter(x => x.Location.WithinDistanceFrom(sergelsTorg, 1.Kilometer()))
    .GetResult();

This will produce a single hit, the restaurant close to Sergels torg.

It is also possible to search for documents whose range from a location is within a specific range:

C#
result = client.Search<Restaurant>()
    .Filter(x => 
        x.Location.WithinDistanceFrom(
        sergelsTorg, 
        1.Kilometer(), 
        2.Kilometers()))
    .GetResult();

Note the use of the two extension methods Kilometer and Kilometers above. The WithinDistanceFrom method requires distances as either miles or kilometers which is represented by the abstract GeoDistance type and its sub classes Kilometer and Miles. The extension methods used above offer a convenient way of creating instances of the Kilometer class which is a sub class of GeoDistance. Simillar extension methods exist for miles.

Finding documents with locations in an area

Using the Within method it is also possible to search for documents within an area represented by at least three coordinates. For instance, assume we have the following helper class with coordinates that describe Sdermalm in Stockholm (found using Google maps).

C#
using System.Collections.Generic;
using EPiServer.Find;

public class CoordinatesOf
{
    public static IEnumerable<GeoLocation> Sodermalm
    {
        get
        {
            yield return new GeoLocation(59.32194, 18.07148);
            yield return new GeoLocation(59.32154, 18.07483);
            yield return new GeoLocation(59.32045, 18.07457);
            yield return new GeoLocation(59.31607, 18.10727);
            yield return new GeoLocation(59.30718, 18.09792);
            yield return new GeoLocation(59.30350, 18.07989);
            yield return new GeoLocation(59.30284, 18.07105);
            yield return new GeoLocation(59.30827, 18.04925);
            yield return new GeoLocation(59.31015, 18.03955);
            yield return new GeoLocation(59.31598, 18.02582);
            yield return new GeoLocation(59.31830, 18.02599);
            yield return new GeoLocation(59.31927, 18.02745);
            yield return new GeoLocation(59.31979, 18.03140);
            yield return new GeoLocation(59.32154, 18.05097);
        }
    }
}

We can then use the Within method to find restaurants on Sdermalm:

C#
result = client.Search<Restaurant>()
    .Filter(x =>
        x.Location.Within(CoordinatesOf.Sodermalm))
    .GetResult();

Sorting by geographical distance

Search hits can be ordered by a GeoLocation fields distance from a specific location using the OrderBy and OrderByDescending methods. As an example, the below code will order search results by their closeness to Sergels Torg in Stockholm.

C#
var sergelsTorg = new GeoLocation(59.33234, 18.06291);

var result = client.Search<Restaurant>()
    .OrderBy(x => x.Location).DistanceFrom(sergelsTorg)
    .GetResult();

Any matching documents that do not have a location at all will be ordered last when sorting with the OrderBy method and first when sorting with the OrderByDescending methods.

Aggregations/facets

Apart from filtering and sorting by geographical coordinates/distance it's also possible to count how many documents/locations are within certain distances from a specific location using the GeoDistanceFacetFor method. See the separate documentation for geographical distance facets.

Comments