Elasticsearch Painless获取当前时间

Elasticsearch Painless获取当前时间

本文讨论下Elasticsearch如何获取当前时间,通常需要计算时间间隔时使用。日期处理Painless使用标准的Java库,主要类有:

  • java.time
  • java.time.chrono
  • java.time.format
  • java.time.temporal
  • java.time.zone

官方API地址为:https://www.elastic.co/guide/en/elasticsearch/painless/master/painless-api-reference-shared-org-elasticsearch-script.html#painless-api-reference-shared-JodaCompatibleZonedDateTime

1. Java 8 获取当前时间

我们首先介绍几种Java 8获取当前日期、时间方式。

1.1. 当前Date

使用java.time.LocalDate 获取当前系统日期:

LocalDate localDate = LocalDate.now();

获取带时区的当前日期:

LocalDate localDate = LocalDate.now(ZoneId.of("GMT+02:30"));
ZonedDateTime zbj = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));

当然也可以通过LocalDateTime获得LocalDate:

LocalDateTime localDateTime = LocalDateTime.now();
LocalDate localDate = localDateTime.toLocalDate();

1.1. 当前Time

通过LocalTime类获取当前时间:

LocalTime localTime = LocalTime.now();

指定时区获取:

LocalTime localTime = LocalTime.now(ZoneId.of("GMT+02:30"));
ZonedDateTime zbj = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));

也可以通过LocalDateTime类获取LocalTime:

LocalDateTime localDateTime = LocalDateTime.now();
LocalTime localTime = localDateTime.toLocalTime();

1.3. 当前Timestamp

java.time.Instant 从epoch时间获取时间戳,即从1970-01-01T00:00:00Z开始计算毫秒正数值:

Instant instant = Instant.now();
long timeStampMillis = instant.toEpochMilli();

当然也可以获取秒数:

Instant instant = Instant.now();
long timeStampSeconds = instant.getEpochSecond();

2. Elasticsearch Painless获取当前时间

在大多数Painless上下文中,当前datetime,now都不支持。主要有两个原因,第一是脚本对每个文档都运行一次,导致每次now的返回值不同。第二脚本通常运行在分布式环境,无法获得一致的now。一般采用的方法是用户定义参数,字符串类型或数值类型的日期,数值类型更好,无需进行格式解析。

举例:

long now = params['now'];
ZonedDateTime zdt =ZonedDateTime.ofInstant(doc['event_datetime'].value.toInstant(), ZoneId.of('Z'))
long millisDateTime = zdt.toInstant().toEpochMilli();
long elapsedTime = now - millisDateTime;

我们看到官网示例直接写ZonedDateTime zdt = doc[‘event_datetime’];,这样会报异常:即JodaCompatibleZonedDateTime类型不能转为ZonedDateTime 。

2.1 计算日期间隔示例

定义映射

PUT /messages
{
    "mappings": {
        "properties": {
            "priority": {
                "type": "integer"
            },
            "datetime": {
                "type": "date"
            },
            "message": {
                "type": "text"
            }
        }
    }
}

载入示例数据

POST /_bulk
{ "index" : { "_index" : "messages", "_id" : "1" } }
{ "priority": 1, "datetime": "2019-07-17T12:13:14Z", "message": "m1" }
{ "index" : { "_index" : "messages", "_id" : "2" } }
{ "priority": 1, "datetime": "2019-07-24T01:14:59Z", "message": "m2" }
{ "index" : { "_index" : "messages", "_id" : "3" } }
{ "priority": 2, "datetime": "1983-10-14T00:36:42Z", "message": "m3" }
{ "index" : { "_index" : "messages", "_id" : "4" } }
{ "priority": 3, "datetime": "1983-10-10T02:15:15Z", "message": "m4" }
{ "index" : { "_index" : "messages", "_id" : "5" } }
{ "priority": 3, "datetime": "1983-10-10T17:18:19Z", "message": "m5" }
{ "index" : { "_index" : "messages", "_id" : "6" } }
{ "priority": 1, "datetime": "2019-08-03T17:19:31Z", "message": "m6" }
{ "index" : { "_index" : "messages", "_id" : "7" } }
{ "priority": 3, "datetime": "2019-08-04T17:20:00Z", "message": "m7" }
{ "index" : { "_index" : "messages", "_id" : "8" } }
{ "priority": 2, "datetime": "2019-08-04T18:01:01Z", "message": "m8" }
{ "index" : { "_index" : "messages", "_id" : "9" } }
{ "priority": 3, "datetime": "1983-10-10T19:00:45Z", "message": "m9" }
{ "index" : { "_index" : "messages", "_id" : "10" } }
{ "priority": 2, "datetime": "2019-07-23T23:39:54Z", "message": "m10" }

