一、背景
最近有个需要,须要获取某个地位左近的楼盘,比方:获取以后用户所在位置,方圆100km千米之内的楼盘信息。通过调研,发现能够应用 redis
、mongodb
、elasticsearch
等实现。通过思考之后决定应用es
来实现,此处简略记录下es
中geo
方面api的应用。
二、geo数据类型
在es
中存在2种地理位置数据类型,geo_point
和geo_shape
。es无奈自动识别这种数据类型,须要在创立mapping的时候,本人手动指定。
1、geo_point
geo_point
应用的是经纬度
的坐标点,能够计算落在某个矩形内的点、以某个点为半径(圆)的点、某个多边形内的点(弃用了)、排序、聚合等操作。
2、geo_shape
geo_shape
示意的是一个简单的图形,应用的是GeoJSON
的格局来示意简单的图形。比方:咱们要示意一个图书馆的坐标地位,如果图书馆占的地位比拟大,用一个点示意可能就不准了,此时就能够应用geo_shape
来示意了。
不过这种数据类型也有毛病:比方不能排序等等(因为是多边形的点)。
三、此处对geo_point类型实战
1、背景
1、图中的 ① ② ③ ④ 示意是须要退出到 es 中的建筑物
建筑物 | 坐标 | 间隔地点 | 相隔间隔 | 解释 |
---|---|---|---|---|
上海站 | 121.462311,31.256224 | 上海站 | ||
上海静安洲际酒店 | 121.460186,31.251281 | 上海站 | 586.24米 | 上海站和该酒店大略像个586.24米 |
交通公园 | 121.473939,31.253531 | 上海站 | 1146.45米 | |
万业近景大厦 | 121.448215,31.26229 | 上海站 | 1501.74米 |
2、图中的圆形、正方形、多边形示意前期须要应用 es 查问进去外面外面的地点。
3、图中的短小的箭头➡️示意边界。
2、插入地点数据
1、创立索引
PUT /geo_index{ "settings": { "number_of_shards": 2, "number_of_replicas": 2, "analysis": { "analyzer": { "default": { "type": "ik_max_word" } } } }, "mappings": { "properties": { "building_name": { "type": "keyword" }, "location": { // 此处手动指定数据类型 "type": "geo_point" } } }}
留神⚠️:
1、在索引中,咱们本人指定来location
字段的类型为geo_point
类型。
2、building_name
的字段类型为keyword
示意不分词,这个字段只是为了测试,没有什么用。
3、不必指定索引的type,在es7中只有一个type。
2、插入地理位置数据
POST _bulk{"create":{"_index":"geo_index","_id":1}}{"building_name":"上海站","location":{"lat":31.256224,"lon":121.462311}}{"create":{"_index":"geo_index","_id":2}}{"building_name":"上海静安洲际酒店","location":"POINT (121.460186 31.251281)"}{"create":{"_index":"geo_index","_id":3}}{"building_name":"交通公园","location":"31.253531,121.473939"}{"create":{"_index":"geo_index","_id":4}}{"building_name":"万业近景大厦","location":[121.448215,31.26229]}
留神⚠️:
1、从下面可知:地理位置的插入的格局能够存在4种
形式。
1、 {"lat":"","lon":""}2、 "lat,lon"3、 [Well-Known Text](https://docs.opengeospatial.org/is/12-063r5/12-063r5.html) "POINT (lon lat)"4、 [lon,lat]5、 还有一种 geohash 的格局须要留神的是:应用 数组/Well-Known-Text 的格局的时候,经纬度是反过来的。
3、执行检索
1、geo_bounding_box 矩形过滤
从上图可知左上角和右下方的坐标别离为 (121.444075,31.265395)和(121.468417,31.253845)
执行查问,应该能够查问出 上海站
和万业近景大厦
1、es查问语句
GET /geo_index/_search{ "query": { "bool": { "must": { "match_all": {} }, "filter": { "geo_bounding_box": { "location": { "top_left": { "lat": 31.265395, "lon": 121.444075 }, "bottom_right": { "lat": 31.253845, "lon": 121.468417 } } } } } }}
2、查问后果
从图中能够看到,查问进去了 上海站
和万业近景大厦
,后果是正确的。
2、geo_distance 圆形查问
这个是间隔查问,是以某个点向四周扩算的间隔范畴。
在上一步的背景中,咱们晓得上海站
的坐标(121.462311,31.256224
),同时也晓得了上海站间隔各个周边的间隔有多远,此处咱们以上海站为核心,查问方圆600米
的建筑物,可知只有上海静安洲际酒店
和上海站
合乎。
1、es查问语句
GET /geo_index/_search{ "query": { "bool": { "must": { "match_all": {} }, "filter": { "geo_distance": { "distance": "600m", "distance_type": "arc", "_name":"optional_name", "location": { "lat": 31.256224, "lon": 121.462311 } } } } }}
留神⚠️:
1、distance_type
的值存在2个 arc
和plane
arc
:默认的形式,这种形式计算比拟准确,然而比较慢,是把地球当作一个球体计算。plane
:这种形式计算比拟快,然而可能不怎么准,越凑近赤道越准,是把地球当成平坦的进行计算。
2、distance
前面可用的单位有km
、m
、cm
、mm
、nmi
、mi
、yd
、ft
、in
2、查问后果
3、geo_distance 查问并排序,返回间隔相隔多少米
1、es 查问语句
GET /geo_index/_search{ "query": { "bool": { "must": { "match_all": {} }, "filter": { "geo_distance": { "distance": "600m", "distance_type": "arc", "_name": "optional_name", "location": { "lat": 31.256224, "lon": 121.462311 } } } } }, "sort": [ { "_geo_distance": { "location": { "lat": 31.256224, "lon": 121.462311 }, "order": "desc", "unit": "m", "distance_type": "arc" } } ]}
留神⚠️:
1、sort
执行排序。
2、查问后果
4、geo_distance聚合
需要:
1. 统计`上海站`500米之内的建筑物有多少。 2. 统计`上海站`500-1000米之内的建筑物有多少。 3. 统计`上海站`大于1000米的建筑物有多少。
1、es查问语句
GET /geo_index/_search{ "query": { "bool": { "must": { "match_all": {} } } }, "aggs": { "rings_around_amsterdam": { "geo_distance": { "field": "location", "origin": { "lat": 31.256224, "lon": 121.462311 }, "unit": "m", "distance_type": "arc", "ranges": [ {"to": 500,"key": "first"}, {"from": 500,"to": 1000,"key": "second" }, {"from": 1000,"key": "third"} ], "keyed": true } } }}
2、查问后果
从上图中能够看到:
1、间隔上海站在 0-500米之间的建筑物只有1个。
2、间隔上海站在 500-1000之间的建筑物有1个。
3、间隔上海站在 1000以上的有2个。
5、geo-polygon-多边形查问(过期)
在 es7.12 中曾经过期了,举荐应用 geo_shape来实现
6、一个综合案例
1、需要:
1、查问语句query
,查问出所有的数据,并过滤出以上海站为核心的3km内的所有的建筑物。
2、aggs
,用于统计出上海在 500米以内、500-1000米、1000米之外的建筑物数量。
3、sort
用于排序。
4、post_filter
用于将后果放大到上海站1000米以内。
2、查问后果
GET /geo_index/_search{ "query": { "bool": { "must": { "match_all": {} }, // 过滤出上海站四周3km范畴内的建筑物 "filter": { "geo_distance": { "distance": "3km", "distance_type": "arc", "_name":"optional_name", "location": { "lat": 31.256224, "lon": 121.462311 } } } } }, // 聚合上海站四周的建筑物的数量 "aggs": { "rings_around_amsterdam": { "geo_distance": { "field": "location", "origin": { "lat": 31.256224, "lon": 121.462311 }, "unit": "m", "distance_type": "arc", "ranges": [ {"to": 500,"key": "first"}, {"from": 500,"to": 1000,"key": "second" }, {"from": 1000,"key": "third"} ], "keyed": true } } },// 对查问到的后果排序,并将间隔放到响应数据的 sort 字段中。 "sort": [ { "_geo_distance": { "location": { "lat": 31.256224, "lon": 121.462311 }, "order": "desc", "unit": "m", "distance_type": "arc" } } ],// 将后果放大到上海站左近1km的范畴内。 "post_filter": { "geo_distance": { "distance": "1km", "location": { "lat": 31.256224, "lon": 121.462311 } } }}
四、参考文档
1、geo_point数据类型
2、间隔单位
3、排序
4、矩形查问
5、圆形查问,间隔查问
6、坐标拾取零碎