地理距离过滤器

地理距离过滤器geo_distance)以给定位置为圆心画一个圆,来找出那些位置落在其中的文档:

GET /attractions/restaurant/_search
{
  "query": {
    "filtered": {
      "filter": {
        "geo_distance": {
          "distance": "1km", <1>
          "location": { <2>
            "lat":  40.715,
            "lon": -73.988
          }
        }
      }
    }
  }
}
  • <1> 找出所有与指定点距离在1公里(1km)内的 location 字段。访问 Distance Units 查看所支持的距离表示单位
  • <2> 中心点可以表示为字符串,数组或者(如示例中的)对象。详见 lat-lon-formats

地理距离过滤器计算代价昂贵。 为了优化性能,Elasticsearch 先画一个矩形框(边长为2倍距离)来围住整个圆形, 这样就可以用消耗较少的盒模型计算方式来排除掉那些不在盒子内(自然也不在圆形内)的文档, 然后只对落在盒模型内的这部分点用地理坐标计算方式处理。

提示

你需要判断你的使用场景,是否需要如此精确的使用圆模型来做距离过滤? 通常使用矩形模型是更高效的方式,并且往往也能满足应用需求。

更快的地理距离计算

两点间的距离计算,有多种性能换精度的算法:

  • arc:: 最慢但是最精确是弧形arc)计算方式,这种方式把世界当作是球体来处理。 不过这种方式精度还是有限,因为这个世界并不是完全的球体。
  • plane:: 平面plane)计算方式,((("plane distance calculation")))把地球当成是平坦的。 这种方式快一些但是精度略逊;在赤道附近位置精度最好,而靠近两极则变差。
  • sloppy_arc:: 如此命名,是因为它使用了 Lucene 的 SloppyMath 类。 这是一种用精度换取速度的计算方式,它使用 Haversine formula 来计算距离; 它比弧形arc)计算方式快4~5倍, 并且距离精度达99.9%。这也是默认的计算方式。

你可以参考下例来指定不同的计算方式:

GET /attractions/restaurant/_search
{
  "query": {
    "filtered": {
      "filter": {
        "geo_distance": {
          "distance":      "1km",
          "distance_type": "plane", <1>
          "location": {
            "lat":  40.715,
            "lon": -73.988
          }
        }
      }
    }
  }
}
  • <1> 使用更快但精度稍差的平面plane)计算方式。

提示: 你的用户真的会在意一个宾馆落在指定圆形区域数米之外了吗? 一些地理位置相关的应用会有较高的精度要求;但大部分实际应用场景中,使用精度较低但响应更快的计算方式可能就挺好。

地理距离区间过滤器

地理距离过滤器geo_distance)和地理距离区间过滤器geo_distance_range)的唯一差别在于后者是一个环状的,它会排除掉落在内圈中的那部分文档。

指定到中心点的距离也可以换一种表示方式: 指定一个最小距离(使用 gt或者gte)和最大距离(使用lt或者lte),就像使用区间range)过滤器一样。

GET /attractions/restaurant/_search
{
  "query": {
    "filtered": {
      "filter": {
        "geo_distance_range": {
          "gte":    "1km", <1>
          "lt":     "2km", <1>
          "location": {
            "lat":  40.715,
            "lon": -73.988
          }
        }
      }
    }
  }
}
  • <1> 匹配那些距离中心点超过1公里而小于2公里的位置。