Elasticsearch-97-基于地理位置的搜索和聚合

案例背景

一个酒店o2o的app,根据用户指定的位置,找到周围的符合条件的酒店.

geo_point地理位置数据类型

geo_point,就是一个地理位置坐标点,记录了经度和纬度,通过经纬度,就可以定位地球上的位置

创建索引
1
2
3
4
5
6
7
8
9
10
11
12
PUT /my_index
{
"mappings": {
"my_type": {
"properties": {
"location":{
"type": "geo_point"
}
}
}
}
}

field的类型设置为geo_point

写入geo_point的三种方法

第一种

1
2
3
4
5
6
7
8
PUT /my_index/my_type/1
{
"text": "Geo-point as an object",
"location": {
"lat": 41.12,
"lon": -71.34
}
}

  • latitude(lat): 纬度
  • longitude(lon): 经度

第二种

1
2
3
4
5
PUT my_index/my_type/2
{
"text": "Geo-point as a string",
"location": "41.12,-71.34"
}

第三种

1
2
3
4
5
PUT my_index/my_type/4
{
"text": "Geo-point as an array",
"location": [ -71.34, 41.12 ]
}

后面两种不推荐使用

搜索

geo_bounding_box查询

geo_bounding_box查询: 查询某个矩形的地理位置范围内的坐标点

看一下搜索请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
GET /my_index/my_type/_search
{
"query": {
"geo_bounding_box":{
"location":{
"top_left":{
"lat":42,
"lon":-72
},
"bottom_right":{
"lat":40,
"lon":-74
}
}
}
}
}

返回值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
{
"took": 17,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 1,
"hits": [
{
"_index": "my_index",
"_type": "my_type",
"_id": "2",
"_score": 1,
"_source": {
"text": "Geo-point as a string",
"location": "41.12,-71.34"
}
},
{
"_index": "my_index",
"_type": "my_type",
"_id": "4",
"_score": 1,
"_source": {
"text": "Geo-point as an array",
"location": [
-71.34,
41.12
]
}
},
{
"_index": "my_index",
"_type": "my_type",
"_id": "1",
"_score": 1,
"_source": {
"text": "Geo-point as an object",
"location": {
"lat": 41.12,
"lon": -71.34
}
}
}
]
}
}

搜索的时候指定了一个top_left,和一个bottom_right
image
如上图,以top_left,和一个bottom_right 成一个矩形,然后这个矩形之内的坐标对应的数据都可以被搜索出来

geo_polygon查询

geo_polygon查询:以多个坐标组成一个多边形来查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
GET /my_index/my_type/_search
{
"query": {
"bool": {
"must": [
{
"match_all": {}
}
],
"filter": {
"geo_polygon": {
"location": {
"points": [
{
"lat": 40.73,
"lon": -74.1
},
{
"lat" : 40.01,
"lon" : -71.12
},
{
"lat" : 50.56,
"lon" : -90.58
}
]
}
}
}
}
}
}

跟上面的矩形搜索是类似的,只不过这里是以多个坐标组成的多边形去搜索

距离查询

比如说要查询距离自己200km以内的酒店, 我们自己的坐标是知道的 app都可以获取的到

搜索

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
GET /my_index/my_type/_search
{
"query": {
"bool": {
"must": [
{
"match_all": {}
}
],
"filter": {
"geo_distance": {
"distance": "200km",
"location": {
"lat": 40.73,
"lon": -74.1
}
}
}
}
}
}

location里面的经纬度就是我们自己的坐标,然后distance,设置查询距离

聚合分析

需求:统计距离我当前位置的几个范围内的酒店数量, 比如我0-100m有几个酒店,100-300m有几个,300以上的有几个

请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
GET /my_index/my_type/_search
{
"size": 0,
"aggs": {
"agg_by_distance_range": {
"geo_distance": {
"field": "location",
"origin": {
"lat": 52.376,
"lon": 4.894
},
"unit": "mi",
"ranges": [
{
"to": 100
},
{
"from": 100,
"to": 300
},
{
"from": 300
}
]
}
}
}
}

返回值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
{
"took": 13,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 0,
"hits": []
},
"aggregations": {
"agg_by_distance_range": {
"buckets": [
{
"key": "*-100.0",
"from": 0,
"to": 100,
"doc_count": 0
},
{
"key": "100.0-300.0",
"from": 100,
"to": 300,
"doc_count": 0
},
{
"key": "300.0-*",
"from": 300,
"doc_count": 3
}
]
}
}
}

请求中的几个参数

  • unit:单位,可以是mi 也可以是km
  • origin: 自己当前的坐标
  • ranges: 要统计的几个区间