Elasticsearch:在日期直方图中为每个桶添加过滤器范围

时间:2016-09-29 09:44:47

标签: date elasticsearch aggregation

在我的索引中,我有文档,其中每个文档都有时间戳(通过'datetime'字段),格式为yyyy-MM-dd'T'HH:mm:ss

我有一个查询,它为文档中的给定字段提供每日(日期直方图)平均值的存储桶,这很有效,没有问题。

我正在尝试对此进行扩展以过滤每个存储桶,以便每日平均值仅考虑每天某一部分内的时间戳(例如,仅在早上或下午创建的文档等)。

我尝试过以下查询:

{
   "size": 0,
   "aggs": {
      "rating": {
         "date_histogram": {
            "field": "datetime",
            "interval": "1d",
            "time_zone": "Europe/London",
            "min_doc_count": 1
         },
         "aggs": {
            "afternoon": {
               "filter": {
                  "range": {
                     "datetime": {
                        "gte": "12:00:00",
                        "lte": "17:00:00",
                        "format": "HH:mm:ss"
                     }
                  }
               },
               "aggs": {
                  "service": {
                     "avg": {
                        "field": "qr2"
                     }
                  }
               }
            }
         }
      }
   },
   "query": {
      "constant_score": {
         "filter": {
            "range": {
               "datetime": {
                  "gte": "2016-08-28T23:00:00",
                  "lte": "2016-09-29T07:34:49"
               }
            }
         }
      }
   }
}

但是这会返回聚合的空值(0 doc count),即使父存储桶有多个文档的时间戳落入时间范围 - 请参阅下面的示例:

"aggregations": {
      "rating": {
         "buckets": [
            {
               "key_as_string": "1472428800000",
               "key": 1472425200000,
               "doc_count": 843,
               "afternoon": {
                  "doc_count": 0,
                  "service": {
                     "value": null
                  }
               }
            },
            {
               "key_as_string": "1472515200000",
               "key": 1472511600000,
               "doc_count": 748,
               "afternoon": {
                  "doc_count": 0,
                  "service": {
                     "value": null
                  }
               }
            },

我猜测只是指定日期时间的时间部分没有达到预期效果,它可能正在进行范围查询,日期部分默认为某个值,因此不匹配父存储桶中返回的文档的任何时间戳

我是否有一种简单的方法可以做到这一点,还是需要将时间分成单独的字段?

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:3)

有两种解决方法。

第一个解决方案是索引另一个名为hourOfTheDay的字段,以便您可以在其上运行简单的数字range过滤器。

           "filter": {
              "range": {
                 "hourOfTheDay": {
                    "gte": 12,
                    "lte": 17
                 }
              }
           },

第二个解决方案只涉及在script过滤器

中使用Groovy脚本
           "filter": {
              "script": {
                 "script": {
                    "inline": "def hod = doc.datetime.date.getHourOfDay(); return hod >= min && hod <= max",
                    "params": {
                       "min": 12,
                       "max": 17
                    }
                 }
              }
           },

对于第二个解决方案,请确保enable dynamic scripting

答案 1 :(得分:1)

上述答案完美无缺。但对于2.1.0之前的版本,这似乎有效

{
    "script": {
        "script": "def hod = doc.datetime.date.getHourOfDay(); return hod >= min && hod <= max",
        "params": {
            "min": 12,
            "max": 17
        }
    }
}

这是由于旧版本出现问题并已修复。 https://github.com/elastic/elasticsearch-net/issues/1931