嵌套聚合求百分比——es记一次关于 bucket_script 根据需求不断改进的DSL及jestAPI

本文记录了在ES中如何通过bucket_script聚合计算每个科室下不同病历级别的百分比。通过多次尝试和错误分析,最终找到了解决方案,同时探讨了ES6.3新增的buckets_sort功能以及Jest API的实现方式。
  1. 需求:求每个科室下不同病历级别的百分比。
  2. 思路:按每个科室分组,再按级别分组,再求占比。
  3. 开动。

第一次尝试:

POST /medicalrecord/my_type/_search?size=0
{
  "size": 0,
  "aggs": {
    "department_group": {
      "terms": {
        "field": "department_secondary",
        "size": 1000000
      },
      "aggs": {
        "total_record": {
          "value_count": {
            "field": "emr_id"
          }
        },
        "levels": {
          "filter": {
            "terms": {
              "has_bug": [
                "1",
                "2",
                "3"
              ]
            }
          },
          "aggs": {
            "level_group": {
              "terms": {
                "field": "has_bug",
                "size": 3
              },
              "aggs": {
                "every_level_count": {
                  "value_count": {
                    "field": "emr_id"
                  }
                },
                "level_percentage": {
                  "bucket_script": {
                    "buckets_path": {
                      "every_level_count": "every_level_count",
                      "department_total_record": "total_record"
                    },
                    "script": "params.every_level_count / params.department_total_record"
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

报错:

{
  "error": {
    "root_cause": [
      {
        "type": "illegal_argument_exception",
        "reason": "No aggregation found for path [total_record]"
      }
    ],
    "type": "search_phase_execution_exception",
    "reason": "all shards failed",
    "phase": "query",
    "grouped": true,
    "failed_shards": [
      {
        "shard": 0,
        "index": "medicalrecord",
        "node": "p9ZUXdr9R3mxulJKxgNtGA",
        "reason": {
          "type": "illegal_argument_exception",
          "reason": "No aggregation found for path [total_record]"
        }
      }
    ]
  },
  "status"
<think>我们正在处理一个关于Elasticsearch7中使用bucket_script聚合时结果未正确显示的问题。根据用户描述,他们在使用bucket_script聚合时,查询结果中没有正确显示该聚合的结果。可能的原因及解决方案:1.语法错误:检查bucket_script聚合的语法是否正确。bucket_script聚合需要放在pipelineaggregation(管道聚合)中,并且必须指定buckets_path参数来引用之前聚合的结果。2.路径引用错误:在buckets_path中引用的其他聚合名称是否正确?注意,路径是使用点符号(例如:"the_sum"或"the_sum.value")来引用的,具体取决于被引用的聚合类型。3.聚合顺序问题:bucket_script聚合必须定义在它引用的聚合之后,因为管道聚合是顺序执行的。4.缺少必要的父聚合bucket_script聚合必须作为父聚合的子聚合,且父聚合必须是多聚合(如date_histogram,terms等)。5.结果中未包含该聚合:在查询返回的结果中,管道聚合的结果通常位于其父聚合的结果对象中,而不是在顶层。因此,需要检查父聚合的结果中是否有该管道聚合的输出。我们来看一个正确的bucket_script聚合的示例:假设我们有一个销售数据索引,我们想按日期(天)分组,然后计算每个的总销售额(sum聚合),然后使用bucket_script聚合计算一个表达式(例如,总销售额乘以0.1作为税费)。正确的查询结构如下:```json{"size":0,"aggs":{"sales_over_time":{"date_histogram":{"field":"date","calendar_interval":"day"},"aggs":{"total_sales":{"sum":{"field":"price"}},"sales_tax":{"bucket_script":{"buckets_path":{"totalSales":"total_sales"//这里引用子聚合total_sales的结果},"script":"params.totalSales*0.1"}}}}}}```在返回的结果中,每个日期中会包含两个子聚合的结果:total_sales和sales_tax。如果用户没有看到sales_tax的结果,请检查:-聚合名称是否拼写正确(大小写敏感)。-在父聚合(sales_over_time)的buckets数组中,每个是否包含sales_tax字段。-脚本是否正确(例如,没有语法错误,且使用了正确的参数名)。另外,Elasticsearch7对脚本语言进行了调整,默认使用Painless脚本语言,并且需要确保脚本的正确性。如果脚本有错误,可能会导致整个聚合失败。如果问题仍然存在,建议检查Elasticsearch的返回错误(如果有),或者启用调试模式来查看更详细的错误信息。根据引用[3]中的内容,我们可以联想到在聚合结果中如何组织数据,但引用[3]是关于Kibana可视化操作的,与直接查询Elasticsearch稍有不同。不过,原理是相通的:聚合结果需要正确组织才能被展示。因此,用户需要检查其聚合查询的结构,确保bucket_script聚合被正确嵌套在父聚合中,并且引用的路径正确。如果用户的问题仍未解决,可能需要提供具体的查询示例以便进一步诊断。现在,根据指令要,生成相关问题:§§相关问题§§1.如何调试Elasticsearch聚合查询中的错误?2.在Elasticsearch中,管道聚合(如bucket_script)有哪些使用限制?3.如何优化包含脚本的聚合查询性能?4.在Kibana中如何可视化bucket_script聚合的结果?</think>### Elasticsearch 7中bucket_script聚合未显示问题分析 在Elasticsearch 7中使用`bucket_script`聚合时结果未显示,通常由以下原因导致: #### 常见原因及解决方案 1. **路径引用错误** `buckets_path`必须正确指向现有聚合: ```json "buckets_path": { "var1": "agg1", // 正确引用子聚合名称 "var2": "agg2.value" // 对metric聚合需加.value后缀 } ``` 🔍 检查:确保引用的聚合名称与定义完全一致(区分大小写) 2. **脚本语法问题** - Elasticsearch 7默认使用Painless脚本 - 错误示例:`"script": "params.var1 + params.var2"`(缺少分号) - 正确格式: ```json "script": "params.var1 + params.var2;" // Painless需要分号结尾 ``` 3. **聚合位置错误** `bucket_script`必须定义在**多聚合**(如`date_histogram`)内部: ```json "aggs": { "date_agg": { "date_histogram": {"field": "timestamp", "calendar_interval": "day"}, "aggs": { "sum_agg": {"sum": {"field": "price"}}, "calc_agg": { // ✅ 正确位置 "bucket_script": { "buckets_path": {"total": "sum_agg"}, "script": "params.total * 0.1;" } } } } } ``` 4. **空处理缺失** 当引用聚合结果为空时需设置默认值: ```json "bucket_script": { "buckets_path": {"v": "some_agg"}, "script": "params.v != null ? params.v : 0;", // 空值处理 "gap_policy": "skip" // 或"insert_zeros" } ``` #### 调试建议 1. 先单独测试被引用的子聚合是否正常返回结果 2. 在Kibana Dev Tools中执行查询,检查错误响应: ```json { "error": { "root_cause": [ { "type": "script_exception", "reason": "runtime error..." } ] } } ``` 3. 使用简单脚本逐步调试: ```json "script": "return 1;" // 最小化测试 ``` #### 完整示例 ```json GET /sales/_search { "size": 0, "aggs": { "by_date": { "date_histogram": { "field": "order_date", "calendar_interval": "month" }, "aggs": { "total_sales": {"sum": {"field": "amount"}}, "tax_calculated": { "bucket_script": { "buckets_path": {"sales": "total_sales"}, "script": "params.sales * 0.08;", // 计算税率 "gap_policy": "insert_zeros" } } } } } } ``` > **结果验证**:成功执行后,每个日期会包含`tax_calculated`字段: > ```json > "buckets": [ > { > "key_as_string": "2023-01-01", > "key": 1672531200000, > "doc_count": 45, > "total_sales": {"value": 12000}, > "tax_calculated": {"value": 960} // ✅ 显示计算结果 > } > ] > ```
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值