Пусть документ соответствует нескольким сегментам гистограммы даты - PullRequest
1 голос
/ 25 апреля 2019

У меня есть индекс с отображением, похожим на

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

Я хочу создать гистограмму даты, чтобы каждый документ попадал во все сегменты, интервалы между которыми "начало" и "конец".

Например. если для одного документа "start" = 01.12.2017, "end" = 25/04/2019, мой интервал даты-гистограммы составляет недели, а диапазон составляет от-1 до настоящего момента. Теперь я хочу, чтобы документ попадал в каждое ведро, начиная с недели с 12/01/2018 и до недели с 25/04/2019. Таким образом, только с одним этим документом результат должен составить 52 сегмента, в которых интервалы с апреля по декабрь имеют значение doc_count 0, а сегменты с декабря по апрель имеют значение doc_count 1.

На мой взгляд, гистограмма даты дает мне возможность сопоставить мой документ точно с одним сегментом в зависимости от одного поля: «начало» или «конец».

Что я пробовал до сих пор:

  1. Динамически генерировать запрос с 52 фильтрами, который проверяет, попадает ли документ в это «ведро»
  2. Попробуйте использовать безболезненные сценарии в каждом запросе

Оба решения были чрезвычайно медленными. Я работаю с около 200 тыс. Документов, и на такие запросы уходит около 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
}

Надеюсь, этот вопрос понятен. Если нет, я объясню это более подробно.

1 Ответ

1 голос
/ 28 апреля 2019

Как насчет выполнения 2 запросов date_histogram и расчета разницы в неделю? Я предполагаю, что вам просто нужно общее количество из-за размера: 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 секунд в моем локальном масштабе по аналогии с вашим.

Вы можете запустить оба агрегата одновременно, чтобы сэкономить больше времени.

...