更多内容请参考 : https://www.felayman.com
翻译版本:https://es.xiaoleilu.com/310_Geopoints/00_Intro.html
官方原文:https://www.elastic.co/guide/en/elasticsearch/guide/current/geoloc.html
本文只是针对这些内容通过具体的例子用java来实现其具体细节,如果只想看java实现部分,请直接往下面代码实现部分看
地理坐标点(geo-point) 是指地球表面可以用经纬度描述的一个点。地理坐标点可以用来计算两个坐标位置间的距离,或者判断一个点是否在一个区域中。地理坐标点不能被动态映射(dynamic mapping)自动检测,而是需要显式声明对应字段类型为 geo_point 。
PUT /attractions
{
"mappings": {
"restaurant": {
"properties": {
"name": {
"type": "string"
},
"location": {
"type": "geo_point"
}
}
}
}
}
如上例,location 被声明为 geo_point 后,我们就可以索引包含了经纬度信息的文档了。经纬度信息的形式可以是字符串,数组或者对象。
PUT /attractions/restaurant/1
{
"name": "Chipotle Mexican Grill",
"location": "40.715, -74.011" <1>
}
PUT /attractions/restaurant/2
{
"name": "Pala Pizza",
"location": { <2>
"lat": 40.722,
"lon": -73.989
}
}
PUT /attractions/restaurant/3
{
"name": "Mini Munchies Pizza",
"location": [ -73.983, 40.719 ] <3>
}
- <1> 以半角逗号分割的字符串形式 “lat,lon”;
- <2> 明确以 lat 和 lon 作为属性的对象;
- <3> 数组形式表示 [lon,lat]。
注意 :
可能所有人都至少踩过一次这个坑:地理坐标点用字符串形式表示时是纬度在前,经度在后(”latitude,longitude”),而数组形式表示时刚好相反,是经度在前,纬度在后([longitude,latitude])。其实,在 Elasticesearch 内部,不管字符串形式还是数组形式,都是纬度在前,经度在后。不过早期为了适配 GeoJSON 的格式规范,调整了数组形式的表示方式。因此,在使用地理位置(geolocation)的路上就出现了这么一个“捕熊器”,专坑那些不了解这个陷阱的使用者。
通过地理坐标点过滤
有四种地理坐标点相关的过滤方式可以用来选中或者排除文档:
- geo_bounding_box::
找出落在指定矩形框中的坐标点 - geo_distance::
找出与指定位置在给定距离内的点 - geo_distance_range::
找出与指定点距离在给定最小距离和最大距离之间的点 - geo_polygon::
找出落在多边形中的点。这个过滤器使用代价很大。当你觉得自己需要使用它,最好先看看 geo-shapes
所有这些过滤器的工作方式都相似: 把 索引中所有文档(而不仅仅是查询中匹配到的部分文档,见 fielddata-intro)的经纬度信息都载入内存,然后每个过滤器执行一个轻量级的计算去判断当前点是否落在指定区域。
提示
地理坐标过滤器使用代价昂贵 —— 所以最好在文档集合尽可能少的场景使用。 你可以先使用那些简单快捷的过滤器,比如 term 或者 range,来过滤掉尽可能多的文档,最后才交给地理坐标过滤器处理。
布尔型过滤器(bool filter)会自动帮你做这件事。 它会优先让那些基于“bitset”的简单过滤器(见 filter-caching)来过滤掉尽可能多的文档,然后依次才是地理坐标过滤器或者脚本类的过滤器。
地理坐标盒模型过滤器
这是目前为止最有效的 地理坐标过滤器了,因为它计算起来非常简单。 你指定一个矩形的 顶部(top), 底部(bottom), 左边界(left), 和 右边界(right), 然后它只需判断坐标的经度是否在左右边界之间,纬度是否在上下边界之间。(译注:原文似乎写反了)
GET /attractions/restaurant/_search
{
"query": {