计算两个日期字段之间的差异的平均值

时间:2020-03-11 16:36:10

标签: elasticsearch elasticsearch-aggregation elasticsearch-dsl elasticsearch-7

我正在一个使用Elasticsearch存储数据并显示一些复杂统计信息的项目。

我有一个索引,它看起来像这样:

Reservation {
  id: number
  check_in: Date
  check_out: Date
  created_at: Date
  // other fields...
}

我需要计算我的 check_in created_at 之间的平均天差 {{1 }}在特定日期范围内,并将结果显示为数字。

我尝试了这个Reservation

query

日期字段 ISO 8601 格式保存(例如:2020-03-11T14:25:15 + 00:00),我不知道这是否可能会产生问题。

它会吸引一些点击,因此,该查询肯定有效!但是,它总是返回{ "script_fields": { "avgDates": { "script": { "lang": "expression", "source": "doc['created_at'].value - doc['check_in'].value" } } }, "query": { "bool": { "must": [ { "range": { "created_at": { "gte": "{{lastMountTimestamp}}", "lte": "{{currentTimestamp}}" } } } ] } }, "size": 0, "aggs": { "avgBetweenDates": { "avg": { "field": "avgDates" } } } } 作为null聚合的值。

我需要这样的结果:

avgBetweenDates

任何想法都会有所帮助!

谢谢。

2 个答案:

答案 0 :(得分:1)

_search上下文中创建的脚本字段可以only be consumed within that scope。它们在aggregations中不可见!这意味着您必须选择两者之一

  • 将脚本移至aggs部分和doing the avg there
  • scripted metric聚合(相当缓慢且难以正确实现)
  • 或在索引时间创建一个dateDifference字段(最好是int –时间戳的差异),这将使您能够执行extended stats之类的强大数字汇总,以提供统计信息有用的输出,例如:
{
    ...

    "aggregations": {
        "grades_stats": {
           "count": 2,
           "min": 50.0,
           "max": 100.0,
           "avg": 75.0,
           "sum": 150.0,
           "sum_of_squares": 12500.0,
           "variance": 625.0,
           "std_deviation": 25.0,
           "std_deviation_bounds": {
            "upper": 125.0,
            "lower": 25.0
           }
        }
    }
}

并且总是比使用脚本计算时间戳差异快。

答案 1 :(得分:1)

脚本字段不是ES中存储的字段。由于scripted fields是动态创建的,因此只能对存储的字段执行聚合。

您可以简单地在Average Aggregation中移动脚本逻辑,如下所示。请注意,为了理解,我创建了示例映射,文档,查询及其响应。

映射:

PUT my_date_index
{
  "mappings": {
    "properties": {
      "check_in":{
        "type":"date",
        "format": "date_time"
      },
      "check_out":{
        "type": "date",
        "format": "date_time"
      },
      "created_at":{
        "type": "date",
        "format": "date_time"
      }
    }
  }
}

样本文档:

POST my_date_index/_doc/1
{
  "check_in": "2019-01-15T00:00:00.000Z",
  "check_out": "2019-01-20T00:00:00.000Z",
  "created_at": "2019-01-17T00:00:00.000Z"
}

POST my_date_index/_doc/2
{
  "check_in": "2019-01-15T00:00:00.000Z",
  "check_out": "2019-01-22T00:00:00.000Z",
  "created_at": "2019-01-20T00:00:00.000Z"
}

汇总查询:

POST my_date_index/_search
{
  "size": 0,
  "aggs": {
    "my_dates_diff": {
      "avg": {
        "script": """
          ZonedDateTime d1 = doc['created_at'].value;
          ZonedDateTime d2 = doc['check_in'].value;
          long differenceInMillis = ChronoUnit.MILLIS.between(d1, d2);
          return Math.abs(differenceInMillis/86400000);
        """
      }
    }
  }
}

请注意,您希望获得不同的天数。上面的逻辑可以做到这一点。

响应:

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "my_dates_diff" : {
      "value" : 3.5              <---- Average in Number of Days
    }
  }
}

希望这会有所帮助!