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

ElasticSearch: What is the best way to find distinct dates in a daterange that contains documents?

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

如果我想找到在我的索引中存在一段时间的所有不同 date_time(即,如果是订单,将是该期间注册的订单的所有日期,如果是是租来的汽车,就是所有租来的汽车的日子,等等)

假设我想查找 ES 中存在的 2018-10-01 和 2018-10-03 的不同日期时间(此示例的缩写)

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

{
  "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 万个文档。所以我试图找到最有效的方法来检索它。

ADDED-注意:实际上,这个查询用于验证我们所有索引中每天的数据是否存在,其中一些非常小,一些像这样巨大,并且可以时间出来,它们都有一个 dateTime 字段, 并且所有这些都带有对应于第 0 天毫秒和相同时区的时间戳,因此它们不会以毫秒或任何其他方式变化

在 datetype.keyword 上使用术语聚合的日期范围查询应该 return 唯一日期作为存储桶 ID

我想下面的查询就是您要查找的内容。我已经使用 date histogram and used bucket selector aggregation 实现了 aggregationrange part,因此只有那些具有 document count>0 的范围才会被 returned。

{  
   "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"
                  }
               }
            }
         }
      }
   }
}

所以上面的查询会 return 为您提供周列表以及该周的文档计数。如果那个星期没有任何文件,它不会显示那个星期。

如果您想分别查看每月或每天的详细信息,您可以在上述查询中使用 monthday 而不是 week

性能

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

下面介绍了如何将分析参数添加到查询中。

{
    "profile": true,
    "size": 0,
    "query": {}
}

添加此内容后,您将能够在回复中查看带有 profile 的单独 JSON 对象。作为响应,您将能够查看每个分片的查询性能的详细信息。特别检查 aggregation 部分,您可以进一步参考此 link 以了解有关时序细分的更多信息。

希望对您有所帮助!