springboot 使用 Spring Data Elasticsearch 地理查询、经纬度查询(GeoDistanceQueryBuilder) 作者:马育民 • 2021-12-05 21:44 • 阅读:10752 # 说明 给定圆心点坐标、半径,查询落在该圆的点 [![](https://www.malaoshi.top/upload/pic/elasticsearch/QQ20210911195050.png)](https://www.malaoshi.top/upload/pic/elasticsearch/QQ20210911195050.png) # 实体类 ``` package es.entity; import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.elasticsearch.annotations.GeoPointField; import org.elasticsearch.common.geo.GeoPoint; import org.springframework.data.annotation.Id; import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.elasticsearch.annotations.Field; import org.springframework.data.elasticsearch.annotations.FieldType; import org.springframework.data.elasticsearch.annotations.GeoPointField; @Document(indexName = "meituan_v1", shards = 1, replicas = 0) public class Meituan { @Id private String id; @Field(type = FieldType.Keyword) private String name; @GeoPointField private GeoPoint location; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public GeoPoint getLocation() { return location; } public void setLocation(GeoPoint location) { this.location = location; } @Override public String toString() { return "Meituan{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", location=" + location + '}'; } } ``` # 地理范围查询 ### service类 ``` package day1.service; import day1.entity.Meituan; import org.elasticsearch.common.geo.GeoDistance; import org.elasticsearch.common.unit.DistanceUnit; import org.elasticsearch.index.query.GeoDistanceQueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.sort.GeoDistanceSortBuilder; import org.elasticsearch.search.sort.SortBuilders; import org.elasticsearch.search.sort.SortOrder; import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; import org.springframework.data.elasticsearch.core.SearchHits; import org.springframework.data.elasticsearch.core.query.NativeSearchQuery; import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.RequestMapping; import javax.annotation.Resource; @Service public class ESMeituanSrvImpl { @Resource private ElasticsearchRestTemplate template; /** * 地理范围查询 * * @param lat * @param lon * @param distance * @return */ public SearchHits geo(double lat, double lon, double distance){ //构建地理查询条件 GeoDistanceQueryBuilder builder = QueryBuilders .geoDistanceQuery("location")//查询字段 .point(lat, lon)//设置圆心点经纬度 .distance(distance, DistanceUnit.KILOMETERS)//设置半径距离和单位(千米) .geoDistance(GeoDistance.PLANE);// 使用平面算法 //构建排序 GeoDistanceSortBuilder sortBuilder = SortBuilders.geoDistanceSort("location",lat,lon)//设置参照点经纬度 .point(lat, lon) .unit(DistanceUnit.KILOMETERS) // 返回结果有sort,表示距离,这个单位就是距离单位 .order(SortOrder.ASC);//排序方式 //构造查询条件 NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder() .withFilter(builder) .withSort(sortBuilder) .build(); SearchHits shs = template.search(nativeSearchQuery, Meituan.class); return shs; } } ``` ### 测试类 在 `test` 目录下创建类,如下图: [![](/upload/0/0/1IX4VtKQJBOi.png)](/upload/0/0/1IX4VtKQJBOi.png) ``` package test; import day1.Main; import day1.entity.Meituan; import day1.service.ESMeituanSrvImpl; import org.elasticsearch.common.unit.DistanceUnit; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.elasticsearch.core.SearchHit; import org.springframework.data.elasticsearch.core.SearchHits; import org.springframework.test.context.junit4.SpringRunner; import javax.annotation.Resource; import java.util.List; @RunWith(SpringRunner.class) @SpringBootTest(classes = Main.class) public class TestESMeituanSrvImpl { @Resource private ESMeituanSrvImpl srv; @Test public void geo(){ SearchHits shs = srv.geo(77, 35, 200); for(SearchHit item:shs){ Meituan meituan=item.getContent(); List sortValues = item.getSortValues(); if(sortValues!=null && sortValues.size()>0){ double d=(Double)sortValues.get(0);//距离 System.out.print("距离:"+d+" "+ DistanceUnit.KILOMETERS+ "--"); } System.out.println(meituan); } } } ``` # 模糊条件 + 地理查询 通配符实现模糊查询店家名称,并在距离圆心点200km的范围的店家 ### service 在上面 service 类中加入下面代码: ``` public SearchHits geo2(String keyword, double lat, double lon, double distance){ //通配符模糊查询店家名称 WildcardQueryBuilder nameQuery = QueryBuilders.wildcardQuery("name", "*" + keyword + "*"); //构建地理查询条件 GeoDistanceQueryBuilder geoBuilder = QueryBuilders.geoDistanceQuery("location")//查询字段 .point(lat, lon)//设置圆心点经纬度 .distance(distance, DistanceUnit.KILOMETERS)//设置半径距离和单位(千米) .geoDistance(GeoDistance.PLANE);// 使用平面算法 //构建bool查询 BoolQueryBuilder boolQuery = QueryBuilders.boolQuery() .must(nameQuery) .must(geoBuilder); //构建排序 GeoDistanceSortBuilder sortBuilder = SortBuilders.geoDistanceSort("location",lat,lon)//设置参照点经纬度 .point(lat, lon) .unit(DistanceUnit.KILOMETERS) // 返回结果有sort,表示距离,这个单位就是距离单位 .order(SortOrder.ASC);//排序方式 //构造查询条件 NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder() .withFilter(boolQuery) .withSort(sortBuilder); SearchHits shs = template.search(nativeSearchQueryBuilder.build(), Meituan.class); return shs; } ``` ### 测试 在上面的测试类中增加下面代码: ``` @Test public void geo2(){ SearchHits shs = srv.geo2("面",77,35,120); // SearchHits shs = srv.geo2("面",77,35,200); for(SearchHit item:shs){ Meituan meituan=item.getContent(); List sortValues = item.getSortValues(); if(sortValues!=null && sortValues.size()>0){ double d=(Double)sortValues.get(0);//距离 System.out.print("距离:"+d+" "+DistanceUnit.KILOMETERS+"--"); } System.out.println(meituan); } } ``` 半径不同,查询出的店家也不同 原文出处:http://malaoshi.top/show_1IX2LxcdQU1p.html