Spec-Zone.ru › Elasticsearch 8
›Elasticsearch Guide [8.17] ›Агрегирования ›Агрегирования по корзинам

Особенности агрегирования по диапазонам полей

Документы подсчитываются для каждой корзины, в которую они попадают

Поскольку диапазон представляет собой несколько значений, выполнение агрегирования по корзинам по полю диапазона может привести к тому, что один и тот же документ попадет в несколько корзин. Это может привести к неожиданному поведению, например, сумма подсчетов корзин может быть выше, чем количество сопоставленных документов. Рассмотрим, например, следующий индекс:

resp = client.indices.create(
    index="range_index",
    settings={
        "number_of_shards": 2
    },
    mappings={
        "properties": {
            "expected_attendees": {
                "type": "integer_range"
            },
            "time_frame": {
                "type": "date_range",
                "format": "yyyy-MM-dd||epoch_millis"
            }
        }
    },
)
print(resp)

resp1 = client.index(
    index="range_index",
    id="1",
    refresh=True,
    document={
        "expected_attendees": {
            "gte": 10,
            "lte": 20
        },
        "time_frame": {
            "gte": "2019-10-28",
            "lte": "2019-11-04"
        }
    },
)
print(resp1)
response = client.indices.create(
  index: 'range_index',
  body: {
    settings: {
      number_of_shards: 2
    },
    mappings: {
      properties: {
        expected_attendees: {
          type: 'integer_range'
        },
        time_frame: {
          type: 'date_range',
          format: 'yyyy-MM-dd||epoch_millis'
        }
      }
    }
  }
)
puts response

response = client.index(
  index: 'range_index',
  id: 1,
  refresh: true,
  body: {
    expected_attendees: {
      gte: 10,
      lte: 20
    },
    time_frame: {
      gte: '2019-10-28',
      lte: '2019-11-04'
    }
  }
)
puts response
const response = await client.indices.create({
  index: "range_index",
  settings: {
    number_of_shards: 2,
  },
  mappings: {
    properties: {
      expected_attendees: {
        type: "integer_range",
      },
      time_frame: {
        type: "date_range",
        format: "yyyy-MM-dd||epoch_millis",
      },
    },
  },
});
console.log(response);

const response1 = await client.index({
  index: "range_index",
  id: 1,
  refresh: "true",
  document: {
    expected_attendees: {
      gte: 10,
      lte: 20,
    },
    time_frame: {
      gte: "2019-10-28",
      lte: "2019-11-04",
    },
  },
});
console.log(response1);
PUT range_index
{
  "settings": {
    "number_of_shards": 2
  },
  "mappings": {
    "properties": {
      "expected_attendees": {
        "type": "integer_range"
      },
      "time_frame": {
        "type": "date_range",
        "format": "yyyy-MM-dd||epoch_millis"
      }
    }
  }
}

PUT range_index/_doc/1?refresh
{
  "expected_attendees" : {
    "gte" : 10,
    "lte" : 20
  },
  "time_frame" : {
    "gte" : "2019-10-28",
    "lte" : "2019-11-04"
  }
}

Диапазон шире интервала в следующем агрегировании, и поэтому документ попадет в несколько корзин.

