Elasticsearch:向日期直方图中的每个桶添加过滤范围

Elasticsearch: Adding a filter range to each bucket in a date histogram

在我的索引中,我有文档,其中每个文档都有时间戳(通过 '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"
               }
            }
         }
      }
   }
}

但是这个 returns 聚合的空值(0 个文档计数)即使父存储桶有多个文档的时间戳落入时间范围 - 请参见下面的示例:

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

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

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

非常感谢任何帮助!

有两种解决方法。

第一个解决方案是索引另一个名为 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

以上答案非常有效。但是对于 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