ElasticSearch使用嵌套和根级别数据的嵌套聚合比率

cig3rfwq  于 2023-03-17  发布在  ElasticSearch
关注(0)|答案(1)|浏览(108)

我有一个简单的聚合,我有一个计时代码文档,如下所示:

{
  "task_start": "2020-06-03T21:19:07.908821Z",
  "task_end": "2020-06-03T21:27:00.323790Z",
  "sub_tasks": [
    {
      "key": "sub-task1-time-milliseconds",
      "value": 3310
    },
    {
      "key": "sub-task2-time-milliseconds",
      "value": 2410
    },
    ...
  ]
}

其中sub_tasks是嵌套的。我想得到的是每个子任务的时间与整个任务时间的中值比率。整个任务时间将是end_time - start_time。我知道如何分别聚合中值子任务时间和总任务时间。但我想聚合每个文档的比率。
问题是在嵌套聚合中,我只能访问带有嵌套数据的数据,而在反向嵌套聚合中,我只能访问根级别的数据,但不能同时访问这两个数据。我知道有一种方法可以访问copy_to,这样我就可以在嵌套路径中获得任务时间,但我无法修改索引结构,也不希望有额外的存储空间。
下面是我尝试的方法。对于嵌套聚合:

{
  "aggs": {
    "task_metrics": {
      "nested": {
        "path": "sub_tasks"
      },
      "aggs": {
        "sub_task_metrics": {
          "filter": {
            "term": {
              "sub_tasks.key": "sub-task1-time-milliseconds"
            }
          },
          "aggs": {
            "median_time": {
              "percentiles": {
                "script": {
                  "lang": "painless",
                  "source": """
                            double task_time = (doc['task_end'].value.millis - doc['task_start'].value.millis);
                            return doc['sub_tasks.value'].value / task_time; 
                            """
                },
                "percents": 50
              }
            }
          }
        }
      }
    }
  }
}

但是在那个聚合中,doc['task_start']doc['task_end']只返回零,因为我没有访问它们的权限。为了获得访问权限,我还尝试了添加另一个子聚合的reverse_nested。这使我获得了对doc['task_start']doc['task_end']的访问权限,但是doc['sub_tasks.value'].value只返回0
我只是感觉这应该是可能的,但是当我阅读管道聚合和其他脚本聚合时,我不相信它们中的任何一个能达到我的目的。非常感谢任何帮助,谢谢!

kx7yvsdv

kx7yvsdv1#

这个问题比较棘手--已经讨论过here了。
我认为您必须求助于一些scripted_metric和一些方法模拟,因为公开的无痛API是somewhat limited

{
  "size": 0, 
  "aggs": {
    "task_metrics_median": {
      "scripted_metric": {
        "init_script": "state.ratios = new ArrayList();",

        "map_script": """
          // access the source incl. the nested subtasks
          def d = params._source;

          for (def subtask : d.sub_tasks) {
            // mimicking a `term` query
            if (subtask.key != 'sub-task1-time-milliseconds') break;
           
            // incoming as strings so parse
            def millis_end = ZonedDateTime.parse(d.task_end).toInstant().toEpochMilli();
            def millis_start = ZonedDateTime.parse(d.task_start).toInstant().toEpochMilli();
            
            double task_time = (millis_end - millis_start);

            // prevent zero division
            if (task_time <= 0) break;

            state['ratios'].add(subtask.value / task_time);  
          }
        """,

        "combine_script": """
            def ratios = state.ratios;
            Collections.sort(ratios);
            
            // trivial median calc
            double median;
            if (ratios.length % 2 == 0) {
                median = ((double)ratios[ratios.length/2] + (double)ratios[ratios.length/2 - 1])/2;
            } else {
                median = (double) ratios[ratios.length/2];
            }

            return median
        """,

        "reduce_script": "return states"
      }
    }
  }
}

相关问题