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