对Elasticsearch日期字段进行基于脚本的排序

mic*_*bcn 4 sorting datetime date elasticsearch

我刚刚开始使用Elasticsearch,并且想在映射为dateformat 的字段上使用基于脚本的排序hour_minute。每个文档中可以有该字段的多个实例。

在介绍表达式之前,首先,我要尝试一种简单的排序(使用Sense插件):

POST myIndex/_search
{
   "query": {
      "match_all": {}
   },
   "sort": {
      "_script": {
         "script": "doc[\"someTime\"].value",
         "lang": "groovy",
         "type": "date",
         "order": "asc"
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

我收到此错误(片段):

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…
Run Code Online (Sandbox Code Playgroud)

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

POST myIndex/_search
{
   "query": {
      "match_all": {}
   },
   "sort": {
      "someTime": {
         "order": "asc"
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

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

任何建议将不胜感激。

Val*_*Val 5

使用脚本对文档进行排序实际上并不是很有效,特别是如果您的文档库预计会随着时间增长。因此,我将提供一种解决方案,然后提出另一种选择。

为了使用脚本进行排序,您需要将日期转换为毫秒,以便可以在一个简单的数字上运行排序(排序类型只能是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"
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

请注意,根据所需的粒度,您还可以使用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"
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

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

更新

如果someTime有格式的HH:mm,那么你也可以保存它的 millisOfDay价值,例如,如果someTime = 17:30millisOfDay会(17H * 3600000毫秒)+(30分钟* 60000毫秒)= 6300

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

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