【问题标题】:Script-based sorting on Elasticsearch date field基于脚本的 Elasticsearch 日期字段排序
【发布时间】:2015-10-07 11:03:48
【问题描述】:

我刚开始使用 Elasticsearch,想对映射为 date 的字段使用基于脚本的排序,格式为 hour_minute。每个文档中可以有多个字段实例。

在引入表达式之前,作为第一步,我尝试了一个简单的排序(使用 Sense 插件):

POST myIndex/_search
{
   "query": {
      "match_all": {}
   },
   "sort": {
      "_script": {
         "script": "doc[\"someTime\"].value",
         "lang": "groovy",
         "type": "date",
         "order": "asc"
      }
   }
}

我收到此错误(片段):

SearchPhaseExecutionException[Failed to execute phase [query], all shards failed;
shardFailures {[tjWL-zV5QXmGjNlXzLvrzw][myIndex][0]:
SearchParseException[[myIndex][0]: 
query[ConstantScore(*:*)],from[-1],size[-1]: Parse Failure [Failed to parse source…

如果我使用"type": "number" 发布上述查询,则没有错误,尽管这当然不是按日期排序的。以下工作正常:

POST myIndex/_search
{
   "query": {
      "match_all": {}
   },
   "sort": {
      "someTime": {
         "order": "asc"
      }
   }
}

最终我想使用基于脚本的排序,因为我将尝试使用日期和时间条件进行查询、过滤或排序,例如查询具有今天日期的文档,然后按日期之后的最低时间对它们进行排序现在时间等。

任何建议将不胜感激。

【问题讨论】:

    标签: sorting date datetime elasticsearch


    【解决方案1】:

    使用脚本对文档进行排序并不是很高效,尤其是当您的文档库预计会随着时间的推移而增长时。因此,我将为此提供一个解决方案,然后提出另一种选择。

    为了使用脚本进行排序,您需要将日期转换为毫秒,以便您的排序可以在一个简单的数字上运行(排序类型只能是numberstring)。

    POST myIndex/_search
    {
       "query": {
          "match_all": {}
       },
       "sort": {
          "_script": {
             "script": "doc[\"someTime\"].date.getMillisOfDay()",
             "lang": "groovy",
             "type": "number",       <----- make sure this is number
             "order": "asc"
          }
       }
    }
    

    请注意,根据您想要的粒度,您还可以使用getSecondOfDay()getMinuteOfDay()。这样,如果您的查询和过滤器选择了正确日期的文档,您的排序脚本将根据当天的毫秒数(或秒数或分钟数)对文档进行排序。

    第二种解决方案意味着还将自那天开始以来的毫秒数(或秒或分钟)索引到另一个字段中,并简单地使用它进行排序,这样您就不需要脚本。最重要的是,您在搜索时需要的任何信息都应该在索引时知道,而不是实时计算。

    例如,如果您的someTime 字段包含日期2015-10-05T05:34:12.276Z,那么您将使用值20052276 索引millisOfDay 字段,即

    • 5 小时 * 3600000 毫秒
    • +34 分钟 * 60000 毫秒
    • +12 秒 * 1000 毫秒
    • +276 毫秒

    然后你可以使用排序

    POST myIndex/_search
    {
       "query": {
          "range": {
              "someTime": {
                  "gt": "now"
              }
          }
       },
       "sort": {
          "millisOfDay": {
             "order": "asc"
          }
       }
    }
    

    请注意,我添加了一个查询以仅选择 someTime 日期在现在之后的文档,因此您将在未来获得所有文档,但按升序排列 millisOfDay,这意味着您将获得距离now最近的日期。

    更新

    如果someTime 的格式为HH:mm,那么您也可以存储它的millisOfDay 值,例如如果someTime = 17:30 那么millisOfDay 将是 (17h * 3600000 ms) + (30 min * 60000 ms) = 63000000

    然后,您的查询需要使用script 过滤器进行一些修改,如下所示:

    {
      "query": {
        "filtered": {
          "filter": {
            "script": {
              "script": "doc.millisOfDay.value > new DateTime().millisOfDay"
            }
          }
        }
      },
      "sort": {
        "millisOfDay": {
          "order": "asc"
        }
      }
    }
    

    【讨论】:

    • 转换对我不起作用,可能是因为someTime 的格式是hour_minute(例如“17:30”)……不过我会继续朝这个方向努力,谢谢.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-19
    相关资源
    最近更新 更多