sorting - 基于脚本的 Elasticsearch 日期字段排序

标签 sorting date datetime elasticsearch

我刚刚开始使用 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"
      }
   }
}

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

如有任何建议,我们将不胜感激。

最佳答案

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

为了使用脚本进行排序,您需要将日期转换为毫秒,以便您的排序可以在一个简单的数字上运行(排序类型只能是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 那么您将索引 millisOfDay 值为 20052276 的字段,即

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

然后你可以使用排序

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

请注意,我添加了一个查询以仅选择 someTime 日期晚于现在的文档,因此您将获得 future 的所有文档,但按 millisOfDay< 升序排序,这意味着您将首先获得离现在最近的日期。

更新

如果 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"
    }
  }
}

关于sorting - 基于脚本的 Elasticsearch 日期字段排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32933085/

相关文章:

c# - 排序通用链表

excel - 在 VBA Excel 中,当我将一个单元格复制到另一个单元格时,如果它是未复制的日期,我该怎么办?

sql - 从 Oracle 日期中删除前导零

c# - 发布到 Web 服务器后将字符串转换为 DateTime 时出错

sorting - 我可以对 Base32/64 编码的 MD5 哈希值进行 alpha 排序吗?

C++ 对数组进行排序

mongodb - MongoDB 中新插入的文档肯定比旧文档具有 "bigger"_id 吗?

date - 如何在extjs字段中获取前一天的日期

javascript - 考虑到网络延迟,如何确定 HTTP 请求的准确发送时间?

java - 在 Spring 表单标签中显示日期 (java.sql.Date) 时出错