Elasticsearch Painless - 按字段对所有文档进行分组,并对所有值进行计算

Elasticsearch Painless - Group all doucuments by a field, and do calculation on all values

我有 'vehicles' 索引模式,每个文档都有一个车牌号 ('plateNo')、'position' 和 'date' 字段。作为测试,我想按车牌号对该索引中的所有文档进行分组,然后按日期对文档进行排序,最后计算每辆车移动的距离,并将每两个位置之间的绝对差相加。

例如:

plateNo position date
vehicle 1 1 May 16, 2021 @ 15:55:37
vehicle 2 7 May 16, 2021 @ 15:55:05
vehicle 1 5 May 16, 2021 @ 15:54:30
vehicle 2 10 May 16, 2021 @ 15:53:01
vehicle 1 2 May 16, 2021 @ 15:50:41

的输出必须是

plateNo distance
vehicle 1 abs(5 - 2) + abs(1 - 5) = 7
vehicle 2 abs(7 - 10) = 3

我如何使用 Painless 做到这一点? - 快速响应很重要,文档数量非常大 谢谢

假设:

  • 同一车辆的数据存在于单个分片上
  • 映射中定义的日期格式为'epoch_millis'
  • 如果车辆只有一次进入,则其距离将为零

使用的聚合: scripted_metric

步骤:

  • Init: 初始化了一个 TreeMap 用于存储 timestamp 作为 key 和 pos 作为 value
  • Map: 将timestamp & pos的值放入TreeMap
  • 收集:获取值并计算位置差(pos按时间戳排序返回)
  • 减少: Return距离

示例查询:

  GET vehicle/_search
  {
  "size": 0,
  "aggs": {
    "vehicles": {
      "terms": {
        "field": "vehicle",
        "size": 10
      },
      "aggs": {
        "distance": {
          "scripted_metric": {
            "init_script": "state.dt_point_map=new TreeMap(); state.distance=0; ",
            "map_script": "state.dt_point_map.put(doc.date.value,doc.pos.value);",
            "combine_script": "int i=0;long prev=0; for(p in state.dt_point_map.values()){if(i==0){prev=p;i++;}else{state.distance+=Math.abs(p-prev);prev=p;i++;}} return state.distance;",
            "reduce_script": "double overallDistance = 0; for (distance in states) { overallDistance += distance } return overallDistance;"
          }
        }
      }
    }
  }
  }

建议:预先计算并存储数据以便快速访问。