# 8.2 버킷 - Bucket Aggregations

&#x20; Bucket aggregation 은 주어진 조건으로 분류된 **버킷** 들을 만들고, 각 버킷에 소속되는 도큐먼트들을 모아 **그룹으로 구분**하는 것입니다. 각 버킷 별로 포함되는 도큐먼트의 개수는 **doc\_count** 값에 기본적으로 표시가 되며 각 버킷 안에 metrics aggregation 을 이용해서 다른 계산들도 가능합니다. 주로 사용되는 bucket aggregation 들은 **Range**, **Histogram**, **Terms** 등이 있습니다.

### range

&#x20; **range** 는 숫자 필드 값으로 범위를 지정하고 각 범위에 해당하는 버킷을 만드는 aggregation 입니다. **field** 옵션에 해당 필드의 이름을 지정하고 **ranges** 옵션에 배열로 **from**, **to** 값을 가진 오브젝트 값을 나열해서 범위를 지정합니다. 다음은 passangers 값이 각각 1000 미만, 1000\~4000 사이, 4000 이상 인 버킷들을 생성하는 예제입니다.

{% tabs %}
{% tab title="request" %}
{% code title="range aggs 를 이용해서 passangers 필드의 값을 버킷으로 구분" %}

```javascript
GET my_stations/_search
{
  "size": 0,
  "aggs": {
    "passangers_range": {
      "range": {
        "field": "passangers",
        "ranges": [
          {
            "to": 1000
          },
          {
            "from": 1000,
            "to": 4000
          },
          {
            "from": 4000
          }
        ]
      }
    }
  }
}
```

{% endcode %}
{% endtab %}

{% tab title="response" %}
{% code title="range aggs 를 이용해서 passangers 필드의 값을 버킷으로 구분한 결과" %}

