一、背景
最近有个需要,须要获取某个地位左近的楼盘,比方:获取以后用户所在位置,方圆 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、坐标拾取零碎