Elasticsearch-100-Java API基于地理位置的搜索

案例背景

比如我们有很多的4s店,然后呢给了用户一个app,在某个地方的时候,可以根据当前的地理位置搜索一下,自己附近的4s店

数据准备

添加一个地理位置的field,手动设置mapping映射,然后添加一条测试数据

1
2
3
4
5
6
7
8
9
10
11
12
POST /car_shop/_mapping/shops
{
"properties": {
"pin": {
"properties": {
"location": {
"type": "geo_point"
}
}
}
}
}

1
2
3
4
5
6
7
8
9
10
PUT /car_shop/shops/1
{
"name": "上海至全宝马4S店",
"pin" : {
"location" : {
"lat" : 40.12,
"lon" : -71.34
}
}
}

依赖引入

maven中引入基于地理位置查询的依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<dependency>
<groupId>org.locationtech.spatial4j</groupId>
<artifactId>spatial4j</artifactId>
<version>0.6</version>
</dependency>

<dependency>
<groupId>com.vividsolutions</groupId>
<artifactId>jts</artifactId>
<version>1.13</version>
<exclusions>
<exclusion>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
</exclusion>
</exclusions>
</dependency>

矩形搜索

搜索两个坐标点,组成的一个矩形区域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
public void getBoundingBoxQuery(){

QueryBuilder queryBuilder = QueryBuilders.geoBoundingBoxQuery("pin.location").setCorners(40.73, -74.1, 40.01, -71.12);

SearchResponse response = client.prepareSearch("car_shop")
.setTypes("shops")
.setQuery(queryBuilder)
.get();

for (SearchHit hit : response.getHits().getHits()) {
log.info("hit:{}", hit.getSourceAsString());
}
}

console:

1
2
3
4
5
6
7
8
9
2019-01-23 16:39:39.306 [main] INFO  com.demo.elasticsearch.CarShopTests - hit:{
"name": "上海至全宝马4S店",
"pin" : {
"location" : {
"lat" : 40.12,
"lon" : -71.34
}
}
}

多个坐标点区域查询

多个坐标点组成一个多边形区域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Test
public void geoPolygonQuery(){

// 多个坐标点
List<GeoPoint> points = new ArrayList<>(3);
points.add(new GeoPoint(40.73, -74.1));
points.add(new GeoPoint(40.01, -71.12));
points.add(new GeoPoint(50.56, -90.58));

// 查询条件
QueryBuilder queryBuilder = QueryBuilders.geoPolygonQuery("pin.location", points);

SearchResponse response = client.prepareSearch("car_shop")
.setTypes("shops")
.setQuery(queryBuilder)
.get();

for (SearchHit hit : response.getHits().getHits()) {
log.info("hit:{}", hit.getSourceAsString());
}
}

console:

1
2
3
4
5
6
7
8
9
2019-01-23 16:49:05.885 [main] INFO  com.demo.elasticsearch.CarShopTests - hit:{
"name": "上海至全宝马4S店",
"pin" : {
"location" : {
"lat" : 40.12,
"lon" : -71.34
}
}
}

根据当前坐标的范围查询

以某一坐标为基准,查询距离该坐标2km以内的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Test
public void geoDistanceQuery(){

// 查询条件
QueryBuilder queryBuilder = QueryBuilders.geoDistanceQuery("pin.location")
.point(40, -70)
.distance(200, DistanceUnit.KILOMETERS);

SearchResponse response = client.prepareSearch("car_shop")
.setTypes("shops")
.setQuery(queryBuilder)
.get();

for (SearchHit hit : response.getHits().getHits()) {
log.info("hit:{}", hit.getSourceAsString());
}
}

console:

1
2
3
4
5
6
7
8
9
2019-01-23 16:55:23.224 [main] INFO  com.demo.elasticsearch.CarShopTests - hit:{
"name": "上海至全宝马4S店",
"pin" : {
"location" : {
"lat" : 40.12,
"lon" : -71.34
}
}
}

最后

以上的java Api的代码,都放在了github,传送门