ElasticSearch 聚合查询百分比

时间:2021-09-19 23:19:20

这里用的是es5.6.9

bucket_script :它执行一个脚本,该脚本可以对多桶聚合中的指定度量执行每桶计算,指定的度量标准必须为数字,并且脚本必须返回数值。

官方语法

https://www.elastic.co/guide/en/elasticsearch/reference/master/search-aggregations-pipeline-bucket-script-aggregation.html

{
    "bucket_script": {
        "buckets_path": {
            "my_var1": "the_sum", 
            "my_var2": "the_value_count"
        },
        "script": "params.my_var1 / params.my_var2"
    }
}

给的一个例子

算出t-shirts卖出的钱占总钱数的百分比
POST /sales/_search
{
    "size": 0,
    "aggs" : {
        "sales_per_month" : {
            "date_histogram" : {
                "field" : "date",
                "interval" : "month"
            },
            "aggs": {
                "total_sales": {
                    "sum": {
                        "field": "price"
                    }
                },
                "t-shirts": {
                  "filter": {
                    "term": {
                      "type": "t-shirt"
                    }
                  },
                  "aggs": {
                    "sales": {
                      "sum": {
                        "field": "price"
                      }
                    }
                  }
                },
                "t-shirt-percentage": {
                    "bucket_script": {
                        "buckets_path": {
                          "tShirtSales": "t-shirts>sales",
                          "totalSales": "total_sales"
                        },
                        "script": "params.tShirtSales / params.totalSales * 100"
                    }
                }
            }
        }
    }
}
script:聚合运行的脚本
buckets_path:脚本变量的映射及其与我们希望用于变量的桶的关联路径
format:格式以应用于此聚合的输出值
gap_policy:在数据中发现差距时应用的策略
其中"t-shirts"这个聚合里面又套了一层取值的聚合是因为buckets_path里引用的必须是一个值filter返回的不是一个值

也可以这样写
POST /sales/_search
{
    "size": 0,
    "aggs" : {
        "sales_per_month" : {
            "date_histogram" : {
                "field" : "date",
                "interval" : "month"
            },
            "aggs": {
                "total_sales": {
                    "sum": {
                        "field": "price"
                    }
                },
                "t-shirts": {
                  "filter": {
                    "term": {
                      "type": "t-shirt"
                    }
                  }
                },
                "t-shirt-percentage": {
                    "bucket_script": {
                        "buckets_path": {
                          "tShirtSales": "t-shirts>_count",
                          "totalSales": "total_sales"
                        },
                        "script": "params.tShirtSales / params.totalSales * 100"
                    }
                }
            }
        }
    }
}

在spring data 中使用 bucket_script 聚合

ValueCountAggregationBuilder valueCountAggregationBuilder=AggregationBuilders.count("聚合的名字:total_attendance").field("聚合的字段名");
FilterAggregationBuilder filterLate=AggregationBuilders
                .filter("聚合的名字:filter_count",QueryBuilders.termQuery("term的字段名","过滤的字段值"));
Map<String,String> scriptParams=new HashMap<>();
        lateScriptParams.put("total","total_attendance");
        lateScriptParams.put("count","filter_count>_count");
BucketScriptPipelineAggregationBuilder script= PipelineAggregatorBuilders
                .bucketScript("聚合的名字:result",scriptParams,new Script("params.count/params.total*100")).format("#.##");

然后就是把聚合放到查询里面了

TermsAggregationBuilder usersResultAggs= AggregationBuilders.terms("users_term").field("userId.keyword")
.subAggregation(result)
.subAggregation(filter_count)
.subAggregation(total);

取值

1.使用elasticsearchTemplate

elasticsearchTemplate.query(searchQuery, searchResponse -> {
            Map<String,Aggregation> aggregationMap=searchResponse.getAggregations().asMap();
            StringTerms stringTerms = (StringTerms)aggregationMap.get("取值的那个聚合的名字:users_term");

        //取值
       return aggregationMap.get("取值的那个聚合的名字:result")).getValue()
   stringTerms.getBuckets().forEach(aggs->{
Map<String,Aggregation> subAggMap=aggs.getAggregations().asMap();
    //取百分比
    Double result=((InternalSimpleValue)subAggMap.get("notsigendScript")).getValue();
  });
  return 返回结果;
});