一、需要
在前一篇文章中,咱们学会了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" } } }}
三、对应java代码
1、引入 jar 包
<dependencyManagement> <dependencies> <dependency> <groupId>org.junit</groupId> <artifactId>junit-bom</artifactId> <version>5.7.1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>7.12.0</version> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.14.1</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.14.1</version> </dependency> </dependencies>
2、创立 RestHighLevelClient
public class AbstractEsApi { protected final RestHighLevelClient client; public AbstractEsApi() { client = new RestHighLevelClient( RestClient.builder( new HttpHost("localhost", 9200, "http"), new HttpHost("localhost", 9201, "http"), new HttpHost("localhost", 9202, "http") ) ); }}
3、实现查问
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("------------"); }); }}
1、输入查问语句
应用输入 SearchSourceBuilder
的后果即可。
2、输入响应后果
间接输入 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