ES多个字段group by操作

以下操作基于es6.8

第一种方式

这种方式查询出来的数据不是扁平化的,而是一层套一层的,比如字段一套字段二。

GET 索引name/索引type/_search
{
	"size": 0,
	"aggregations": {
		"字段一的结果命名": {
			"terms": {
				"field": "要group的字段"
			},
			"aggregations": {
				"字段二的结果命名": {
					"terms": {
						"field": "要group的字段"
					}
				}
			}
		}
	}
}

结果,one下面的buckets里面是two,每个two下面有自己的bukets,就是two的值和count。

ES多个字段group by操作_第1张图片

java代码实现

    public void demo1(RestHighLevelClient client) {
        // group
        TermsAggregationBuilder oneBuilder = AggregationBuilders.terms("one").field("flowCode.keyword");
        TermsAggregationBuilder twoBuilder = AggregationBuilders.terms("two").field("stepExecuteId");
        oneBuilder.subAggregation(twoBuilder);
        // search
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.aggregation(oneBuilder);
        // request
        SearchRequest searchRequest = new SearchRequest("index");
        searchRequest.types("type");
        searchRequest.source(searchSourceBuilder);
        try {
            SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
            Terms oneTerm = (Terms) response.getAggregations().asMap().get("one");
            for (Terms.Bucket bucket : oneTerm.getBuckets()) {
                System.out.println("one下面的" + bucket.getKey() + ", count是: " + bucket.getDocCount());
                Terms twoTerm = (Terms) bucket.getAggregations().asMap().get("two");
                for (Terms.Bucket twoTermBucket : twoTerm.getBuckets()) {
                    System.out.println("two下面的" + twoTermBucket.getKey() + ", count是: " + twoTermBucket.getDocCount());
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

封装

封装一个通用的聚合查询并映射到java类中
 

package com.es.agg.demo;

import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class App2 {

    private RestHighLevelClient client;

    /**
     * group by 多字段统计
     *
     * @param index
     * @param type
     * @param queryBuilder
     * @param clazz
     * @param groupKeys
     * @return
     */
    public List group(String index, String type, String resultKey, BoolQueryBuilder queryBuilder, Class clazz, String... groupKeys) {
        TermsAggregationBuilder firstBuilder = null;
        TermsAggregationBuilder topAggregationBuilder = null;
        for (String groupKey : groupKeys) {
            TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms(groupKey).field(groupKey);
            if (topAggregationBuilder != null) {
                topAggregationBuilder.subAggregation(aggregationBuilder);
            } else {
                firstBuilder = aggregationBuilder;
            }
            topAggregationBuilder = aggregationBuilder;
        }
        SearchResponse response = this.group(index, type, queryBuilder, firstBuilder);
        List finishModels = new ArrayList<>();
        Terms terms = (Terms) response.getAggregations().getAsMap().get(groupKeys[0]);
        this.buildEsModel(groupKeys, resultKey, terms, null, 0, finishModels);
        return finishModels.stream().map(item -> item.build(clazz)).collect(Collectors.toList());
    }

    /**
     * 构建es group by model
     *
     * @param groupKeys
     * @param terms
     * @param topEsModel
     * @param level
     * @param finishModels
     */
    private void buildEsModel(String[] groupKeys, String resultKey, Terms terms, EsModel topEsModel, int level, List finishModels) {
        if (level == (groupKeys.length - 1)) {
            if (terms != null && terms.getBuckets() != null && !terms.getBuckets().isEmpty()) {
                for (Terms.Bucket bucket : terms.getBuckets()) {
                    EsModel parentEsModel = new EsModel(groupKeys[level], bucket.getKey().toString(), topEsModel);
                    EsModel childEsModel = new EsModel(resultKey, bucket.getDocCount(), parentEsModel);
                    finishModels.add(childEsModel);
                }
            }
        } else {
            if (terms != null && terms.getBuckets() != null && !terms.getBuckets().isEmpty()) {
                for (Terms.Bucket bucket : terms.getBuckets()) {
                    EsModel esModel = new EsModel(groupKeys[level], bucket.getKey().toString(), topEsModel);
                    Terms childTerms = (Terms) bucket.getAggregations().getAsMap().get(groupKeys[level + 1]);
                    buildEsModel(groupKeys, resultKey, childTerms, esModel, level + 1, finishModels);
                }
            } else {
                return;
            }
        }
    }

    public SearchResponse group(String index, String type, BoolQueryBuilder queryBuilder, TermsAggregationBuilder aggregationBuilder) {
        // 搜索源构建对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(queryBuilder);
        searchSourceBuilder.aggregation(aggregationBuilder);
        searchSourceBuilder.size(0);
        // 基础设置
        SearchRequest searchRequest = new SearchRequest(index);
        searchRequest.types(type);
        searchRequest.source(searchSourceBuilder);
        try {
            return client.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

}

第二种方式

这种方式查出来的数据更扁平化,容易被接受

GET 索引名称/索引类型/_search
{
    "size": 0,
    "query": {
        "match_all": {}
    },
    "aggs": {
        "result": {
            "terms": {
                "script": {
                    "inline": "doc['字段1'].value +'分隔符'+ doc['字段2'].value "
                }
            }
        }
    }
}

可以看到,这次的数据很扁平化,只是中间有了分隔符,读取数据的时候 需要自己处理

ES多个字段group by操作_第2张图片

java代码实现

    public void demo2(RestHighLevelClient client) {
        // script
        Script script = new Script(ScriptType.INLINE, "groovy", "doc['flowCode.keyword'].value+'-split-'+doc['stepExecuteId'].value", new HashMap<>());
        TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("result").script(script);
        // search
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.aggregation(aggregationBuilder);
        // request
        SearchRequest searchRequest = new SearchRequest("index");
        searchRequest.types("type");
        searchRequest.source(searchSourceBuilder);
        try {
            SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
            Terms oneTerm = (Terms) response.getAggregations().asMap().get("result");
            for (Terms.Bucket bucket : oneTerm.getBuckets()) {
                // 此处自己split分隔处理
                System.out.println(bucket.getKey().toString());
                System.out.println(bucket.getDocCount());
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

代码地址: https://github.com/qiaomengnan16/es-agg-demo

关注公众号,回复加群,邀请你进入技术内推、分享群,一起聊聊新鲜事儿

ES多个字段group by操作_第3张图片

 

你可能感兴趣的:(elasticsearch,大数据,big,data)