elasticsearch - 让文档匹配多桶日期直方图
问题描述
我有一个索引,其映射类似于
{
"id": {
"type": "long"
},
"start": {
"type": "date"
},
"end": {
"type": "date"
}
}
我想创建一个日期直方图,以便每个文档都落入所有桶中,这些桶的间隔落在“开始”和“结束”之间。
例如。如果对于一个文档“开始”= 2018 年 1 月 12 日,“结束”= 2019 年 4 月 25 日,我的日期直方图间隔是周,范围是 now-1y 到现在。我现在希望从 2018 年 12 月 1 日到 2019 年 4 月 25 日这一周,该文档落入每个桶中。因此,仅使用这个文档,结果应该是 52 个存储桶,其中 4 月到 12 月的存储桶具有 doc_count 0,而 12 月到 4 月的存储桶具有 doc_count 1。
正如我所看到的,日期直方图仅让我可以选择根据一个字段(“开始”或“结束”)将我的文档与一个桶完全匹配。
到目前为止我已经尝试过:
- 动态生成带有 52 个过滤器的查询,用于检查文档是否落入此“桶”
- 尝试在每个查询中使用无痛脚本
两种解决方案都非常缓慢。我正在处理大约 200k 个文档,这样的查询大约需要 10 秒。
编辑:这是一个动态生成的示例查询。可以看出,每周创建一个过滤器。此查询大约需要 10 秒,这太长了
%{
aggs: %{
count_chart: %{
aggs: %{
last_seen_over_time: %{
filters: %{
filters: %{
"2018-09-24T00:00:00Z" => %{
bool: %{
must: [
%{range: %{start: %{lte: "2018-09-24T00:00:00Z"}}},
%{range: %{end: %{gte: "2018-09-17T00:00:00Z"}}}
]
}
},
"2018-12-24T00:00:00Z" => %{
bool: %{
must: [
%{range: %{start: %{lte: "2018-12-24T00:00:00Z"}}},
%{range: %{end: %{gte: "2018-12-17T00:00:00Z"}}}
]
}
},
"2019-04-01T00:00:00Z" => %{
bool: %{
must: [
%{range: %{start: %{lte: "2019-04-01T00:00:00Z"}}},
%{range: %{end: %{gte: "2019-03-25T00:00:00Z"}}}
]
}
}, ...
}
}
}
},
size: 0
}
和一个示例响应:
%{
"_shards" => %{"failed" => 0, "skipped" => 0, "successful" => 5, "total" => 5},
"aggregations" => %{
"count_chart" => %{
"doc_count" => 944542,
"last_seen_over_time" => %{
"buckets" => %{
"2018-09-24T00:00:00Z" => %{"doc_count" => 52212},
"2018-12-24T00:00:00Z" => %{"doc_count" => 138509},
"2019-04-01T00:00:00Z" => %{"doc_count" => 119634},
...
}
}
}
},
"hits" => %{"hits" => [], "max_score" => 0.0, "total" => 14161812},
"timed_out" => false,
"took" => 2505
}
我希望这个问题是可以理解的。如果不是,我将更详细地解释它。
解决方案
每周进行 2 次 date_histogram 查询并计算差异如何?我假设由于查询中的 size:0 ,您只需要总数。
let start = await client.search({
index: 'dates',
size: 0,
body: {
"aggs" : {
"start": {
"date_histogram": {
"field": "start",
"interval": "week"
},
}
}
}
});
let end = await client.search({
index: 'dates',
size: 0,
body: {
"aggs" : {
"end": {
"date_histogram": {
"field": "end",
"interval": "week"
},
}
}
}
});
let buckets = {};
let start_buckets = start.aggregations.start.buckets;
let end_buckets = end.aggregations.start.buckets;
let started = 0;
let ended = 0;
for (let i = 0; i < start_buckets.length; i++) {
started += start_buckets[i].doc_count;
buckets[start_buckets[i].key_as_string] = started - ended;
ended += end_buckets[i].doc_count;
}
在我的本地测试中,这个测试用时不到 2 秒,与你的测试规模相似。
您可以同时运行两个聚合以节省更多时间。
推荐阅读
- angularjs - 如何将输入值移动到小数点后 2 位?
- android - 无法为 org.jetbrains.kotlin.gradle.plugin.KaptExtension 类型的对象获取未知属性“增量”
- arm - 使用 PMU 计算 ARM 上的刻度
- spring-tools-4 - 在 STS 4.0 中忽略未知属性支持缺失
- python - 如何按变量对对象进行分组?
- java - 循环通过特定的小部件
- python - 这是按需设置属性的好习惯(如果在尝试获取属性时不存在)?
- reactjs - 你试图重定向到你当前在 React.js 中的同一条路线
- reactjs - Commonly API call for different components in ReactJS Fetch
- python - 读取大型二进制文件(超过 500 MB)的最快方法?