# 基于地理位置对周围汽车 4S 店进行搜索

要进行地理位置的搜索需要添加两个依赖

<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
15
16
17

or

compile 'org.locationtech.spatial4j:spatial4j:0.6'
compile 'com.vividsolutions:jts:1.13'
1
2

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

新增一个 mapping

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

插入数据

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

需求:搜索两个坐标点组成的一个区域

来回顾下 restfull 语法

GET /car_shop/shops/_search
{
  "query": {
    "geo_bounding_box": {
      "pin.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

再对比下 java 语法

@Test
public void geoBoundingBoxQuery() {
    GeoBoundingBoxQueryBuilder geoBoundingBoxQueryBuilder = QueryBuilders.geoBoundingBoxQuery("pin.location")
            .setCorners(40.73, -74.1, 40.01, -71.12);
    SearchResponse searchResponse = client.prepareSearch("car_shop")
            .setTypes("shops")
            .setQuery(geoBoundingBoxQueryBuilder)
            .get();
    System.out.println(searchResponse);
}
1
2
3
4
5
6
7
8
9
10

响应数据

{"took":1,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":1,"max_score":1.0,"hits":[{"_index":"car_shop","_type":"shops","_id":"1","_score":1.0,"_source":{
    "name": "上海至全宝马4S店",
    "pin" : {
        "location" : {
            "lat" : 40.12,
            "lon" : -71.34
        }
    }
}
}]}}
1
2
3
4
5
6
7
8
9
10

需求:指定一个区域,由三个坐标点,组成,比如上海大厦,东方明珠塔,上海火车站

@Test
public void geoPolygonQuery() {
    ArrayList<GeoPoint> geoPoints = new ArrayList<>();
    geoPoints.add(new GeoPoint(40.73, -74.1));
    geoPoints.add(new GeoPoint(40.01, -71.12));
    geoPoints.add(new GeoPoint(50.56, -90.58));
    GeoPolygonQueryBuilder query = QueryBuilders.geoPolygonQuery("pin.location", geoPoints);
    SearchResponse searchResponse = client.prepareSearch("car_shop")
            .setTypes("shops")
            .setQuery(query)
            .get();
    System.out.println(searchResponse);
}
1
2
3
4
5
6
7
8
9
10
11
12
13

需求:搜索距离当前位置在 200 公里内的 4s 店

@Test
public void geoDistanceQuery() {
    GeoDistanceQueryBuilder query = QueryBuilders.geoDistanceQuery("pin.location")
            .point(40, -70)
            .distance(200, DistanceUnit.KILOMETERS);
    SearchResponse searchResponse = client.prepareSearch("car_shop")
            .setTypes("shops")
            .setQuery(query)
            .get();
    System.out.println(searchResponse);
}
1
2
3
4
5
6
7
8
9
10
11