参考:https://www.phpmianshi.com/?id=159
场景
现在基于地理位置的app层出不穷,支持地理位置的组件也有不少,Elasticsearch也不例外,并且ES可以把地理位置、全文搜索、结构化搜索和分析结合到一起,我们来看一下。
注意
本文章基于es7,用es6的话可能语法稍有不同,仅供参考
geo point数据类型
Elasticsearch基于地理位置的搜索,有一个专门的对象geo_point存储地理位置信息(经度,纬度),并且提供了一些基本的查询方法,如geo_bounding_box。
建立geo_point类型的mapping
PUT /my_geo { "mappings": { "properties": { "location": { "type": "geo_point" }, "name": { "type": "text" } } } }
创建了一个my_geo索引,添加了一个字段location,它的类型是geo_point
。
插入数据
#latitude:维度,longitude:经度 POST /my_geo/_doc { "name":"路人甲", "location":{ "lat": 39.90279998006104, "lon": 116.42703999493406 } } POST /my_geo/_doc { "name":"路人乙", "location":{ "lat": 39.93367367974064, "lon": 116.47845257733152 } }
范围查询(3种方式)
1.geo_distance查询,根据当前位置的距离进行搜索,非常实用
查询5km范围内都有谁,filter
使用geo_distance
查询,我们定义距离distance
为5km,再指定geo类型的字段location
POST /my_geo/_search { "query":{ "bool":{ "filter":{ "geo_distance":{ "distance":"5km", "location":{ "lat":39.93031708627304, "lon":116.4470385453491 } } } } } }
结果发现:路人甲,路人乙都出来啦,你再试着改变举例3km看看效果呢?
2.geo_bounding_box查询,查询某个矩形的地理位置范围内的坐标点
POST /my_geo/_search { "query": { "geo_bounding_box": { "location": { "top_left":{ "lon": 116, "lat": 39.99 }, "bottom_right":{ "lon": 117, "lat": 39.9 } } } } }
3.geo_polygon查询,查询三个点(三角形)范围内的坐标点
支持多边形,只是这个过滤器使用代价很大,尽量少用
POST /my_geo/_search { "query": { "geo_polygon": { "location": { "points": [ { "lon": 115, "lat": 23 }, { "lon": 113, "lat": 25 }, { "lon": 112, "lat": 21 } ] } } } }
按距离排序
按从近到远排序
POST /my_geo/_search { "query": { "bool": { "filter": { "geo_distance": { "distance": "5km", "location": { "lat": 39.93031708627304, "lon": 116.4470385453491 } } } } }, "sort": [ { "_geo_distance": { "location": { "lat": 39.93031708627304, "lon": 116.4470385453491 }, "order": "asc", "unit": "m", "distance_type": "plane" } } ] }
_geo_distance: 固定写法,下面为指定位置的经纬度
unit: 距离的单位,m/km都行
distance_type: 计算距离的方式,sloppy_arc (默认值), arc (精准的) and plane (最快速的)
返回值:
{ "took" : 1, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 2, "relation" : "eq" }, "max_score" : null, "hits" : [ { "_index" : "my_geo", "_type" : "_doc", "_id" : "kH1qEHQBfUQLnDXv35Mt", "_score" : null, "_source" : { "name" : "路人乙", "location" : { "lat" : 39.93367367974064, "lon" : 116.47845257733152 } }, "sort" : [ 2704.400492813901 ] }, { "_index" : "my_geo", "_type" : "_doc", "_id" : "j31qEHQBfUQLnDXvfJOK", "_score" : null, "_source" : { "name" : "路人甲", "location" : { "lat" : 39.90279998006104, "lon" : 116.42703999493406 } }, "sort" : [ 3503.0165324004943 ] } ] } }
sort里面的内容,就是与当前位置的地面距离,单位是m。
统计我当前位置几个范围内人的数量
unit表示距离单位,常用的是mi和km。
distance_type表示计算距离的方式,sloppy_arc (默认值), arc (精准的) and plane (最快速的)。
POST /my_geo/_search { "size": 0, "aggs": { "group_by_distance": { "geo_distance": { "field": "location", "origin": { "lon": 39.933673679, "lat": 116.47845257 }, "unit": "mi", "distance_type": "arc", "ranges": [ {"from": 0,"to": 1000}, {"from": 1000,"to": 2000}, {"from": 2000,"to": 5000} ] } } } }