直接上代码,包括多种geo相关查询===>>>矩形/多边形/距离/距离排序/距离分段聚合/geo_shape内含-相交-相离
@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class VehicleEntpApplicationTests {
static {
System.setProperty("es.set.netty.runtime.available.processors", "false");
}
@Autowired
ElasticsearchTemplate elasticsearchTemplate;
//"************************矩形************************"
/*
GET /entp/entp_search
{
"post_filter": {
"geo_bounding_box": {
"geo": {
"top_left": {
"lat": 31.73,
"lon": 104.1
},
"bottom_right": {
"lat": 10.01,
"lon": 141.12
}
}
}
}
}
*/
@Test
public void boundingBoxQuery() throws Exception {
GeoBoundingBoxQueryBuilder filterBuilder = QueryBuilders.geoBoundingBoxQuery("geo")
.setCorners(new GeoPoint(31.73, 104.1), new GeoPoint(10.01, 141.12));
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withIndices("entp")
.withTypes("entp")
.withFilter(filterBuilder)
.build();
System.out.println(filterBuilder.toString());
List<EntpResourceVO> vos = elasticsearchTemplate.queryForList(searchQuery, EntpResourceVO.class);
}
//"************************多边形************************"
/*{
"post_filter": {
"geo_polygon": {
"geo": {
"points": [{
"lat": 22,
"lon": 88
}, {
"lat": 11,
"lon": 111
}, {
"lat": 33,
"lon": 133
}]
}
}
}
}*/
@Test
public void polygonQuery() throws Exception {
List<GeoPoint> geoPoints = new ArrayList<>();
geoPoints.add(new GeoPoint(11, 111));
geoPoints.add(new GeoPoint(22, 88));
geoPoints.add(new GeoPoint(33, 133));
GeoPolygonQueryBuilder filterBuilder = QueryBuilders.geoPolygonQuery("geo", geoPoints);
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withIndices("entp")
.withTypes("entp")
.withFilter(filterBuilder)
.build();
System.out.println(filterBuilder.toString());
List<EntpResourceVO> vos = elasticsearchTemplate.queryForList(searchQuery, EntpResourceVO.class);
}
//"************************距离排序************************"
/*GET /entp/_search
{
"from": 0,
"size": 10,
"query": {
"match_phrase_prefix": {
"entpAddr.chinese": {
"query": "云南",
"boost": 1.0
}
}
},
"sort": [{
"_geo_distance": {
"geo": [{
"lat": 25.0,
"lon": 102.0
}],
"unit": "km",
"distance_type": "plane",
"order": "asc"
}
}, {
"_score": {
"order": "desc"
}
}]
}*/
@Test
public void geoDistanceSortQuery() throws Exception {
QueryBuilder query = QueryBuilders.matchPhrasePrefixQuery("entpAddr.chinese", "云南");
GeoDistanceSortBuilder sortBuilder = SortBuilders
.geoDistanceSort("geo", 25, 110)
.unit(DistanceUnit.KILOMETERS)
.order(SortOrder.ASC)
.geoDistance(GeoDistance.PLANE);
//elasticsearchTemplate的API不便获得到距离,需要用原生的transportClient
SearchRequestBuilder requestBuilder = (elasticsearchTemplate.getClient())
.prepareSearch("entp")
.setTypes("entp")
.setQuery(query)
.setFrom(0)
.setSize(10)
.addSort(sortBuilder).addSort("_score", SortOrder.DESC);//先相关度再距离二级排序
System.out.println(requestBuilder.toString());
Arrays.stream(requestBuilder.get().getHits().getHits()).forEach(searchHit -> {
BigDecimal bigDecimal = new BigDecimal((double) searchHit.getSortValues()[0]);
double distance = bigDecimal.setScale(1, BigDecimal.ROUND_HALF_DOWN).doubleValue();
});
}
//"************************距离查询************************"
/*GET / entp / _search
{
"post_filter": {
"geo_distance": {
"distance": "1000km",
"geo": {
"lat": 30,
"lon": 110
}
}
}
}*/
@Test
public void geoDistanceQuery() throws Exception {
GeoDistanceQueryBuilder filterBuilder = QueryBuilders.geoDistanceQuery("geo")
.distance(1000, DistanceUnit.KILOMETERS)
.point(30, 110);
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withIndices("entp")
.withTypes("entp")
.withFilter(filterBuilder)
.build();
System.out.println(filterBuilder.toString());
List<EntpResourceVO> vos = elasticsearchTemplate.queryForList(searchQuery, EntpResourceVO.class);
}
//"************************分段聚合************************"
/*
GET /entp/_search
{
"size": 0,
"aggs": {
"groupCount": {
"geo_distance": {
"field": "geo",
"origin": { //源坐标
"lat": 30,
"lon": 110
},
"ranges": [ //分段
{"to" : 300},
{
"from": 300,
"to": 600
},
{"from": 600}
],
"unit": "km",
"distance_type": "arc" //平面or球面
}
}
}
}*/
@Test
public void geoAggExample() throws Exception {
GeoDistanceAggregationBuilder agg = AggregationBuilders.geoDistance("groupCount", new GeoPoint(30, 110))
.field("geo")
.addUnboundedTo("300KM以下", 300)
.addRange("300-600KM", 300, 600)
.addUnboundedFrom("600KM以上", 600)
.distanceType(GeoDistance.ARC)
.unit(DistanceUnit.KILOMETERS);
SearchRequestBuilder requestBuilder = (elasticsearchTemplate.getClient())
.prepareSearch("entp")
.setTypes("entp")
.addAggregation(agg)
.setSize(0);
System.out.println(requestBuilder.toString());
InternalGeoDistance internalGeoDistance = requestBuilder.get().getAggregations().get("groupCount");
List buckets = internalGeoDistance.getBuckets();
buckets.forEach(o -> {
long docCount = ((InternalRange.Bucket) o).getDocCount();
});
}
//"************************geo_shape内含-相交-相离************************"
/**/
@Test
public void geoShapeQuery() throws Exception {
// 1.查询针对的不是普通的字段,而是一种特殊的图形数据,是多个geo_point组成的,
// 2. 用该API可以计算点线面形状的输入与ES内的geo_shape类型的内含-相交-相离关系。
// ShapeRelation.WITHIN内含 ShapeRelation.INTERSECTS相交 ShapeRelation.DISJOINT相离
// 3.需要加入两个依赖
/*.
<dependency>
<groupId>org.locationtech.jts</groupId>
<artifactId>jts-core</artifactId>
<version>1.16.1</version>
</dependency>
<dependency>
<groupId>org.locationtech.spatial4j</groupId>
<artifactId>spatial4j</artifactId>
<version>0.7</version>
</dependency>
*/
//4.数据准备
/*PUT /example
{
"mappings": {
"example": {
"properties": {
"myGeoShape": {
"type": "geo_shape"
}
}
}
}
}
POST /example/example
{
"myGeoShape" : {
"type" : "polygon",
"coordinates" : [
[ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ]
]
}
}*/
//5.需求举例
//点面,如电子围栏,机车(点输入)闯入电子围栏触发报警
//ShapeBuilder pointBuilder = new PointBuilder(33, 111);
//线面,新修公路(线输入)线路计划合理性计算,尽量与较多的村庄相交或内含
//ShapeBuilder pointBuilder = new LineStringBuilder(new CoordinatesBuilder().coordinate(11,22).coordinate(33,44));// 点面位置关系
//面面,如汶川多个村庄(在ES中表现为多个坐标组成的多边形),地震震中(面输入)(x,y) r=100Km,计算波及的村庄
ShapeBuilder circleBuilder = new CircleBuilder().center(100.0, 0.0).radius(100, DistanceUnit.KILOMETERS);
GeoShapeQueryBuilder filterBuilder = QueryBuilders.geoShapeQuery("myGeoShape", circleBuilder).relation(ShapeRelation.WITHIN);
SearchRequestBuilder requestBuilder = (elasticsearchTemplate.getClient())
.prepareSearch("example")
.setTypes("example")
.setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
.setQuery(filterBuilder)
.setFrom(0)
.setSize(10);
Arrays.stream(requestBuilder.get().getHits().getHits()).forEach(searchHit -> {
Map<String, Object> source = searchHit.getSourceAsMap();
System.out.println(source);
});
}
}