ES java 请求ES聚合嵌套参数拼接
目录
使用Java请求es聚合查询,这时候使用RestHighLevelClient 进行请求查询,无论是拼接参数,还是处理值都是麻烦些的。如果使用Commons-httpclient里面的 HttpClient进行请求,这时候拼接参数查询就直接是es的语法了,处理值也方便些,没有那么多的类型。
使用 RestHighLevelClient 处理的时候,该如何处理参数呢?
查询query的时候,可以使用
QueryBuilder queryBuilder = QueryBuilders.wrapperQuery(sourceExpr);
searchSourceBuilder.query(queryBuilder);
处理aggs参数的时候,就没了,得手动一个个拼接。
过程:
请求的参数:
{
"size": 0,
"aggs": {
"colors": {
"terms": {
"field": "color.keyword"
},
"aggs": {
"gap_price": {
"bucket_script": {
"buckets_path": {
"deal0": "max_price",
"deal1": "min_price"
},
"script": "params.deal0 - params.deal1"
}
},
"max_price": {
"sum": {
"field": "price"
}
},
"min_price": {
"value_count": {
"field": "material.keyword"
}
}
}
}
}
}
代码:
引用部分参考《es 聚合查询 语法和例子》
1,StrTermNextScript:
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.elasticsearch.script.Script;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.aggregations.bucket.range.DateRangeAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.range.RangeAggregationBuilder;
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregatorBuilders;
import org.elasticsearch.search.aggregations.pipeline.bucketscript.BucketScriptPipelineAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.joda.time.DateTimeZone;
import java.util.List;
import java.util.Map;
public class StrTermNextScript {
/**
* 字符型的拼接
* 第一层用 searchSourceBuilder 加
*/
private static void joinEsStrAggs(Map<String,Object> aggsMap, SearchSourceBuilder searchSourceBuilder) {
Map<String,Object> aggsNameMap = (Map<String, Object>) aggsMap.get("aggs");
AggregationBuilder aggregationBuilder;
for (Map.Entry name : aggsNameMap.entrySet()) {
String aggName = name.getKey().toString();
Map<String,Object> valueMap = (Map<String, Object>) name.getValue();
for (Map.Entry value : valueMap.entrySet()) {
String aggType = value.getKey().toString();
Map<String,Object> fieldMap = (Map<String, Object>) value.getValue();
aggregationBuilder = setAggsBuilders(aggName,aggType,fieldMap);
if("terms".equals(aggType)){
Map<String,Object> innerAggsMap = (Map<String, Object>) valueMap.get("aggs");
if(MapUtils.isNotEmpty(innerAggsMap)){
joinSecEsStrAggs(innerAggsMap, aggregationBuilder);
}
}
if(aggregationBuilder != null){
searchSourceBuilder.aggregation(aggregationBuilder);
}
}
}
}
/**
* 字符型的拼接
* 第二层用 aggregationBuilder 的 subAggregation 方法添加后面的内容
*/
private static void joinSecEsStrAggs(Map<String,Object> aggsNameMap, AggregationBuilder allAggregationBuilder) {
AggregationBuilder aggregationBuilder;
for (Map.Entry name : aggsNameMap.entrySet()) {
String aggName = name.getKey().toString();
Map<String,Object> valueMap = (Map<String, Object>) name.getValue();
for (Map.Entry value : valueMap.entrySet()) {
String aggType = value.getKey().toString();
Map<String,Object> fieldMap = (Map<String, Object>) value.getValue();
aggregationBuilder = setAggsBuilders(aggName,aggType,fieldMap);
if("terms".equals(aggType)){
Map<String,Object> innerAggsMap = (Map<String, Object>) valueMap.get("aggs");
if(MapUtils.isNotEmpty(innerAggsMap)){
joinSecEsStrAggs(innerAggsMap, aggregationBuilder);
}
}
if("bucket_script".equals(aggType)){
BucketScriptPipelineAggregationBuilder bucketScript = getBucketScript(aggName,fieldMap);
if(aggregationBuilder != null){
aggregationBuilder.subAggregation(bucketScript);
}else{
allAggregationBuilder.subAggregation(bucketScript);
}
}
if(aggregationBuilder != null){
allAggregationBuilder.subAggregation(aggregationBuilder);
}
}
}
}
private static BucketScriptPipelineAggregationBuilder getBucketScript(String aggName, Map<String, Object> aggParam){
Map<String, String> bucketsPathHashMap = (Map<String, String>) aggParam.get("buckets_path");
return PipelineAggregatorBuilders.bucketScript(aggName, bucketsPathHashMap,
new Script(MapUtils.getString(aggParam,"script")));
}
/**
* 根据聚合类型 获取对应的聚合builder
* @param aggName 聚合名称
* @param aggType 聚合类型
* @param aggParam 聚合参数
* @return AggregationBuilder
*/
private static AggregationBuilder setAggsBuilders(String aggName, String aggType, Map<String, Object> aggParam){
String fieldValue = MapUtils.getString(aggParam, "field");
AggregationBuilder aggregationBuilder = null;
if("terms".equals(aggType)){
int size = MapUtils.getIntValue(aggParam, "size");
if(size == NumberUtils.INTEGER_ZERO){
size = 10;
}
aggregationBuilder = AggregationBuilders.terms(aggName).field(fieldValue).size(size);
}else if("sum".equals(aggType)){
aggregationBuilder = AggregationBuilders.sum(aggName).field(fieldValue);
}else if("avg".equals(aggType)){
aggregationBuilder = AggregationBuilders.avg(aggName).field(fieldValue);
}else if("max".equals(aggType)){
aggregationBuilder = AggregationBuilders.max(aggName).field(fieldValue);
}else if("min".equals(aggType)){
aggregationBuilder = AggregationBuilders.min(aggName).field(fieldValue);
}else if("value_count".equals(aggType)){
aggregationBuilder = AggregationBuilders.count(aggName).field(fieldValue);
}else if ("cardinality".equals(aggType)) {// 去重之后总数
aggregationBuilder = AggregationBuilders.cardinality(aggName).field(fieldValue);
} else if ("histogram".equals(aggType)) {// 直方图
Double interval = MapUtils.getDouble(aggParam, "interval");
Long minDocCount = MapUtils.getLong(aggParam, "min_doc_count");
aggregationBuilder = AggregationBuilders.histogram(aggName).field(fieldValue).interval(interval)
.minDocCount(minDocCount);
} else if ("date_histogram".equals(aggType)) {// 日期直方图
String interval = MapUtils.getString(aggParam, "interval");
String format = MapUtils.getString(aggParam, "format");
Long minDocCount = MapUtils.getLong(aggParam, "min_doc_count");
DateHistogramAggregationBuilder dateHistogramAggregationBuilder = AggregationBuilders.dateHistogram(aggName)
.field(fieldValue).dateHistogramInterval(new DateHistogramInterval(interval))
.minDocCount(minDocCount).timeZone(DateTimeZone.forOffsetHours(8));
if (StringUtils.isNotEmpty(format)) {
dateHistogramAggregationBuilder.format(format);
}
aggregationBuilder = dateHistogramAggregationBuilder;
} else if ("range".equals(aggType)) {// 范围
String fieleName = MapUtils.getString(aggParam, "field");
List<Map<String, Object>> ranges = (List<Map<String, Object>>) aggParam.get("ranges");
RangeAggregationBuilder rangeAggregationBuilder = AggregationBuilders.range(aggName).field(fieleName);
ListUtils.emptyIfNull(ranges).forEach(e -> {
Double from = MapUtils.getDouble(e, "from");
Double to = MapUtils.getDouble(e, "to");
rangeAggregationBuilder.addRange(from, to);
});
aggregationBuilder = rangeAggregationBuilder;
} else if ("date_range".equals(aggType)) {// 日期范围
String fieleName = MapUtils.getString(aggParam, "field");
String format = MapUtils.getString(aggParam, "format");
List<Map<String, Object>> ranges = (List<Map<String, Object>>) aggParam.get("ranges");
DateRangeAggregationBuilder dateRangeAggregationBuilder = AggregationBuilders.dateRange(aggName)
.field(fieleName).timeZone(DateTimeZone.forOffsetHours(8));
if (StringUtils.isNotEmpty(format)) {
dateRangeAggregationBuilder.format(format);
}
ListUtils.emptyIfNull(ranges).forEach(e -> {
String from = MapUtils.getString(e, "from");
String to = MapUtils.getString(e, "to");
dateRangeAggregationBuilder.addRange(from, to);
});
aggregationBuilder = dateRangeAggregationBuilder;
}
return aggregationBuilder;
}
}
2,模拟数据
private static Map<String,Object> initFirstData(){
String data ="{\n" +
"\t\"size\": 0,\n" +
"\t\"aggs\": {\n" +
"\t\t\"colors\": {\n" +
"\t\t\t\"terms\": {\n" +
"\t\t\t\t\"field\": \"color.keyword\"\n" +
"\t\t\t},\n" +
"\t\t\t\"aggs\": {\n" +
"\t\t\t\t\"min_price\": {\n" +
"\t\t\t\t\t\"value_count\": {\n" +
"\t\t\t\t\t\t\"field\": \"material.keyword\"\n" +
"\t\t\t\t\t}\n" +
"\t\t\t\t},\n" +
"\t\t\t\t\"max_price\": {\n" +
"\t\t\t\t\t\"sum\": {\n" +
"\t\t\t\t\t\t\"field\": \"price\"\n" +
"\t\t\t\t\t}\n" +
"\t\t\t\t},\n" +
"\t\t\t\t\"gap_price\": {\n" +
"\t\t\t\t\t\"bucket_script\": {\n" +
"\t\t\t\t\t\t\"buckets_path\": {\n" +
"\t\t\t\t\t\t\t\"deal0\": \"max_price\",\n" +
"\t\t\t\t\t\t\t\"deal1\": \"min_price\"\n" +
"\t\t\t\t\t\t},\n" +
"\t\t\t\t\t\t\"script\": \"params.deal0 - params.deal1\"\n" +
"\t\t\t\t\t}\n" +
"\t\t\t\t}\n" +
"\t\t\t}\n" +
"\t\t}\n" +
"\t}\n" +
"}";
System.out.println(JSONObject.parseObject(data).toJSONString());
Map<String,Object> parse = (Map<String, Object>) JSON.parse(data);
return parse;
}
3,测试:
public static void main(String[] args) {
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
Map<String,Object> aggsMap = initFirstData();
joinEsStrAggs(aggsMap, searchSourceBuilder);
System.out.println("aggs "+searchSourceBuilder.toString());
}
结果:
aggs {
"aggregations": {
"colors": {
"terms": {
"field": "color.keyword",
"size": 10,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [{
"_count": "desc"
}, {
"_key": "asc"
}]
},
"aggregations": {
"max_price": {
"sum": {
"field": "price"
}
},
"min_price": {
"value_count": {
"field": "material.keyword"
}
},
"gap_price": {
"bucket_script": {
"buckets_path": {
"deal0": "max_price",
"deal1": "min_price"
},
"script": {
"source": "params.deal0 - params.deal1",
"lang": "painless"
},
"gap_policy": "skip"
}
}
}
}
}
}
总结:
使用RestHighLevelClient 查询es聚合数据,处理参数会麻烦些,需要拼接对应的AggregationBuilder的内容,嵌套的,要逐层处理。复杂的东西,先从简单的入手,逐层解析,到后面就会发现规律的,有时候初看,知道有规律,但是又说不出来,那就动手实践。