ElasticSearch:在包含文档的日期范围内查找不同日期的最佳方法是什么?

时间:2018-10-19 20:50:44

标签: elasticsearch elasticsearch-aggregation elasticsearch-java-api

假设我的月度索引包含两个对过滤文档很重要的字段:client_id和date_time,以及其他几个我对该查询不感兴趣的数据字段。

如果我想查找索引中存在特定时间段的所有不同date_time(即,如果是订单,则为该期间内已注册订单的所有日期,如果是租车,则为整天都有租车等)

假设我要查找ES中2018-10-01和2018-10-03中不同的dateTime(此示例的简称)

我可以从添加布尔查询开始,以将该数据限制为日期范围:

{
  "size" : 0,
  "timeout" : 1500,
  "query" : {
    "bool" : {
      "must" : {
        "range" : {
          "date_time" : {
            "from" : "2018-10-01T00:00:00.000Z",
            "to" : "2018-10-03T23:59:59.999Z",
            "include_lower" : true,
            "include_upper" : true
          }
        }
      }
    }
  }
} 

尽管我要进行日期范围汇总并按代码上的文档计数进行过滤:

{
  "size" : 0,
  "timeout" : 1500,
  "query" : {
    "bool" : {
      "must" : {
        "range" : {
          "date_time" : {
            "from" : "2018-09-19T00:00:00.000Z",
            "to" : "2018-10-19T23:59:59.999Z",
            "include_lower" : true,
            "include_upper" : true
          }
        }
      }
    }
  },
  "aggregations" : {
    "date_range_agg" : {
      "date_range" : {
        "field" : "date_time",
        "ranges" : [ {
          "from" : "2018-09-30T00:00:00.000Z",
          "to" : "2018-10-01T00:00:00.000Z"
        }, {
          "from" : "2018-10-01T00:00:00.000Z",
          "to" : "2018-10-02T00:00:00.000Z"
        }, {
          "from" : "2018-10-02T00:00:00.000Z",
          "to" : "2018-10-03T00:00:00.000Z"
        }, {
          "from" : "2018-10-03T00:00:00.000Z",
          "to" : "2018-10-04T00:00:00.000Z"
        }]
      }
    }
  }
} 

我可以使用doc_count> 0从我的代码中过滤date_range_agg中的存储桶,但我仍然不喜欢它。

是否可以在date_range存储桶上应用过滤器,以仅带出文档计数超过0的存储桶?

是否有另一种方法可以像date_time字段的agg一样执行“ sql group by”,以获取日期范围内ES中所有不同的值?

简而言之,我只需要获取在给定时间内实际上具有文档的所有不同的date_time。

我们正在谈论的索引包含7GB的文档(每个索引约160万个文档),或3.8GB的索引和200万个文档。因此,我正在尝试找到最有效的方法来检索此内容。

添加-注意:实际上,此查询用于验证我们所有索引中每天数据的存在,其中一些确实很小,有些如此大,并且可能会超时他们有一个dateTime字段, 并且所有时间戳都与第0天的毫秒对应,并且具有相同的时区,因此它们不会以毫秒为单位变化。

2 个答案:

答案 0 :(得分:1)

在datetype.keyword上进行术语汇总的日期范围查询应返回唯一的日期作为存储区ID

答案 1 :(得分:1)

我认为以下查询是您要寻找的。我已经使用date histogram实现了range part的{​​{1}},并使用了bucket selector aggregation,以便只返回那些具有aggregation的范围。

document count>0

因此,以上查询将返回星期列表以及该周的文档数。并且,如果该周中没有任何文档,则不会显示该周。

如果您想分别查看每月或每天的详细信息,可以在上面的查询中使用{ "size":0, "timeout":"1500ms", "query":{ "bool":{ "must":{ "range":{ "date_time":{ "from":"2018-09-19T00:00:00.000Z", "to":"2018-10-19T23:59:59.999Z", "include_lower":true, "include_upper":true } } } } }, "aggregations":{ "date_range_agg":{ "date_histogram":{ "field":"date_time", "format":"MM-dd-yyyy", "interval":"week" }, "aggs":{ "count_bucket_selector":{ "bucket_selector":{ "buckets_path":{ "count":"_count" }, "script":{ "lang":"expression", "inline":"count>0" } } } } } } } month代替day

性能

建议您不要使用profiling功能,而不要指定week,以使您了解聚合查询需要多长时间才能完成。

下面是如何将配置参数添加到查询中。

timeout

添加时,您可以在响应中使用{ "profile": true, "size": 0, "query": {} } 查看单独的JSON对象。作为响应,您将能够查看每个分片的查询性能的详细信息。请特别检查profile部分,您可以进一步参考此link以了解有关时序细分的更多信息。

希望有帮助!