OData geo-spatial functions in Azure Cognitive Search -
Azure Cognitive Search supports geo-spatial queries in OData filter expressions via the
geo.intersects functions. The
geo.distance function returns the distance in kilometers between two points, one being a field or range variable, and one being a constant passed as part of the filter. The
geo.intersects function returns
true if a given point is within a given polygon, where the point is a field or range variable and the polygon is specified as a constant passed as part of the filter.
geo.distance function can also be used in the $orderby parameter to sort search results by distance from a given point. The syntax for
geo.distance in $orderby is the same as it is in $filter. When using
geo.distance in $orderby, the field to which it applies must be of type
Edm.GeographyPoint and it must also be sortable.
geo.distance in the $orderby parameter, the field you pass to the function must contain only a single geo-point. In other words, it must be of type
Edm.GeographyPoint and not
Collection(Edm.GeographyPoint). It is not possible to sort on collection fields in Azure Cognitive Search.
The following EBNF (Extended Backus-Naur Form) defines the grammar of the
geo.intersects functions, as well as the geo-spatial values on which they operate:
geo_distance_call ::= 'geo.distance(' variable ',' geo_point ')' | 'geo.distance(' geo_point ',' variable ')' geo_point ::= "geography'POINT(" lon_lat ")'" lon_lat ::= float_literal ' ' float_literal geo_intersects_call ::= 'geo.intersects(' variable ',' geo_polygon ')' /* You need at least four points to form a polygon, where the first and last points are the same. */ geo_polygon ::= "geography'POLYGON((" lon_lat ',' lon_lat ',' lon_lat ',' lon_lat_list "))'" lon_lat_list ::= lon_lat(',' lon_lat)*
An interactive syntax diagram is also available:
See OData expression syntax reference for Azure Cognitive Search for the complete EBNF.
geo.distance function takes two parameters of type
Edm.GeographyPoint and returns an
Edm.Double value that is the distance between them in kilometers. This differs from other services that support OData geo-spatial operations, which typically return distances in meters.
One of the parameters to
geo.distance must be a geography point constant, and the other must be a field path (or a range variable in the case of a filter iterating over a field of type
Collection(Edm.GeographyPoint)). The order of these parameters doesn't matter.
The geography point constant is of the form
geography'POINT(<longitude> <latitude>)', where the longitude and latitude are numeric constants.
geo.distance in a filter, you must compare the distance returned by the function with a constant using
ge. The operators
ne are not supported when comparing distances. For example, this is a correct usage of
$filter=geo.distance(location, geography'POINT(-122.131577 47.678581)') le 5.
geo.intersects function takes a variable of type
Edm.GeographyPoint and a constant
Edm.GeographyPolygon and returns an
true if the point is within the bounds of the polygon,
The polygon is a two-dimensional surface stored as a sequence of points defining a bounding ring (see the examples below). The polygon needs to be closed, meaning the first and last point sets must be the same. Points in a polygon must be in counterclockwise order.
Geo-spatial queries and polygons spanning the 180th meridian
For many geo-spatial query libraries formulating a query that includes the 180th meridian (near the dateline) is either off-limits or requires a workaround, such as splitting the polygon into two, one on either side of the meridian.
In Azure Cognitive Search, geo-spatial queries that include 180-degree longitude will work as expected if the query shape is rectangular and your coordinates align to a grid layout along longitude and latitude (for example,
geo.intersects(location, geography'POLYGON((179 65, 179 66, -179 66, -179 65, 179 65))'). Otherwise, for non-rectangular or unaligned shapes, consider the split polygon approach.
Geo-spatial functions and
Like all other non-collection fields in Azure Cognitive Search, fields of type
Edm.GeographyPoint can contain
null values. When Azure Cognitive Search evaluates
geo.intersects for a field that is
null, the result will always be
false. The behavior of
geo.distance in this case depends on the context:
- In filters,
nullfield results in
null. This means the document will not match because
nullcompared to any non-null value evaluates to
- When sorting results using $orderby,
nullfield results in the maximum possible distance. Documents with such a field will sort lower than all others when the sort direction
ascis used (the default), and higher than all others when the direction is
Find all hotels within 10 kilometers of a given reference point (where location is a field of type
geo.distance(location, geography'POINT(-122.131577 47.678581)') le 10
Find all hotels within a given viewport described as a polygon (where location is a field of type
Edm.GeographyPoint). Note that the polygon is closed (the first and last point sets must be the same) and the points must be listed in counterclockwise order.
geo.intersects(location, geography'POLYGON((-122.031577 47.578581, -122.031577 47.678581, -122.131577 47.678581, -122.031577 47.578581))')
Sort hotels descending by
rating, then ascending by distance from the given coordinates:
rating desc,geo.distance(location, geography'POINT(-122.131577 47.678581)') asc
Sort hotels in descending order by
rating, and then in ascending order by distance from the given coordinates so that between two hotels with identical ratings, the closest one is listed first:
search.score() desc,rating desc,geo.distance(location, geography'POINT(-122.131577 47.678581)') asc