ElasticSearch对地理数据查询(二)
在ElasticSearch中,地理位置通過geo_point這個數據類型來支持。地理位置的數據需要提供經緯度信息,當經緯度不合法時,ES會拒絕新增文檔。這種類型的數據支持距離計算,范圍查詢等。在底層,索引使用Geohash實現。
1、創建索引
PUT創建一個索引cn_large_cities,mapping為city:
{"mappings": {"city": {"properties": {"city": {"type": "string"},"state": {"type": "string"},"location": {"type": "geo_point"}}}} }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
geo_point類型必須顯示指定,ES無法從數據中推斷。在ES中,位置數據可以通過對象,字符串,數組三種形式表示,分別如下:
# "lat,lon" "location":"40.715,-74.011""location": {"lat":40.715,"lon":-74.011 }# [lon ,lat] "location":[-74.011,40.715]- 1
POST下面4條測試數據:
{"city": "Beijing", "state": "BJ","location": {"lat": "39.91667", "lon": "116.41667"}}{"city": "Shanghai", "state": "SH","location": {"lat": "34.50000", "lon": "121.43333"}}{"city": "Xiamen", "state": "FJ","location": {"lat": "24.46667", "lon": "118.10000"}}{"city": "Fuzhou", "state": "FJ","location": {"lat": "26.08333", "lon": "119.30000"}}{"city": "Guangzhou", "state": "GD","location": {"lat": "23.16667", "lon": "113.23333"}}- 1
查看全部文檔:
curl -X GET "http://localhost:9200/cn_large_cities/city/_search?pretty=true"- 1
- 1
返回全部的5條數據,score均為1:
2、位置過濾
ES中有4中位置相關的過濾器,用于過濾位置信息:
- geo_distance: 查找距離某個中心點距離在一定范圍內的位置
- geo_bounding_box: 查找某個長方形區域內的位置
- geo_distance_range: 查找距離某個中心的距離在min和max之間的位置
- geo_polygon: 查找位于多邊形內的地點。
geo_distance
該類型過濾器查找的范圍如下圖:
下面是一個查詢例子:
{"query":{"filtered":{"filter":{"geo_distance":"1km","location":{"lat":40.715,"lon": -73.988 }}}} }- 1
以下查詢,查找距廈門500公里以內的城市:
{"query":{"filtered":{"filter":{"geo_distance" : {"distance" : "500km","location" : { "lat" : 24.46667, "lon" : 118.10000 } }}}} }- 16
geo_distance_range
{"query":{"filtered":{"filter":{"geo_distance_range":{"gte": "1km","lt": "2km","location":{ "lat":40.715, "lon": -73.988 } }}} }- 1
- 6
geo_bounding_box
{"query":{"filtered":{"filter":{"geo_bounding_box":{"location":{ "top_left":{ "lat": 40.8, "lon":-74.0 }, "bottom_right":{ "lat":40.715, "lon": -73.0 } } }}} }- 20
3、按距離排序
接著我們按照距離廈門遠近查找:
{"sort" : [{"_geo_distance" : {"location" : {"lat" : 24.46667,"lon" : 118.10000}, "order" : "asc","unit" : "km"}}],"query": {"filtered" : {"query" : {"match_all" : {}}}} }結果如下,依次是廈門、福州、廣州…。符合我們的常識:
{"took": 8,"timed_out": false,"_shards": {"total": 5,"successful": 5,"failed": 0},"hits": {"total": 5,"max_score": null,"hits": [{"_index": "us_large_cities","_type": "city","_id": "AVaiSGXXjL0tfmRppc_p","_score": null,"_source": {"city": "Xiamen","state": "FJ","location": {"lat": "24.46667","lon": "118.10000" }},"sort": [0]},{"_index": "us_large_cities","_type": "city","_id": "AVaiSSuNjL0tfmRppc_r","_score": null,"_source": {"city": "Fuzhou","state": "FJ","location": {"lat": "26.08333","lon": "119.30000" }},"sort": [216.61105485607183]},{"_index": "us_large_cities","_type": "city","_id": "AVaiSd02jL0tfmRppc_s","_score": null,"_source": {"city": "Guangzhou","state": "GD","location": {"lat": "23.16667","lon": "113.23333" }},"sort": [515.9964950041397]},{"_index": "us_large_cities","_type": "city","_id": "AVaiR7_5jL0tfmRppc_o","_score": null,"_source": {"city": "Shanghai","state": "SH","location": {"lat": "34.50000","lon": "121.43333" }},"sort": [1161.512141925948]},{"_index": "us_large_cities","_type": "city","_id": "AVaiRwLUjL0tfmRppc_n","_score": null,"_source": {"city": "Beijing","state": "BJ","location": {"lat": "39.91667","lon": "116.41667" }},"sort": [1725.4543712286697]}]} }- 1
結果返回的sort字段是指公里數。加上限制條件,只返回最近的一個城市:
{"from":0,"size":1,"sort" : [{"_geo_distance" : {"location" : {"lat" : 24.46667,"lon" : 118.10000}, "order" : "asc","unit" : "km"}}],"query": {"filtered" : {"query" : {"match_all" : {}}}} }4、地理位置聚合
ES提供了3種位置聚合:
- geo_distance: 根據到特定中心點的距離聚合
- geohash_grid: 根據Geohash的單元格(cell)聚合
- geo_bounds: 根據區域聚合
4.1 geo_distance聚合
下面這個查詢根據距離廈門的距離來聚合,返回0-500,500-8000km的聚合:
{"query":{"filtered":{"filter":{"geo_distance" : {"distance" : "10000km","location" : { "lat" : 24.46667, "lon" : 118.10000 } }}}},"aggs":{"per_ring":{"geo_distance":{"field": "location","unit": "km","origin":{"lat" : 24.46667,"lon" : 118.10000 },"ranges":[{"from": 0 , "to":500},{"from": 500 , "to":8000}]}}}}- 1
返回的聚合結果如下;
"aggregations": {"per_ring": {"buckets": [{"key": "*-500.0","from": 0,"from_as_string": "0.0","to": 500,"to_as_string": "500.0","doc_count": 2},{"key": "500.0-8000.0","from": 500,"from_as_string": "500.0","to": 8000,"to_as_string": "8000.0","doc_count": 3}]}}- 12
可以看到,距離廈門0-500km的城市有2個,500-8000km的有3個。
4.2 geohash_grid聚合
該聚合方式根據geo_point數據對應的geohash值所在的cell進行聚合,cell的劃分精度通過precision屬性來控制,精度是指cell劃分的次數。
{"query":{"filtered":{"filter":{"geo_distance" : {"distance" : "10000km","location" : { "lat" : 24.46667, "lon" : 118.10000 } }}}},"aggs":{"grid_agg":{"geohash_grid":{"field": "location","precision": 2}}}}- 1
聚合結果如下:
"aggregations": {"grid_agg": {"buckets": [{"key": "ws","doc_count": 3},{"key": "wx","doc_count": 1},{"key": "ww","doc_count": 1}]}}- 1
可以看到,有3個城市的的geohash值為ws。將精度提高到5,聚合結果如下:
"aggregations": {"grid_agg": {"buckets": [{"key": "wx4g1","doc_count": 1},{"key": "wwnk7","doc_count": 1},{"key": "wssu6","doc_count": 1},{"key": "ws7gp","doc_count": 1},{"key": "ws0eb","doc_count": 1}]}}- 1
- 16
4.3 geo_bounds聚合
這個聚合操作計算能夠覆蓋所有查詢結果中geo_point的最小區域,返回的是覆蓋所有位置的最小矩形:
{"query":{"filtered":{"filter":{"geo_distance" : {"distance" : "10000km","location" : { "lat" : 24.46667, "lon" : 118.10000 } }}}},"aggs":{"map-zoom":{"geo_bounds":{"field": "location"}}}}- 1
- 15
結果如下:
"aggregations": {"map-zoom": {"bounds": {"top_left": {"lat": 39.91666993126273,"lon": 113.2333298586309},"bottom_right": {"lat": 23.16666992381215,"lon": 121.43332997336984}}}}- 1
- 6
也就是說,這兩個點構成的矩形能夠包含所有到廈門距離10000km的區域。我們把距離調整為500km,此時覆蓋這些城市的矩形如下:
"aggregations": {"map-zoom": {"bounds": {"top_left": {"lat": 26.083329990506172,"lon": 118.0999999679625},"bottom_right": {"lat": 24.46666999720037,"lon": 119.29999999701977}}}}- 1
- 2
5、參考資料
圖解 MongoDB 地理位置索引的實現原理:http://blog.nosqlfan.com/html/1811.html
Geopoint數據類型:https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-point.html
總結
以上是生活随笔為你收集整理的ElasticSearch对地理数据查询(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Elasticsearch对地理数据查询
- 下一篇: Bootstrap list-gro