Elasticsearch Aggregations, 집계
Elasticsearch 는 검색뿐 아니라 여러가지 연산을 할 수 있는 Aggregation 기능이 있다. Kibana에서 차트, 그래프 등으로 시각화시킬 때 사용하는 기능이 aggregation 이다.
aggregations 에는 두 가지 종류가 있다.
- Metrics aggregation : 숫자 또는 날짜 필드의 값으로 계산함
- Bucket aggregation : 범위나 keyword 값으로 그룹화함
그리고 확장하여 사용할 수 있는 aggregations 도 있다.
- Sub-aggregation : bucket 하위 집계
- Pipeline-aggregation : metrics aggregation 결과로 다시 집계
이 포스팅에서는 Bucket-aggregation 에 대한 개념 설명 및 실습 예제를 다룬다.
** 아래 실습에서 사용된 도큐먼트 데이터 입력은 metrics aggregations 참조
Bucket Aggregations
bucket aggregation은 주어진 조건으로 분류된 버킷 (집합)들을 만들고 각 버킷에 포함되는 도큐먼트들을 모아 그룹으로 구분하는 것이다. 각 버킷 안에 metrics aggregation을 이용해서 다른 계산들도 가능하다. 주로 사용되는 bucket aggregation으로는 range, histogram, terms 등이 있다.
range
숫자 필드 값의 범위를 to, from으로 정해 버킷을 만든다.
GET stations/_search
{
"size": 0,
"aggs": {
"custom_field_passangers_range": {
"range": {
"field": "passangers",
"ranges": [
{
"from": 1000,
"to" : 3000
}
]
}
}
}
}
from 1000 이상부터 to : 3000미만까지 field명 passangers의 값이 1000~ 2999 사이인 것을 가져온다.
결과 :
{
"took" : 22,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 12,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"custom_field_passangers_range" : {
"buckets" : [
{
"key" : "1000.0-3000.0",
"from" : 1000.0,
"to" : 3000.0,
"doc_count" : 7
}
]
}
}
}
aggregations 안에 내가 설정한 필드명 "custom_field_passangers_range" 안에 buckets 이 생겼다. key는 해당 조건 범위를, doc_count는 해당 조건에 맞는 도큐먼트의 수를 나타낸다.
ranges 에 여러가지 range조건 설정하기
GET stations/_search
{
"size": 0,
"aggs": {
"custom_field_passangers_range": {
"range": {
"field": "passangers",
"ranges": [
{
"to": 1001
},
{
"from": 1500,
"to": 2500
},
{
"from": 3000
}
]
}
}
}
}
결과 :
"aggregations" : {
"custom_field_passangers_range" : {
"buckets" : [
{
"key" : "*-1001.0",
"to" : 1001.0,
"doc_count" : 3
},
{
"key" : "1500.0-2500.0",
"from" : 1500.0,
"to" : 2500.0,
"doc_count" : 4
},
{
"key" : "3000.0-*",
"from" : 3000.0,
"doc_count" : 5
}
]
}
}
buckets 안에 설정한 3가지가 각각 나왔다.
histogram
histogram은 위의 range와 비슷하게 숫자 field의 범위로 bucket을 생성하는데 다른점은 interval 옵션으로 간격을 설정해 버킷을 구분한다는 점이다.
GET stations/_search
{
"size": 0,
"aggs": {
"passangers_range_by_histogram": {
"histogram": {
"field": "passangers",
"interval": 1000
}
}
}
}
결과 :
"aggregations" : {
"passangers_range_by_histogram" : {
"buckets" : [
{
"key" : 1000.0,
"doc_count" : 3
},
{
"key" : 2000.0,
"doc_count" : 4
},
{
"key" : 3000.0,
"doc_count" : 5
}
]
}
}
입력한 도큐먼트들의 passanger 값이 1000, 2000, 3000 만 존재하고, 1000 미만의 값이 없어 key : 1000.0부터 시작해서 key 3000에서 끝난다.
첫 번째 key: 1000.0 의 범위는 1000~1999까지
두 번재 key: 2000.0 의 범위는 2000~2999까지
세 번째 key: 3000.0 의 범위는 3000~3999까지 이다.
만약 1000보다 미만인 수가 있었다면 결과의 첫번째 key값은 0.0이 되었을 것이다. 0~999까지
passanger수 : 300 짜리 데이터 하나 추가 입력 후 다시 위의 query를 날리면 결과 :
"aggregations" : {
"passangers_range_by_histogram" : {
"buckets" : [
{
"key" : 0.0,
"doc_count" : 1
},
{
"key" : 1000.0,
"doc_count" : 3
},
{
"key" : 2000.0,
"doc_count" : 4
},
{
"key" : 3000.0,
"doc_count" : 5
}
]
}
}
위에서 살펴본 range, histogram은 숫자 필드에만 사용할 수 있었는데 앞에 date_를 붙이게 되면 날짜에도 사용할 수 있다.
date_range
ranges > from, to에 적을 때 date의 형식들은 아래와 같이 다르게 사용 가능하다.
예시 1
GET stations/_search
{
"size": 0,
"aggs": {
"passangers_by_date_range": {
"date_range": {
"field": "date",
"ranges": [
{
"from": "2023-01-01T20:03:12.963",
"to": "3000-10-21T20:03:12.963"
}
]
}
}
}
}
or 예시 2
"ranges": [
{
"from": "2023-01-01",
"to": "3000-10-21"
}
]
or 예시 3
"ranges": [
{
"from": "now/y",
"to": "now+1y"
}
]
(위의 3번 예시는 범위 값은 다름!! 형식이 이렇게도 가능하다를 보여주기 위해)
위의 es date 형식은 -> 여기 포스팅 에 확인 가능
결과 :
"aggregations" : {
"passangers_by_date_range" : {
"buckets" : [
{
"key" : "2023-01-01T20:03:12.963Z-3000-10-21T20:03:12.963Z",
"from" : 1.672603392963E12,
"from_as_string" : "2023-01-01T20:03:12.963Z",
"to" : 3.2529067392963E13,
"to_as_string" : "3000-10-21T20:03:12.963Z",
"doc_count" : 8
}
]
}
}
date_histogram
date_histogram도 동일하게 interval을 사용해서 구분할 수 있다.
GET stations/_search
{
"size": 0,
"aggs": {
"passangers_by_date_histogram": {
"date_histogram": {
"field": "date",
"interval": "month"
}
}
}
}
사용할 수 있는 interval로는 day, hour, minute, quarter, second, week, month, year 등이 있다.
입력한 도큐먼트들의 date는 분단위가 아닌 "2022-11-11" 요 형식이어서 minute, second로 버킷을 생성하려고 하면 에러가 난다. day, month, year, quarter 그리고 hour 까진 가능했다.
month 결과 :
"aggregations" : {
"passangers_by_date_histogram" : {
"buckets" : [
{
"key_as_string" : "2022-12-01T00:00:00.000Z",
"key" : 1669852800000,
"doc_count" : 4
},
{
"key_as_string" : "2023-01-01T00:00:00.000Z",
"key" : 1672531200000,
"doc_count" : 1
},
{
"key_as_string" : "2023-02-01T00:00:00.000Z",
"key" : 1675209600000,
"doc_count" : 1
},
{
"key_as_string" : "2023-03-01T00:00:00.000Z",
"key" : 1677628800000,
"doc_count" : 0
},
{
"key_as_string" : "2023-04-01T00:00:00.000Z",
"key" : 1680307200000,
"doc_count" : 1
},
{
"key_as_string" : "2023-05-01T00:00:00.000Z",
"key" : 1682899200000,
"doc_count" : 0
},
{
"key_as_string" : "2023-06-01T00:00:00.000Z",
"key" : 1685577600000,
"doc_count" : 0
},
{
"key_as_string" : "2023-07-01T00:00:00.000Z",
"key" : 1688169600000,
"doc_count" : 0
},
{
"key_as_string" : "2023-08-01T00:00:00.000Z",
"key" : 1690848000000,
"doc_count" : 0
},
{
"key_as_string" : "2023-09-01T00:00:00.000Z",
"key" : 1693526400000,
"doc_count" : 1
},
{
"key_as_string" : "2023-10-01T00:00:00.000Z",
"key" : 1696118400000,
"doc_count" : 2
},
{
"key_as_string" : "2023-11-01T00:00:00.000Z",
"key" : 1698796800000,
"doc_count" : 1
},
{
"key_as_string" : "2023-12-01T00:00:00.000Z",
"key" : 1701388800000,
"doc_count" : 2
}
]
}
}
terms
terms하면 es search query에서도 사용하는 용어로 느낌상 정확하게 일치하는 keyword로 bucket을 만드는 것인가 ? 라고 유추해 볼 수 있다. terms aggregation은 keyword 필드의 문자열 별로 버킷을 나눈다. text 필드는 불가하고 keyword 필드만 가능하다.
맨 위에서 처음 도큐먼트를 입력할 때 index를 먼저 선언하지않고 바로 입력해서 각 데이터에 맞는 타입이 자동으로 index에 들어갔다. station 필드는 자동으로 text, keyword 둘 다 설정되어서 terms aggregation을 쓸 수 있다.
"station" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
station 별로 버킷 나누기 query
GET stations/_search
{
"size": 0,
"aggs": {
"passangers_by_terms": {
"terms": {
"field": "station.keyword"
}
}
}
}
결과 :
"aggregations" : {
"passangers_by_terms" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "가락시장",
"doc_count" : 5
},
{
"key" : "잠실",
"doc_count" : 5
},
{
"key" : "잠실새내",
"doc_count" : 3
}
]
}
}
station 에 입력한 잠실, 잠실새내, 가락시장 값들이 정리되어서 나왔다.
bucket 화된 결과 안에서 또 집계를 사용할 수 있는 aggregation으로 Sub-aggregation이 있다.
Reference : https://esbook.kimjmin.net/08-aggregations/
'Elasticsearch' 카테고리의 다른 글
[Elasitcsearch] Pipeline-Aggregation 개념 및 예제 (0) | 2022.11.10 |
---|---|
[Elasticsearch] bucket sub-aggregation 하위 집계 (0) | 2022.11.10 |
[Elasticsearch] Metrics Aggregations 집계 정리 (0) | 2022.11.10 |
[Elasticsearch] mapping field 수정 추가 삭제 (0) | 2022.11.10 |
[Elasticsearch] Analyzer, Tokenizer, Filter 개념 및 활용 방법 (0) | 2022.11.09 |