Azure 认知搜索中的 OData 地理空间函数 - geo.distancegeo.intersectsOData geo-spatial functions in Azure Cognitive Search - geo.distance and geo.intersects

Azure 认知搜索支持使用 geo.distancegeo.intersects 函数通过 OData 筛选器表达式进行地理空间查询。Azure Cognitive Search supports geo-spatial queries in OData filter expressions via the geo.distance and geo.intersects functions. geo.distance 函数以公里为单位返回两点之间的距离,一个点是字段或范围变量,另一个点是作为筛选器一部分传递的常量。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. 如果给定的点位于给定的多边形范围内(其中该点是字段或范围变量,多边形指定为作为筛选器一部分传递的常量),geo.intersects 函数会返回 trueThe 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 函数也可用在 $orderby 参数中,以便按照与给定点的距离对搜索结果排序。The geo.distance function can also be used in the $orderby parameter to sort search results by distance from a given point. $orderbygeo.distance 的语法与其在 $filter 中的语法相同。The syntax for geo.distance in $orderby is the same as it is in $filter. 如果在 $orderby 中使用 geo.distance,则它应用到的字段必须为 Edm.GeographyPoint 类型,而且它还必须是可排序的When using geo.distance in $orderby, the field to which it applies must be of type Edm.GeographyPoint and it must also be sortable.


$orderby 参数中使用 geo.distance 时,传递给函数的字段只能包含单个地理点。When using geo.distance in the $orderby parameter, the field you pass to the function must contain only a single geo-point. 换言之,它必须是类型 Edm.GeographyPoint 而非 Collection(Edm.GeographyPoint)In other words, it must be of type Edm.GeographyPoint and not Collection(Edm.GeographyPoint). 不可能在 Azure 认知搜索中对集合字段排序。It is not possible to sort on collection fields in Azure Cognitive Search.


以下 EBNF(扩展巴科斯-瑙尔范式)定义了 geo.distancegeo.intersects 函数的语法,以及这些函数运算时依据的地理空间值:The following EBNF (Extended Backus-Naur Form) defines the grammar of the geo.distance and 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:


geo.distance 函数使用两个类型为 Edm.GeographyPoint 的参数并返回一个 Edm.Double 值,该值是二者之间的距离,以公里为单位。The geo.distance function takes two parameters of type Edm.GeographyPoint and returns an Edm.Double value that is the distance between them in kilometers. 这与支持 OData 地理空间运算的其他服务不同,后者通常以米为单位返回距离。This differs from other services that support OData geo-spatial operations, which typically return distances in meters.

geo.distance 的一个参数必须是地理点常量,另一个参数必须是字段路径(如果针对类型为 Collection(Edm.GeographyPoint) 的字段进行筛选器迭代,则另一个参数必须是范围变量)。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.

地理点常量采用 geography'POINT(<longitude> <latitude>)' 形式,其中的经度和纬度为数字常量。The geography point constant is of the form geography'POINT(<longitude> <latitude>)', where the longitude and latitude are numeric constants.


如果在筛选器中使用 geo.distance,则必须使用 ltlegtge 将函数返回的距离与常量进行比较。When using geo.distance in a filter, you must compare the distance returned by the function with a constant using lt, le, gt, or ge. 比较距离时不支持使用 eqne 运算符。The operators eq and ne are not supported when comparing distances. 例如,这是 geo.distance 的正确用法:$filter=geo.distance(location, geography'POINT(-122.131577 47.678581)') le 5For example, this is a correct usage of geo.distance: $filter=geo.distance(location, geography'POINT(-122.131577 47.678581)') le 5.


geo.intersects 函数使用类型为 Edm.GeographyPoint 的变量并使用常量 Edm.GeographyPolygon,在点位于多边形边界内的情况下返回 Edm.Boolean -- true,否则返回 falseThe geo.intersects function takes a variable of type Edm.GeographyPoint and a constant Edm.GeographyPolygon and returns an Edm.Boolean -- true if the point is within the bounds of the polygon, false otherwise.

多边形是二维表面,作为定义边界环的一系列点存储(参见以下示例)。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.

跨越 180 度经线的地理空间查询和多边形Geo-spatial queries and polygons spanning the 180th meridian

对于许多地理空间查询库,构建包含 180 度经线(国际日期变更线附近)的查询要么被禁止,要么需要变通方法,例如将多边形拆分为两个,子午线两侧各一个。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.

在 Azure 认知搜索中,如果查询形状为矩形并且坐标沿经度和纬度方向与网格布局对齐(例如,geo.intersects(location, geography'POLYGON((179 65, 179 66, -179 66, -179 65, 179 65))'),则包含 180 度经度的地理空间查询将按预期工作。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.

地理空间函数和 nullGeo-spatial functions and null

与 Azure 认知搜索中的所有其他非集合字段一样,类型为 Edm.GeographyPoint 的字段可以包含 null 值。Like all other non-collection fields in Azure Cognitive Search, fields of type Edm.GeographyPoint can contain null values. 当 Azure 认知搜索对 null 字段的 geo.intersects 求值时,结果始终为 falseWhen Azure Cognitive Search evaluates geo.intersects for a field that is null, the result will always be false. 在这种情况下,geo.distance 的行为取决于上下文:The behavior of geo.distance in this case depends on the context:

  • 在筛选器中,null 字段的 geo.distance 会生成 nullIn filters, geo.distance of a null field results in null. 这意味着文档不会匹配,因为与任何非 null 值一比较,null 的求值结果均为 falseThis means the document will not match because null compared to any non-null value evaluates to false.
  • 使用 $orderby 对结果排序时,null 字段的 geo.distance 会生成最大的可能距离。When sorting results using $orderby, geo.distance of a null field results in the maximum possible distance. 包含此类字段的文档在使用排序方向 asc(默认)排序时其位置会低于所有其他文档,在方向为 desc 时会高于所有其他文档。Documents with such a field will sort lower than all others when the sort direction asc is used (the default), and higher than all others when the direction is desc.


筛选器示例Filter examples

查找与给定参考点的距离在 10 公里范围内的所有酒店(其中 location 是 Edm.GeographyPoint 类型的字段):Find all hotels within 10 kilometers of a given reference point (where location is a field of type Edm.GeographyPoint):

    geo.distance(location, geography'POINT(-122.131577 47.678581)') le 10

查找描述为多边形的给定视区内的所有酒店(其中 location 是 Edm.GeographyPoint 类型的字段)。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))')

Order-by 示例Order-by examples

rating 对酒店进行降序排序,然后按距给定坐标的距离进行升序排序: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

search.scorerating 对酒店进行降序排序,然后按距给定坐标的距离进行升序排序,以便在两个具有相同评分的酒店中,将距离最近的酒店列在前面:Sort hotels in descending order by search.score and 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

后续步骤Next steps