Java High Level REST Client 使用地理位置查询
Posted huan1993
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java High Level REST Client 使用地理位置查询相关的知识,希望对你有一定的参考价值。
一、需求
在前一篇文章中,我们学会了geo_point
的使用,此处使用地理位置查询并使用java
语言实现一下。
功能:
1、实现查询、过滤。
2、实现聚合。
3、实现排序。
4、实现后置过滤。
二、对应的query语句
GET geo_index/_search
{
"from": 0,
"size": 10,
"timeout": "20s",
"query": {
"bool": {
"must": [
{
"match_all": {
"boost": 1.0
}
}
],
"filter": [
{
"geo_distance": {
"location": [
121.462311,
31.256224
],
"distance": 3000.0,
"distance_type": "arc",
"validation_method": "STRICT",
"ignore_unmapped": false,
"boost": 1.0,
"_name": "optional_name"
}
}
],
"adjust_pure_negative": true,
"boost": 1.0
}
},
"post_filter": {
"geo_distance": {
"location": [
121.462311,
31.256224
],
"distance": 1000.0,
"distance_type": "arc",
"validation_method": "STRICT",
"ignore_unmapped": false,
"boost": 1.0
}
},
"sort": [
{
"_geo_distance": {
"location": [
{
"lat": 31.256224,
"lon": 121.462311
}
],
"unit": "m",
"distance_type": "arc",
"order": "desc",
"validation_method": "STRICT",
"ignore_unmapped": false
}
}
],
"aggregations": {
"distanceAgg": {
"geo_distance": {
"field": "location",
"origin": {
"lat": 31.256224,
"lon": 121.462311
},
"ranges": [
{
"key": "first",
"from": 0.0,
"to": 500.0
},
{
"key": "second",
"from": 500.0,
"to": 1000.0
},
{
"key": "third",
"from": 1000.0
}
],
"keyed": true,
"unit": "m",
"distance_type": "ARC"
}
}
}
}
3、实现查询
1、方式一-使用api
import com.huan.study.esapi.AbstractEsApi;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.ShardSearchFailure;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.common.geo.GeoDistance;
import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.range.ParsedGeoDistance;
import org.elasticsearch.search.aggregations.bucket.range.Range;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.GeoDistanceSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.util.Arrays;
/**
* distance query 类型的 地理位置查询
*
* @author huan.fu 2021/4/22 - 下午4:00
*/
public class DistanceQueryApi extends AbstractEsApi {
@DisplayName("距离查询")
@Test
public void distanceQueryTest() throws IOException {
// 查询请求
SearchRequest searchRequest = new SearchRequest("geo_index");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
// 从索引那个开始返回数据
searchSourceBuilder.from(0);
// 查询多少条记录
searchSourceBuilder.size(10);
// 查询超时时间
searchSourceBuilder.timeout(TimeValue.timeValueSeconds(20));
// 构造查询和过滤数据
searchSourceBuilder.query(
// 构造布尔查询
QueryBuilders.boolQuery()
// 查询语句
.must(
QueryBuilders.matchAllQuery()
)
// 过滤语句
.filter(
// name 是过滤的字段
QueryBuilders.geoDistanceQuery("location")
// 在3km之内
.distance("3", DistanceUnit.KILOMETERS)
// 以那个点为中心
.point(31.256224D, 121.462311D)
.geoDistance(GeoDistance.ARC)
// 一个查询的名字,可选
.queryName("optional_name")
)
);
// 后置过滤
searchSourceBuilder.postFilter(
// name 是过滤的字段
QueryBuilders.geoDistanceQuery("location")
// 在3km之内
.distance("1", DistanceUnit.KILOMETERS)
// 以那个点为中心
.point(31.256224D, 121.462311D)
);
// 排序
searchSourceBuilder.sort(
// 不同的类型使用不同的SortBuilder
new GeoDistanceSortBuilder("location", 31.256224D, 121.462311D)
.order(SortOrder.DESC)
.unit(DistanceUnit.METERS)
.geoDistance(GeoDistance.ARC)
);
// 聚合操作
searchSourceBuilder.aggregation(
// name 聚合的名字 point 以那个点为中心开始聚合
AggregationBuilders.geoDistance("distanceAgg", new GeoPoint(31.256224D, 121.462311D))
// 字段
.field("location")
.unit(DistanceUnit.METERS)
.distanceType(GeoDistance.ARC)
.keyed(true)
// 范围
.addRange("first", 0.0D, 500D)
.addRange("second", 500D, 1000D)
.addRange("third", 1000D, Double.NEGATIVE_INFINITY)
);
searchRequest.source(searchSourceBuilder);
System.out.println("查询语句:" + searchSourceBuilder.toString());
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
System.out.println("查询结果:" + searchResponse);
RestStatus status = searchResponse.status();
System.out.println(status.getStatus());
System.out.println(searchResponse.isTerminatedEarly());
System.out.println(searchResponse.isTimedOut());
for (ShardSearchFailure shardFailure : searchResponse.getShardFailures()) {
System.out.println(shardFailure);
}
// 匹配到的结果
for (SearchHit hit : searchResponse.getHits().getHits()) {
// 数据
System.out.println(hit.getSourceAsMap());
// 排序距离
Object[] sortValues = hit.getSortValues();
System.out.println(Arrays.toString(sortValues));
System.out.println("=====");
}
// 获取聚合的结果
Aggregations aggregations = searchResponse.getAggregations();
aggregations.getAsMap().forEach((key, value) -> {
System.out.println("key:" + key);
for (Range.Bucket bucket : ((ParsedGeoDistance) value).getBuckets()) {
System.out.println("from:" + bucket.getFromAsString() + " to:" + bucket.getToAsString() + " value:" + bucket.getDocCount());
}
System.out.println("------------");
});
}
}
2、方式二-之内传入json查询串
Request request = new Request("GET", "geo_index/_search");
// 需要查询的 json 字符串
String queryJsonEntity = "{\\"from\\":0,\\"size\\":10,\\"timeout\\":\\"20s\\",\\"query\\":{\\"bool\\":{\\"must\\":[{\\"match_all\\":{\\"boost\\":1.0}}],\\"filter\\":[{\\"geo_distance\\":{\\"location\\":[121.462311,31.256224],\\"distance\\":3000.0,\\"distance_type\\":\\"arc\\",\\"validation_method\\":\\"STRICT\\",\\"ignore_unmapped\\":false,\\"boost\\":1.0,\\"_name\\":\\"optional_name\\"}}],\\"adjust_pure_negative\\":true,\\"boost\\":1.0}},\\"post_filter\\":{\\"geo_distance\\":{\\"location\\":[121.462311,31.256224],\\"distance\\":1000.0,\\"distance_type\\":\\"arc\\",\\"validation_method\\":\\"STRICT\\",\\"ignore_unmapped\\":false,\\"boost\\":1.0}},\\"sort\\":[{\\"_geo_distance\\":{\\"location\\":[{\\"lat\\":31.256224,\\"lon\\":121.462311}],\\"unit\\":\\"m\\",\\"distance_type\\":\\"arc\\",\\"order\\":\\"desc\\",\\"validation_method\\":\\"STRICT\\",\\"ignore_unmapped\\":false}}],\\"aggregations\\":{\\"distanceAgg\\":{\\"geo_distance\\":{\\"field\\":\\"location\\",\\"origin\\":{\\"lat\\":31.256224,\\"lon\\":121.462311},\\"ranges\\":[{\\"key\\":\\"first\\",\\"from\\":0.0,\\"to\\":500.0},{\\"key\\":\\"second\\",\\"from\\":500.0,\\"to\\":1000.0},{\\"key\\":\\"third\\",\\"from\\":1000.0}],\\"keyed\\":true,\\"unit\\":\\"m\\",\\"distance_type\\":\\"ARC\\"}}}}";
request.setJsonEntity(queryJsonEntity);
Response response = client.getLowLevelClient().performRequest(request);
String result = EntityUtils.toString(request.getEntity(), StandardCharsets.UTF_8);
System.out.println("响应结果: " + result);
3、输出查询语句
使用输出 SearchSourceBuilder
的结果即可。
4、输出响应结果
直接输出 SearchResponse
的结果即可。
至此就完成了上方的查询。
四、注意事项
- java high level rest client 的版本最好和我们的
es
的版本一致,如果不一致,那么最好要和主版本一致。 - jdk的版本最少要是
1.8
的版本。 - 不推荐使用
TransportClient
,这个已经过时了,在es8
中将会移除。 - 输出我们自己的查询语句,直接输出
SearchSourceBuilder
即可。 - 输出响应语句,直接输出
SearchResponse
即可。
五、完整代码路径
https://gitee.com/huan1993/spring-cloud-parent/blob/master/es/es-api/src/test/java/com/huan/study/esapi/dslapi/geoapi/DistanceQueryApi.java
六、参考文档
1、https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.12/java-rest-high-query-builders.html
2、https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.12/java-rest-high-search.html
以上是关于Java High Level REST Client 使用地理位置查询的主要内容,如果未能解决你的问题,请参考以下文章