1、线上问题![](http://image109.360doc.com/DownloadImg/2021/12/2414/236478934_1_20211224022204677_wm) 老大,请教个问题。你用painless操作过@timestamp字段吗?比如我获取了当前timestamp后,想要减去5分钟, 这个怎么写?ctx._source['@timestamp'] 是get当前的timestamp,后面operator要怎么写?2、问题拆解第一:晚上 11:14发出问题,说明问题很着急,极大可能是线上问题。第二:球友周大哥是资深架构师,可能问题会有一点弯或是有一些不常用的细节。一句话概括问题:对于给定的时间字段值,用 painless 脚本实现减去 5 分钟的处理。painless 脚本的处理,我想到的是:ingest 预处理管道的使用。当然之前我们也讲过还有直接处理脚本的方式,但是:结合管道预处理会更方便、更好理解。3、开搞,实战一把3.1 步骤 1:创建索引,并导入一批含日期类型的数据。DELETE logs PUT logs { "mappings": { "properties": { "name": { "type": "text" }, "start_date": { "type": "date" }, "close_date": { "type": "date" } } } }
PUT logs/_bulk?refresh {"index":{"_id":1}} {"name":"Person AA","start_date":"2015-05-06T02:49:40.894Z","close_date":"2015-11-01T18:10:30Z"} {"index":{"_id":2}} {"name":"Person CC","start_date":"2015-05-06T02:49:40.894Z","close_date":"2015-11-02T13:10:30Z"}
3.2 步骤 2:更新处理尝试。我的初始理解,获取时间,然后 - 5(代表 5 分钟的意思),不就搞定了吗。 试试看?simulate 仿真执行一下: POST /_ingest/pipeline/_simulate { "pipeline": { "description": "_description", "processors": [ { "script": { "description": "add time", "lang": "painless", "source": """ ctx.start_date = ctx.start_date - 5 """ } } ] }, "docs": [ { "_index": "index", "_id": 1, "_source": { "name": "Person AA", "start_date": "2015-05-06T02:49:40.894Z", "close_date": "2015-11-01T18:10:30Z" } } ] } 是的,一种方案就是继续:在类型转换上下功夫。搞定类型转换就搞定上面的脚本。我做了很多尝试,效果不大理想。看到这里的同学,可以自己尝试一下,欢迎留言交流。3.3 步骤 3:换个思路,从脚本部分再切入。换个思路思考,既然:官方文档拿出 1 篇文章的篇幅讲解 Datetime 时间类型的 painless 的应用,说明这里还是有“文章”的。
宏观上看:在 painless “无痛”脚本中,Datetime 时间类型共有如下三种类型:- 类型2:string 类型。举例:"2015-05-06T02:49:40.894Z"。
- 类型3:complex 类型。这种我们不常见,它是一种复杂对象类型。在 painless 中通常为:ZonedDateTime。
单看 ZonedDateTime 干巴巴的,不知道是啥意思?但是,跳转链接看到如下内容的时候,顿时感觉豁然开朗。![](http://image109.360doc.com/DownloadImg/2021/12/2414/236478934_5_20211224022205708_wm)
要强调的是如下一段话,切中选型要害! 在日期时间格式上述三种不同类型之间切换通常是实现脚本目标所必需的。 脚本中的典型应用是:将数字(numeric)或字符串(string)格式切换为 complex 日期格式,基于complex 日期格式做修改或比较,然后将其切换回数字或字符串日期格式进行存储或返回结果。
继续开搞吧: PUT /_ingest/pipeline/time_pipeline { "processors": [ { "script": { "description": "add time", "lang": "painless", "source": """ String datetime = ctx.start_date; ZonedDateTime zdt = ZonedDateTime.parse(datetime); zdt = zdt.minusMinutes(5); ctx.start_date = zdt; """ } } ] }
POST logs/_update_by_query?pipeline=time_pipeline { "query": { "match_all": {} } }
GET logs/_search
![](http://image109.360doc.com/DownloadImg/2021/12/2414/236478934_6_20211224022206366_wm)
4、核心实现的语法解读String datetime = ctx.start_date; ZonedDateTime zdt = ZonedDateTime.parse(datetime); zdt = zdt.minusMinutes(5); 有了 painless 脚本,后面借助:update_by_query 批量更新结合 painless 脚本就能方便的实现已有数据的更新操作。更多 Datetime painless 脚本的使用细节,推荐参考阅读文末的官方链接地址。5、小结第一:对于不是特别熟悉或者非常小众的知识点,找到突破口很关键。找到了突破口,就找到了解决问题的思路。第二:一个小的知识点,能引发很多知识点甚至知识链条。就拿本文举例:我自己之前肯定也遇到过日期时间的查询、聚合、更新处理操作,但是没有系统化的翻看过 painless 时间处理的文档。所以,当遇到新的问题的时候,依然是没有方法论,只是凭经验去猜、尝试,“猜、尝试”花的时间总体算下来比查看官方文档还要长。“前事不忘后事之师”,今天的实践和小结尤其方法论部分是未来学习、实战环节要改进的点。参考https://www./guide/en/elasticsearch/painless/master/painless-datetime.htmlhttps://www./guide/en/elasticsearch/painless/master/painless-api-reference-shared-java-time.html#painless-api-reference-shared-ZonedDateTime推荐更短时间更快习得更多干货!
已带领70位球友通过 Elastic 官方认证! 中国仅通过百余人
|