让文档匹配多桶日期直方图

Let document match multiple buckets of date histogram

我有一个索引,其映射类似于

{
    "id": {
        "type": "long"
    },
    "start": {
        "type": "date"
    },
    "end": {
        "type": "date"
    }
}

我想创建一个日期直方图,以便每个文档都属于间隔介于 "start" 和 "end" 之间的所有桶。

例如。如果对于一个文档 "start" = 12/01/2018,"end" = 04/25/2019,我的日期直方图间隔是几周,范围是 now-1y 到现在。我现在希望从 2018 年 1 月 1 日那一周开始到 2019 年 4 月 25 日那一周,将文档放入每个桶中。因此,只有这个文件的结果应该是 52 个桶,其中四月到十二月的桶有 doc_count 0,十二月到四月的桶有 doc_count 1.

据我所知,日期直方图仅让我可以选择根据一个字段将我的文档准确匹配到一个存储桶,"start" 或 "end"。

到目前为止我尝试过的:

  1. 动态生成一个包含 52 个过滤器的查询,检查文档是否属于此 "bucket"
  2. 尝试在每个查询中使用无痛脚本

两种解决方案都非常慢。我正在处理大约 20 万份文档,此类查询大约需要 10 秒。

编辑:这是一个动态生成的示例查询。可以看出,每周创建一个过滤器。这个查询大约需要 10 秒,这是 long

的方式
%{
  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 秒,规模与您的相似。

您可以 运行 同时进行两种聚合以节省更多时间。