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 使用地理位置查询的主要内容,如果未能解决你的问题,请参考以下文章
Java High Level REST Client 使用地理位置查询
使用Java High Level REST Client操作elasticsearch
SpringBoot整合ElasticSearch之Java High Level REST Client
ElasticSearch 使用 High Level REST Client 实现搜索等功能实战
Elasticsearch Java High-Level REST Client 建立一堆 TCP 连接并且在索引数据后不关闭它们