```javascript
{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 10,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "passangers_range" : {
      "buckets" : [
        {
          "key" : "*-1000.0",
          "to" : 1000.0,
          "doc_count" : 1
        },
        {
          "key" : "1000.0-4000.0",
          "from" : 1000.0,
          "to" : 4000.0,
          "doc_count" : 3
        },
        {
          "key" : "4000.0-*",
          "from" : 4000.0,
          "doc_count" : 6
        }
      ]
    }
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

&#x20; 각각의 버킷을 구분하는 key 값은 `"from-to"` 형태로 생성됩니다. 위 쿼리 결과에서 각각의 `"*-1000.0"`, `"1000.0-4000.0"`, `"key" : "4000.0-*"` 버킷에 속한 도큐먼트의 개수가 **1**, **3**, **6**개 인 것을 확인할 수 있습니다.

{% hint style="info" %}
aggs 에 설정한 **from** 은 **이상** 즉 버킷에 포함이고 **to** 는 **미만** 으로 버킷에 포함하지 않습니다. 예를 들어 필드 값이 **200** 인 도큐먼트는 `"key" : "100-200"` 버킷에는 포함되지 않고 `"key" : "200-300"` 버킷에는 포함됩니다.
{% endhint %}

### histogram

&#x20; histogram 도 range 와 마찬가지로 숫자 필드의 범위를 나누는 aggs 입니다. 앞에서 본 range 는 from 과 to 를 이용해서 각 버킷의 범위를 지정했습니다. histogram 은 from, to 대신 **interval** 옵션을 이용해서 주어진 간격 크기대로 버킷을 구분합니다. 다음은 passangers 필드에 간격이 2000인 버킷들을 생성하는 예제입니다.

{% tabs %}
{% tab title="request" %}
{% code title="histogram aggs 를 이용해서 passangers 필드의 값을 버킷으로 구분" %}

```javascript
GET my_stations/_search
{
  "size": 0,
  "aggs": {
    "passangers_his": {
      "histogram": {
        "field": "passangers",
        "interval": 2000
      }
    }
  }
}
```

{% endcode %}
{% endtab %}

{% tab title="response" %}
{% code title="histogram aggs 를 이용해서 passangers 필드의 값을 버킷으로 구분한 결과" %}

```javascript
{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 10,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "passangers_his" : {
      "buckets" : [
        {
          "key" : 0.0,
          "doc_count" : 2
        },
        {
          "key" : 2000.0,
          "doc_count" : 2
        },
        {
          "key" : 4000.0,
          "doc_count" : 4
        },
        {
          "key" : 6000.0,
          "doc_count" : 2
        }
      ]
    }
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

&#x20; 각각의 버킷을 구분하는 key 에는 값의 최소값이 표시됩니다. 위 예제에서 `0`, `2000`, `4000`, `6000` 인 버킷들이 생성되었고 각 버킷들에 포함되는 도큐먼트 개수가 표시된 것을 볼 수 있습니다. key 값은 range 와 마찬가지로 key 로 지정된 값이 버킷에 이상(포함) / 미만(포함하지 않음) 으로 지정됩니다.

### date\_range, date\_histogram

&#x20; **range** 와 **histogram** aggs 처럼 숫자 외에도 날짜 필드를 이용해서 범위별로 버킷의 생성이 가능합니다. 이 때 사용되는 **date\_range**, **date\_histogram** aggs 들은 특히 시계열 데이터에서 날짜별로 값을 표시할 때 매우 유용합니다. **date\_range** 는 **ranges** 옵션에 `{"from": "2019-06-01", "to": "2016-07-01"}` 와 같이 입력하며 **date\_histogram** 은 **interval** 옵션에 `day`, `month`, `week` 와 같은 값들을 이용해서 날짜 간격을 지정할 수 있습니다. 다음은 **date\_histogram** 으로 **date** 필드를 **1개월** 간격으로 구분하는 예제입니다.

{% tabs %}
{% tab title="request" %}
{% code title="date\_histogram 을 이용해서 date 값을 1개월 간격의 버킷으로 구분" %}

```javascript
GET my_stations/_search
{
  "size": 0,
  "aggs": {
    "date_his": {
      "date_histogram": {
        "field": "date",
        "interval": "month"
      }
    }
  }
}
```

{% endcode %}
{% endtab %}

{% tab title="response" %}
{% code title="date\_histogram 을 이용해서 date 값을 1개월 간격의 버킷으로 구분한 결과" %}

```javascript
{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 10,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "date_his" : {
      "buckets" : [
        {
          "key_as_string" : "2019-06-01T00:00:00.000Z",
          "key" : 1559347200000,
          "doc_count" : 2
        },
        {
          "key_as_string" : "2019-07-01T00:00:00.000Z",
          "key" : 1561939200000,
          "doc_count" : 2
        },
        {
          "key_as_string" : "2019-08-01T00:00:00.000Z",
          "key" : 1564617600000,
          "doc_count" : 2
        },
        {
          "key_as_string" : "2019-09-01T00:00:00.000Z",
          "key" : 1567296000000,
          "doc_count" : 3
        },
        {
          "key_as_string" : "2019-10-01T00:00:00.000Z",
          "key" : 1569888000000,
          "doc_count" : 1
        }
      ]
    }
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

&#x20; date\_histogram의 결과에서는 버킷별로 key 에 시작 날짜가 **epoch\_millis** 값으로 표시됩니다. 그리고 **key\_as\_string** 에 **ISO8601** 형태로도 함께 표시됩니다.

{% hint style="warning" %}
7.2 버전 부터는 interval 옵션이 사용 종료 권장(depricated) 되고 대신 **fixed\_interval** 과 **calendar\_interval** 으로 나누어 지게 되었습니다. year, quarter, month, week, 같은 달력 기준의 값은 `"calendar_interval" : "month"` 로 입력을 하고, 30일 처럼 정확히 구분되는 날짜들은 `"fixed_interval" : "30d"` 로 지정을 해야 합니다.
{% endhint %}

### terms

&#x20; 앞에서 살펴 본 **(date\_)range**, **histogram** 은 모두 숫자, 날짜를 가지고 구간을 나누는 aggregation 이었습니다. **terms** aggregation 은 **keyword** 필드의 문자열 별로 버킷을 나누어 집계가 가능합니다. keyword 필드 값으로만 사용이 가능하며 분석된 text 필드는 일반적으로는 사용이 불가능합니다. 다음은 my\_stations 인덱스에서 **station.keyword** 필드를 기준으로 버킷들을 만드는 예제입니다.

{% tabs %}
{% tab title="request" %}
{% code title="terms 을 이용해서 station 값을 별로 버킷 생성" %}

```javascript
GET my_stations/_search
{
  "size": 0,
  "aggs": {
    "stations": {
      "terms": {
        "field": "station.keyword"
      }
    }
  }
}
```

{% endcode %}
{% endtab %}

{% tab title="response" %}
{% code title="terms 을 이용해서 station 값을 별로 버킷 생성한 결과" %}

```javascript
{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 10,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "stations" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "강남",
          "doc_count" : 5
        },
        {
          "key" : "불광",
          "doc_count" : 1
        },
        {
          "key" : "신촌",
          "doc_count" : 1
        },
        {
          "key" : "양재",
          "doc_count" : 1
        },
        {
          "key" : "종각",
          "doc_count" : 1
        },
        {
          "key" : "홍제",
          "doc_count" : 1
        }
      ]
    }
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

&#x20; **terms** aggregation 에는 **field** 외에도 가져올 버킷의 개수를 지정하는 **size** 옵션이 있으며 디폴트 값은 **10** 입니다. 인덱스의 특정 keyword 필드에 있는 모든 값들을 종류별로 버킷을 만들면 가져와야 할 결과가 매우 많기 때문에 먼저 도큐먼트 개수 또는 주어진 metrics 연산 결과가 가장 많은 버킷 들을 샤드별로 계산해서 상위 몇개의 버킷들만 coordinate 노드로 가져오고, 그것들을 취합해서 결과를 나타냅니다. 이 과정은 검색의 query 그리고 fetch 과정과 유사합니다.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://esbook.kimjmin.net/08-aggregations/8.2-bucket-aggregations.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
