1、地理坐标点

地理坐标点 是指地球表面可以用经纬度描述的一个点。 地理坐标点可以用来计算两个坐标间的距离,还可以判断一个坐标是否在一个区域中,或在聚合中。

地理坐标点不能被动态映射(dynamic mapping)自动检测,而是需要显式声明对应字段类型为 geo-point

PUT /attractions
{
  "mappings": {
    "restaurant": {
      "properties": {
        "name": {
          "type": "string"
        },
        "location": {
          "type": "geo_point"
        }
      }
    }
  }
}

2、经纬度坐标格式

如上例,location 字段被声明为 geo_point 后,我们就可以索引包含了经纬度信息的文档了。经纬度信息的形式可以是字符串、数组或者对象:

地理坐标点用字符串形式表示时是纬度在前,经度在后( "latitude,longitude" ),而数组形式表示时是经度在前,纬度在后( [longitude,latitude] )—顺序刚好相反。

UT /attractions/restaurant/1
{
  "name":     "Chipotle Mexican Grill",
  "location": "40.715, -74.011" 
}

PUT /attractions/restaurant/2
{
  "name":     "Pala Pizza",
  "location": { 
    "lat":     40.722,
    "lon":    -73.989
  }
}

PUT /attractions/restaurant/3
{
  "name":     "Mini Munchies Pizza",
  "location": [ -73.983, 40.719 ] 
}

3、通过地理坐标点过滤

1、geo_bounding_box

这是目前为止最有效的地理坐标过滤器了,因为它计算起来非常简单。 你指定一个矩形的 顶部 , 底部 , 左边界 ,和 右边界 ,然后过滤器只需判断坐标的经度是否在左右边界之间,纬度是否在上下边界之间:

GET /attractions/restaurant/_search
{
  "query": {
    "filtered": {
      "filter": {
        "geo_bounding_box": {
          "location": { 
            "top_left": {
              "lat":  40.8,
              "lon": -74.0
            },
            "bottom_right": {
              "lat":  40.7,
              "lon": -73.0
            }
          }
        }
      }
    }
  }
}
2、geo_distance

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

1、找出所有与指定点距离在 1km 内的 location 字段。访问 Distance Units 查看所支持的距离表示单位

2、 中心点可以表示为字符串,数组或者(如示例中的)对象。详见 经纬度坐标格式

GET /attractions/restaurant/_search
{
  "query": {
    "filtered": {
      "filter": {
        "geo_distance": {
          "distance":      "1km",
          "distance_type": "plane", 
          "location": {
            "lat":  40.715,
            "lon": -73.988
          }
        }
      }
    }
  }
}

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

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

是一个环状的,它会排除掉落在内圈中的那部分文档。

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

GET /attractions/restaurant/_search
{
  "query": {
    "filtered": {
      "filter": {
        "geo_distance_range": {
          "gte":    "1km", 
          "lt":     "2km", 
          "location": {
            "lat":  40.715,
            "lon": -73.988
          }
        }
      }
    }
  }
}
4、geo_polygon 找出落在多边形中的点。 这个过滤器使用代价很大 。当你觉得自己需要使用它,最好先看看 geo-shapes

4、按距离排序

检索结果可以按与指定点的距离排序:

GET /attractions/restaurant/_search
{
  "query": {
    "filtered": {
      "filter": {
        "geo_bounding_box": {
          "type":       "indexed",
          "location": {
            "top_left": {
              "lat":  40.8,
              "lon": -74.0
            },
            "bottom_right": {
              "lat":  40.4,
              "lon": -73.0
            }
          }
        }
      }
    }
  },
  "sort": [
    {
      "_geo_distance": {
        "location": { 
          "lat":  40.715,
          "lon": -73.998
        },
        "order":         "asc",
        "unit":          "km", 
        "distance_type": "plane" 
      }
    }
  ]
}