【问题标题】:Format date in elasticsearch query (during retrieval)在弹性搜索查询中格式化日期(在检索期间)
【发布时间】:2015-01-13 20:50:09
【问题描述】:

我有一个弹性搜索索引,其中包含一个字段“aDate”(以及许多其他字段),具有以下映射

"aDate" : {
        "type" : "date",
        "format" : "date_optional_time"
}

当我查询一个文档时,我得到一个类似的结果

"aDate" : 1421179734000,

我知道这是纪元,内部 java/elasticsearch 日期格式,但我希望得到如下结果:

"aDate" : "2015-01-13T20:08:54",

我在玩脚本

{  
 "query":{  
   "match_all":{  

   }
 },
 "script_fields":{  
   "aDate":{  
      "script":"if (!_source.aDate?.equals('null')) new java.text.SimpleDateFormat('yyyy-MM-dd\\'T\\'HH:mm:ss').format(new java.util.Date(_source.aDate));"
   }
 }
}

但它给出了奇怪的结果(脚本基本上可以工作,但 aDate 是唯一返回的字段并且缺少 _source)。这看起来像

"hits": [{
        "_index": "idx1",
        "_type": "type2",
        "_id": "8770",
        "_score": 1.0,
        "fields": {
            "aDate": ["2015-01-12T17:15:47"]
        }
    },

如果可能的话,我更喜欢没有脚本的解决方案。

【问题讨论】:

    标签: java groovy elasticsearch


    【解决方案1】:

    当您在 Elasticsearch 中运行查询时,您可以请求它返回原始数据,例如指定 fields

    curl -XGET http://localhost:9200/myindex/date-test/_search?pretty -d '
    {
     "fields" : "aDate",
     "query":{  
       "match_all":{  
    
       }
     }
    }'
    

    将以您最初存储的格式为您提供日期:

    {
      "_index" : "myindex",
      "_type" : "date-test",
      "_id" : "AUrlWNTAk1DYhbTcL2xO",
      "_score" : 1.0,
      "fields" : {
        "aDate" : [ "2015-01-13T20:08:56" ]
      }
    }, {
      "_index" : "myindex",
      "_type" : "date-test",
      "_id" : "AUrlQnFgk1DYhbTcL2xM",
      "_score" : 1.0,
      "fields" : {
        "aDate" : [ 1421179734000 ]
      }
    

    除非您使用脚本,否则无法更改日期格式。

    curl -XGET http://localhost:9200/myindex/date-test/_search?pretty -d '
    {  
     "query":{  
       "match_all":{ }
     },
     "script_fields":{  
       "aDate":{  
          "script":"use( groovy.time.TimeCategory ) { new Date( doc[\"aDate\"].value )  }"
       }
     }
    }'
    

    将返回:

    {
      "_index" : "myindex",
      "_type" : "date-test",
      "_id" : "AUrlWNTAk1DYhbTcL2xO",
      "_score" : 1.0,
      "fields" : {
        "aDate" : [ "2015-01-13T20:08:56.000Z" ]
      }
    }, {
      "_index" : "myindex",
      "_type" : "date-test",
      "_id" : "AUrlQnFgk1DYhbTcL2xM",
      "_score" : 1.0,
      "fields" : {
        "aDate" : [ "2015-01-13T20:08:54.000Z" ]
      }
    }
    

    要应用格式,请按如下方式附加:

    "script":"use( groovy.time.TimeCategory ){ new Date( doc[\"aDate\"].value ).format(\"yyyy-MM-dd\")   }"
    

    将返回"aDate" : [ "2015-01-13" ]

    要显示T,您需要使用引号但将它们替换为等效的Unicode:

    "script":"use( groovy.time.TimeCategory ){ new Date( doc[\"aDate\"].value ).format(\"yyyy-MM-dd\u0027T\u0027HH:mm:ss\") }"
    

    返回"aDate" : [ "2015-01-13T20:08:54" ]


    返回 script_fields 和 source

    在查询中使用 _source 来指定要返回的字段:

    curl -XGET http://localhost:9200/myindex/date-test/_search?pretty -d '
     {  "_source" : "name",
      "query":{
        "match_all":{ }
      },
      "script_fields":{
        "aDate":{
           "script":"use( groovy.time.TimeCategory ) { new Date( doc[\"aDate\"].value )  }"
        }
      }
     }'
    

    将返回我的name 字段:

    "_source":{"name":"Terry"},
      "fields" : {
        "aDate" : [ "2015-01-13T20:08:56.000Z" ]
      }
    

    使用星号将返回所有字段,例如:"_source" : "*",

    "_source":{"name":"Terry","aDate":1421179736000},
      "fields" : {
        "aDate" : [ "2015-01-13T20:08:56.000Z" ]
      }
    

    【讨论】:

    • 谢谢。由于原始日期格式是纪元,我必须使用脚本。我怎样才能得到包含 _source 的结果? (请参阅问题中的粗体标记文本)
    • 我已经更新了答案,包括使用 _source 带回其他字段。
    • 太棒了,工作。如果我使用 "_source" : "*" 我得到所有源字段,这就是我想要的
    • use(groovy.time.TimeCategory) 似乎不适用于 ES 2.2。任何想法,(lang 是 groovy)?没有这样的属性:类的常规:05c0662f39d36342a9a0a646db3aa789da16c191
    • 这不再适用于 7.4....
    【解决方案2】:

    正如LabOctoCat 提到的,Olly Cruickshank 答案不再适用于弹性 2.2。我将脚本更改为:

    "script":"new Date(doc['time'].value)"
    

    您可以根据this格式化日期。

    【讨论】:

    • 不适用于 6.x。从5.0.0开始,es使用Painless作为脚本语言
    【解决方案3】:

    从5.0.0开始,es使用Painless作为脚本语言:link

    试试这个(在 6.3.2 中工作)

    "script":"doc['aDate'].value.toString('yyyy-MM-dd HH:mm:ss')"
    

    【讨论】:

    • 谢谢!我一直在到处寻找这个。
    【解决方案4】:

    编写脚本仅在提取行时计算答案。这很昂贵,并且使您无法在 Elasticsearch 中使用任何与日期相关的搜索功能。

    您应该在插入之前创建一个弹性搜索“日期”字段。看起来像 java Date() 对象will do

    【讨论】:

      【解决方案5】:

      感谢@Archon 的建议。我以您的回答为指导,从 Elasticsearch 中的日期时间字段中删除了时间元素

      {
          "aggs": {
              "grp_by_date": {
                  "terms": {
                      "size": 200,
                      "script": "doc['TransactionReconciliationsCreated'].value.toString('yyyy-MM-dd')"
                  }
              }
          }
      }
      

      【讨论】:

        【解决方案6】:

        如果你使用 Elasticsearch 7,并且想在指定的时区显示日期时间,你可以这样请求

        "query": {
            "bool": {
              "filter": [
                {
                  "term": {
                    "client": {
                      "value": "iOS",
                      "boost": 1
                    }
                  }
                }
              ],
              "adjust_pure_negative": true,
              "boost": 1
            }
          },
          "script_fields": {
            "time": {
              "script": "ZonedDateTime input = doc['time'].value; input = input.withZoneSameInstant(ZoneId.of('Asia/Shanghai')); String output = input.format(DateTimeFormatter.ISO_ZONED_DATE_TIME); return output"
            }
          },
          "_source": true,
        

        返回

        {
        ...
                "_source" : {
                  ...
                  "time" : 1632903354213
        ...
                },
                "fields" : {
                  "time" : [
                    "2021-09-29T16:15:54.213+08:00[Asia/Shanghai]"
                  ]
                }
              },
        ...
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-10-24
          • 2023-03-03
          • 2012-08-01
          相关资源
          最近更新 更多