统计星期

GET /messages/_search?pretty=true
{
  "size": 0, 
    "aggs": {
        "day-of-week-count": {
            "terms": {
                "script": "return doc[\"datetime\"].value.getDayOfWeekEnum();"
            }
        }
    }
}

返回结果如下:

...
  "aggregations" : {
    "day-of-week-count" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "MONDAY",
          "doc_count" : 3
        },
        {
          "key" : "SUNDAY",
          "doc_count" : 2
        },
        {
          "key" : "WEDNESDAY",
          "doc_count" : 2
        },
        {
          "key" : "FRIDAY",
          "doc_count" : 1
        },
        {
          "key" : "SATURDAY",
          "doc_count" : 1
        },
        {
          "key" : "TUESDAY",
          "doc_count" : 1
        }
      ]
    }
  }

统计上午和下午

GET /messages/_search?pretty=true
{
  "size": 0, 
    "aggs": {
        "am-pm-count": {
            "terms": {
                "script": "return doc[\"datetime\"].value.getHour() < 12 ? \"AM\" : \"PM\";"
            }
        }
    }
}

返回响应:

  "aggregations" : {
    "am-pm-count" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "PM",
          "doc_count" : 7
        },
        {
          "key" : "AM",
          "doc_count" : 3
        }
      ]
    }
  }

统计年

GET /messages/_search?pretty=true
{
  "size": 3, 
    "script_fields" : {
        "message_age" : {
            "script" : {
                "source": "ZonedDateTime now = ZonedDateTime.ofInstant(Instant.ofEpochMilli(params['now']), ZoneId.of('Z')); ZonedDateTime mdt=ZonedDateTime.ofInstant(doc['datetime'].value.toInstant(), ZoneId.of('Z'));return mdt.until(now, ChronoUnit.YEARS);",
                "params": {
                    "now": 1674005645830
                }
            }
        }
    }
}

可读形式脚本:

ZonedDateTime now = ZonedDateTime.ofInstant(Instant.ofEpochMilli(params['now']), ZoneId.of('Z')); 
ZonedDateTime mdt=ZonedDateTime.ofInstant(doc['datetime'].value.toInstant(), ZoneId.of('Z'));
return mdt.until(now, ChronoUnit.YEARS);

第一步获取ZonedDateTime类型now对象。然后转换文档的datetime字段为ZonedDateTime mdt对象,最后 mdt.until(now, ChronoUnit.YEARS)求两个时间间隔年份。

这里需要注意的是doc[‘datetime’].value类型为JodaCompatibleZonedDateTime,需要通过ZonedDateTime.ofInstant(doc['datetime'].value.toInstant(), ZoneId.of('Z'))转换为ZonedDateTime。

响应如下:

 "hits" : [
      {
        "_index" : "messages",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "fields" : {
          "message_age" : [
            3
          ]
        }
      },
      {
        "_index" : "messages",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "fields" : {
          "message_age" : [
            3
          ]
        }
      },
      {
        "_index" : "messages",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "fields" : {
          "message_age" : [
            39
          ]
        }
      }
    ]

3. 总结

本文介绍Painless如何获取当前时间,并计算时间间隔。

原创文章 408 获赞 792 访问量 154万+

猜你喜欢

转载自blog.csdn.net/neweastsun/article/details/105186817