在弹性搜索 date_histogram 聚合中将长时间戳表示为日期

Representing a long timestamp as date in elastic search date_histogram aggregation

我有一个索引,其中 ts 字段代表纪元 ms:

"ts": {
    "type": "long"
}

注意类型是 long,不是 epoch_millis 日期类型。

I 运行 该字段上的日期直方图聚合:

{
    ...
    "aggs": {
       "agg_name": {
            "date_histogram": {
                "field": "ts",
                "interval": "1d",
                "format": "yyyy-MM-dd",
                "min_doc_count": 1
            }
        }
    }
}

正在尝试以每天的文档为基础进行汇总。 操作运行没问题,但是一个bucket输出如下:

{
    "key_as_string": "yyyy-MM-dd1577836800000",
    "key": 1577836800000,
    "doc_count": 3
}

我的问题是:如何在不更改字段类型的情况下将 key_as_string 呈现为 2020-01-01 之类的东西。

您可以使用 painless scripting language 来实现您想要的,但效率不高,因为无痛脚本在字段操作方面有很多开销。这是执行此操作的脚本方法

您可以设置格式并将纪元的长整数转换为纪元的瞬时值,然后按照您想要的方式进行格式化。如前所述,这效率不高,但可以完成工作。

{
  "aggs": {
    "dt_terms": {
      "terms": {
        "script": {
          "source": """
           DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd").withZone(ZoneId.systemDefault());
           return df.format(Instant.ofEpochMilli(doc['ts'].value));
""",
          "lang": "painless"
        }
      }
    }
  }
}

由于您不想修改原始字段的数据类型,另一种实现方式是使用 copy_to 字段。在您的映射中,如果您添加如下所示的新 copy_to 字段并使用日期数据类型,则您不必 运行 脚本并使用其复制到的字段进行聚合。

PUT /index_name/_mapping
{
  "properties": {
    "ts": {
      "type": "long",
      "copy_to": "ts_d"
    },
    "ts_d": {
      "type": "date"
    }
  }
}

如果你有上面的映射,你可以使用 reindex API 来索引新的映射,然后使用下面的查询,它现在可以处理日期数据类型。

GET /_search
{
  "aggs": {
       "agg_name": {
            "date_histogram": {
                "field": "ts_d",
                "interval": "1d",
                "format": "yyyy-MM-dd",
                "min_doc_count": 1
            }
        }
    }
}