前两篇介绍了es的简单条件查询,本文将在条件查询的基础上添加聚合条件进行查询,聚合查询很大的不同是在查询结果的解析上。
首先看一下这条dsl查询语句:
GET test*/_search
{
"size": 0,
"timeout": "60s",
"query": {
"bool": {
"must": [
{
"terms": {
"server_name.keyword": [
"www.test.com"
],
"boost": 1
}
},
{
"match_phrase": {
"args": {
"query": "786754748671257",
"slop": 0,
"zero_terms_query": "NONE",
"boost": 1
}
}
},
{
"range": {
"@timestamp": {
"from": "2020-06-04T16:00:00.000Z",
"to": "2020-06-04T18:00:00.000Z",
"include_lower": true,
"include_upper": false,
"boost": 1
}
}
}
],
"adjust_pure_negative": true,
"boost": 1
}
},
"aggregations": {
"@timestamp": {
"date_histogram": {
"field": "@timestamp",
"interval": "1h",
"offset": 0,
"order": {
"_key": "asc"
},
"keyed": false,
"min_doc_count": 0
},
"aggregations": {
"args": {
"terms": {
"field": "args.keyword",
"min_doc_count": 100,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
}
}
}
}
},
"track_total_hits": "true"
}
接下来的代码绑定查询条件部分都会围绕这条语句来写
再看一下这条语句的查询结果:
{
"took" : 42,
"timed_out" : false,
"_shards" : {
"total" : 660,
"successful" : 660,
"skipped" : 648,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 53,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"@timestamp" : {
"buckets" : [
{
"key_as_string" : "2020-06-04T16:00:00.000Z",
"key" : 1591286400000,
"doc_count" : 28,
"args" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 27,
"buckets" : [
{
"key" : "dt=51&expired=1591286876393&ufi=786754748671257&zyc=5&token=cloud14&sig=5DqpNn5G2L8rtytertThyvXoyqXjIl%2BSck%3D",
"doc_count" : 1
}
]
}
},
{
"key_as_string" : "2020-06-04T17:00:00.000Z",
"key" : 1591290000000,
"doc_count" : 25,
"args" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 24,
"buckets" : [
{
"key" : "dt=51&expired=1591290322988&ufi=786754748671257&zyc=5&token=cloud16&sig=nARSWMB5%2BuerteregKADzmCARMRk4oXoms%3D",
"doc_count" : 1
}
]
}
}
]
}
}
}
接下来代码里的解析查询结果部分会围绕这个来写
代码
public class ESReadTest {
// ES的用户名,密码,地址
private final String user = "user";
private final String password = "password";
private final String hostname = "127.0.0.1";
private String indexName;
private RestHighLevelClient client;
// 用来将北京时间转换成UTC时间
public String getUTCStr(String date) {
String returnDate = "";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
returnDate = new DateTime(sdf.parse(date)).plusHours(-8).toString("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
}
catch (ParseException e)
{
e.printStackTrace();
}
return returnDate;
}
// 初始化Client
public void iniES(String indexName){
final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(AuthScope.ANY,
new UsernamePasswordCredentials(user, password));
RestClientBuilder builder = RestClient.builder(
new HttpHost(hostname, 9200))
.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
return httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);}});
this.client = new RestHighLevelClient(builder);
this.indexName=indexName;
}
//构建请求
public SearchResponse dslBulider() throws IOException {
SearchRequest searchRequest = new SearchRequest(this.indexName);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
// hit 返回值(bool 查询返回条数)
searchSourceBuilder.size(0);
// searchSourceBuilder.from(0);
searchSourceBuilder.trackTotalHits(true);
// 超时时间60s
searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
// 添加查询条件
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
boolQueryBuilder.must(QueryBuilders.termsQuery("server_name.keyword", "www.test.com"));
boolQueryBuilder.must(QueryBuilders.matchPhraseQuery("args","786754748671257"));
boolQueryBuilder.must(QueryBuilders.rangeQuery("@timestamp").gte(getUTCStr("2020-06-05 00:00:00")).lt(getUTCStr("2020-06-05 02:00:00")));
// 添加聚合条件 按每小时 args字段聚合
DateHistogramAggregationBuilder dateBuilder = AggregationBuilders.dateHistogram("@timestamp").dateHistogramInterval(new DateHistogramInterval("1h")).field("@timestamp")
.subAggregation(
AggregationBuilders.terms("args").field("args.keyword")
);
// 绑定条件
searchSourceBuilder.query(boolQueryBuilder);
searchSourceBuilder.aggregation(dateBuilder);
searchRequest.source(searchSourceBuilder);
// 发起请求并接收响应
SearchResponse searchResponse = this.client.search(searchRequest, RequestOptions.DEFAULT);
// 打印dsl语句
System.out.println("dsl is: "+searchRequest.source());
return searchResponse;
}
// 解析查询结果
public List<JSONObject> dslParse(SearchResponse searchResponse) {
List<JSONObject> jsonList=new ArrayList<>();
// 获取第一层timestamp并遍历
ParsedDateHistogram timestampList = searchResponse.getAggregations().get("@timestamp");
for (MultiBucketsAggregation.Bucket timestamp : timestampList.getBuckets()){
// 获取第二层args并遍历
ParsedStringTerms argsList = timestamp.getAggregations().get("args");
for (MultiBucketsAggregation.Bucket args : argsList.getBuckets()){
// 获取时间、args、数量,这里的时间也是UTC时间
JSONObject jsonObject=new JSONObject();
jsonObject.put("date",timestamp.getKey());
jsonObject.put("args",args.getKey());
jsonObject.put("doc_count",args.getDocCount());
jsonList.add(jsonObject);
}
}
return jsonList;
}
public void closeES(){
try {
this.client.close();
}catch (Exception e){
e.printStackTrace();
}
}
public void run(){
try {
this.iniES("test*");
// 查询并打印结果
List<JSONObject> jsonStringList = this.dslParse(this.dslBulider());
for (JSONObject jsonObject : jsonStringList) {
System.out.println(JSON.toJSONString(jsonObject));
}
}catch (Exception e){
e.printStackTrace();
}finally {
this.closeES();
}
}
public static void main(String[] args) {
ESReadTest esReadTest=new ESReadTest();
esReadTest.run();
}
}