resp = client.search(
    index="range_index",
    size="0",
    aggs={
        "range_histo": {
            "histogram": {
                "field": "expected_attendees",
                "interval": 5
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'range_index',
  size: 0,
  body: {
    aggregations: {
      range_histo: {
        histogram: {
          field: 'expected_attendees',
          interval: 5
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "range_index",
  size: 0,
  aggs: {
    range_histo: {
      histogram: {
        field: "expected_attendees",
        interval: 5,
      },
    },
  },
});
console.log(response);
POST /range_index/_search?size=0
{
  "aggs": {
    "range_histo": {
      "histogram": {
        "field": "expected_attendees",
        "interval": 5
      }
    }
  }
}

Поскольку интервал равен 5 (а смещение по умолчанию равно 0), мы ожидаем корзины 10, 15 и 20. Наш документ диапазона попадет во все три этих корзины.

{
  ...
  "aggregations" : {
    "range_histo" : {
      "buckets" : [
        {
          "key" : 10.0,
          "doc_count" : 1
        },
        {
          "key" : 15.0,
          "doc_count" : 1
        },
        {
          "key" : 20.0,
          "doc_count" : 1
        }
      ]
    }
  }
}

Документ не может частично находиться в корзине; например, вышеупомянутый документ не может считаться одной третью в каждой из трех упомянутых выше корзин. В этом примере, так как диапазон документа попал в несколько корзин, полное значение этого документа также будет учитываться во всех под-агрегированиях для каждой корзины.

Границы запроса не являются фильтрами агрегирования

Другое неожиданное поведение может возникнуть, когда запрос используется для фильтрации по агрегируемому полю. В этом случае документ может соответствовать запросу, но все равно иметь одну или обе конечные точки диапазона за пределами запроса. Рассмотрим следующую агрегацию по вышеупомянутому документу:

resp = client.search(
    index="range_index",
    size="0",
    query={
        "range": {
            "time_frame": {
                "gte": "2019-11-01",
                "format": "yyyy-MM-dd"
            }
        }
    },
    aggs={
        "november_data": {
            "date_histogram": {
                "field": "time_frame",
                "calendar_interval": "day",
                "format": "yyyy-MM-dd"
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'range_index',
  size: 0,
  body: {
    query: {
      range: {
        time_frame: {
          gte: '2019-11-01',
          format: 'yyyy-MM-dd'
        }
      }
    },
    aggregations: {
      november_data: {
        date_histogram: {
          field: 'time_frame',
          calendar_interval: 'day',
          format: 'yyyy-MM-dd'
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "range_index",
  size: 0,
  query: {
    range: {
      time_frame: {
        gte: "2019-11-01",
        format: "yyyy-MM-dd",
      },
    },
  },
  aggs: {
    november_data: {
      date_histogram: {
        field: "time_frame",
        calendar_interval: "day",
        format: "yyyy-MM-dd",
      },
    },
  },
});
console.log(response);
POST /range_index/_search?size=0
{
  "query": {
    "range": {
      "time_frame": {
        "gte": "2019-11-01",
        "format": "yyyy-MM-dd"
      }
    }
  },
  "aggs": {
    "november_data": {
      "date_histogram": {
        "field": "time_frame",
        "calendar_interval": "day",
        "format": "yyyy-MM-dd"
      }
    }
  }
}

Несмотря на то, что запрос рассматривает только дни ноября, агрегирование создает 8 корзин (4 в октябре, 4 в ноябре), потому что агрегирование вычисляется по диапазонам всех соответствующих документов.

{
  ...
  "aggregations" : {
    "november_data" : {
      "buckets" : [
              {
          "key_as_string" : "2019-10-28",
          "key" : 1572220800000,
          "doc_count" : 1
        },
        {
          "key_as_string" : "2019-10-29",
          "key" : 1572307200000,
          "doc_count" : 1
        },
        {
          "key_as_string" : "2019-10-30",
          "key" : 1572393600000,
          "doc_count" : 1
        },
        {
          "key_as_string" : "2019-10-31",
          "key" : 1572480000000,
          "doc_count" : 1
        },
        {
          "key_as_string" : "2019-11-01",
          "key" : 1572566400000,
          "doc_count" : 1
        },
        {
          "key_as_string" : "2019-11-02",
          "key" : 1572652800000,
          "doc_count" : 1
        },
        {
          "key_as_string" : "2019-11-03",
          "key" : 1572739200000,
          "doc_count" : 1
        },
        {
          "key_as_string" : "2019-11-04",
          "key" : 1572825600000,
          "doc_count" : 1
        }
      ]
    }
  }
}

В зависимости от использования, запрос CONTAINS может ограничить документы только теми, которые полностью попадают в запрошенный диапазон. В этом примере один документ не будет включен, и агрегирование будет пустым. Фильтрация корзин после агрегирования также является вариантом для тех случаев, когда документ должен быть учтен, но данные за пределами границ можно безопасно игнорировать.

© 2023-2025 Elasticsearch
As of September 2024, Elasticsearch is available under a choice of three licenses: the Server Side Public License (SSPL), the Elastic License, or the AGPLv3 (OSI approved).
Elasticsearch and the Elasticsearch logo are trademarks of Elasticsearch B.V., registered in the U.S. and in other countries.
https://www.elastic.co/guide/en/elasticsearch/reference/8.17/search-aggregations-bucket-range-field-note.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API