Elastic - 집계 Aggregations
🙈

Elastic - 집계 Aggregations

Created
May 10, 2024 08:24 AM
Last edited time
Last updated May 20, 2024
Tags
ElasticSearch
Language
URL

Intro::

Elasticsearch가 다양한 목적의 데이터 시스템으로 사용되는 이유인 Aggregation 기능에 대해 알아봅시다.
 
// 테스트를 위한 my_stations 인덱스에 데이터 입력 PUT my_stations/_bulk {"index": {"_id": "1"}} {"date": "2019-06-01", "line": "1호선", "station": "종각", "passangers": 2314} {"index": {"_id": "2"}} {"date": "2019-06-01", "line": "2호선", "station": "강남", "passangers": 5412} {"index": {"_id": "3"}} {"date": "2019-07-10", "line": "2호선", "station": "강남", "passangers": 6221} {"index": {"_id": "4"}} {"date": "2019-07-15", "line": "2호선", "station": "강남", "passangers": 6478} {"index": {"_id": "5"}} {"date": "2019-08-07", "line": "2호선", "station": "강남", "passangers": 5821} {"index": {"_id": "6"}} {"date": "2019-08-18", "line": "2호선", "station": "강남", "passangers": 5724} {"index": {"_id": "7"}} {"date": "2019-09-02", "line": "2호선", "station": "신촌", "passangers": 3912} {"index": {"_id": "8"}} {"date": "2019-09-11", "line": "3호선", "station": "양재", "passangers": 4121} {"index": {"_id": "9"}} {"date": "2019-09-20", "line": "3호선", "station": "홍제", "passangers": 1021} {"index": {"_id": "10"}} {"date": "2019-10-01", "line": "3호선", "station": "불광", "passangers": 971}

메트릭 - Metrics Aggregations

min, max, sum, avg

// my_stations 인덱스의 passangers 필드 합 (sum) 을 가져오는 aggs GET my_stations/_search { "size": 0, "aggs": { "all_passangers": { "sum": { "field": "passangers" } } } }
💡
말 드대로 최소, 최대, 합, 평균을 구해준다. 이때 쿼리의 영향을 받는다는 점을 인지하고 있어야 합니다.
 

stats

💡
min, max, sum, avg 모두 가져와야 한다면 stats aggregation을 사용하면 됩니다.
// stats 로 passangers 필드의 min, max, sum, avg 값을 가져오는 aggs GET my_stations/_search { "size": 0, "aggs": { "passangers_stats": { "stats": { "field": "passangers" } } } }
 

cardinality

💡
필드의 값이 모두 몇 종류인지 분포값을 알려면 cardinality aggregation을 사용해서 구할 수 있습니다. Cardinality는 일반적으로 text 필드에서는 사용할 수 없으며 숫자 필드나 keyword, ip 필드 등에 사용이 가능합니다. 사용자 접속 로그에서 IP주소 필드를 가지고 실제로 접속한 사용자가 몇명인지 파악하는 등의 용도로 주로 사용됩니다.
// line 필드의 값이 몇 종류인지를 가져오는 aggs GET my_stations/_search { "size": 0, "aggs": { "uniq_lines ": { "cardinality": { "field": "line.keyword" } } } }
 

percentiles, percentile_ranks

💡
값들을 백분위 별로 볼때 percentiles aggregation이 사용 가능합니다. percentiles aggregation은 디폴트로 1%, 5%, 25%, 50%, 75%, 95%, 99% 구간에 위치 해 있는 값들을 표시 해 줍니다. 백분위 구간을 직접 지정하고 싶으면 percents 옵션을 이용해서 지정이 가능합니다. 다음은 20%, 60%, 80% 백분위의 값을 가져오는 percentiles aggregation 입니다.
// passangers 필드의 백분위를 가져오는 aggs GET my_stations/_search { "size": 0, "aggs": { "pass_percentiles": { "percentiles": { "field": "passangers" //"percents": [ 20, 60, 80 ] } } } } // 결과 { "took" : 1, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 10, "relation" : "eq" }, "max_score" : null, "hits" : [ ] }, "aggregations" : { "pass_percentiles" : { "values" : { "20.0" : 1667.5, "60.0" : 5568.0, "80.0" : 6021.0 } } } }
 
💡
percentile_ranks aggregation을 이용하면 반대로 값을 입력해서 그 값이 위치 해 있는 백분위를 볼 수 있습니다.
// passangers 필드의 값을 지정해서 백분위를 가져오는 aggs GET my_stations/_search { "size": 0, "aggs": { "pass_percentile_ranks": { "percentile_ranks": { "field": "passangers", "values": [ 1000, 3000, 6000 ] } } } } // 결과 { "took" : 1, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 10, "relation" : "eq" }, "max_score" : null, "hits" : [ ] }, "aggregations" : { "pass_percentile_ranks" : { "values" : { "1000.0" : 10.059568131049886, "3000.0" : 29.218263576617087, "6000.0" : 79.1549295774648 } } } }
 

버킷 - Bucket Aggregations

range

💡
range는 숫자 필드값으로 범위를 지정하고 각 범위에 해당하는 버킷을 만드는 aggregation입니다. field 옵션에 해당 필드의 이름을 지정하고 ranges 옵션에 배열로 from, to 값(이상, 미만)을 가진 오브젝트 값을 나열해서 범위를 지정합니다.
// range aggs 를 이용해서 passangers 필드의 값을 버킷으로 구분 GET my_stations/_search { "size": 0, "aggs": { "passangers_range": { "range": { "field": "passangers", "ranges": [ { "to": 1000 }, { "from": 1000, "to": 4000 }, { "from": 4000 } ] } } } } // 결과 { "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 } ] } } }
 

histogram

💡
range 와는 조금 다르게 interval 옵션을 주어 버킷을 구분합니다. 결과는 range와 유사합니다.
// histogram aggs 를 이용해서 passangers 필드의 값을 버킷으로 구분 GET my_stations/_search { "size": 0, "aggs": { "passangers_his": { "histogram": { "field": "passangers", "interval": 2000 } } } }
 

date_range, date_histogram

💡
시계열 데이터에서 날짜별로 값을 표기할 때 유용한 aggregation입니다.
// date_histogram 을 이용해서 date 값을 1개월 간격의 버킷으로 구분 GET my_stations/_search { "size": 0, "aggs": { "date_his": { "date_histogram": { "field": "date", "interval": "month" } } } }
 

terms

💡
keyword 필드의 문자열 별로 버킷을 나누어 집계가 가능합니다.
// terms 을 이용해서 station 값을 별로 버킷 생성 GET my_stations/_search { "size": 0, "aggs": { "stations": { "terms": { "field": "station.keyword" } } } } // 결 { "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 } ] } } }
 

하위 - sub-aggregations

💡
Bucket Aggregation 으로 만든 버킷들 내부에 다시 "aggs" : { } 를 선언해서 또다른 버킷을 만들거나 Metrics Aggregation 을 만들어 사용이 가능합니다.
// terms aggs 아래에 avg aggs 사용 GET my_stations/_search { "size": 0, "aggs": { "stations": { "terms": { "field": "station.keyword" }, "aggs": { "avg_psg_per_st": { "avg": { "field": "passangers" } } } } } }
// terms aggs 아래에 하위 terms aggs 사용 GET my_stations/_search { "size": 0, "aggs": { "lines": { "terms": { "field": "line.keyword" }, "aggs": { "stations_per_lines": { "terms": { "field": "station.keyword" } } } } } } // 결과 { "took" : 1, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 10, "relation" : "eq" }, "max_score" : null, "hits" : [ ] }, "aggregations" : { "lines" : { "doc_count_error_upper_bound" : 0, "sum_other_doc_count" : 0, "buckets" : [ { "key" : "2호선", "doc_count" : 6, "stations_per_lines" : { "doc_count_error_upper_bound" : 0, "sum_other_doc_count" : 0, "buckets" : [ { "key" : "강남", "doc_count" : 5 }, { "key" : "신촌", "doc_count" : 1 } ] } }, { "key" : "3호선", "doc_count" : 3, "stations_per_lines" : { "doc_count_error_upper_bound" : 0, "sum_other_doc_count" : 0, "buckets" : [ { "key" : "불광", "doc_count" : 1 }, { "key" : "양재", "doc_count" : 1 }, { "key" : "홍제", "doc_count" : 1 } ] } }, { "key" : "1호선", "doc_count" : 1, "stations_per_lines" : { "doc_count_error_upper_bound" : 0, "sum_other_doc_count" : 0, "buckets" : [ { "key" : "종각", "doc_count" : 1 } ] } } ] } } }
 

파이프라인 - Pipeline Aggregations

💡
Aggregation 중에는 다른 metrics aggregation의 결과를 새로운 입력으로 하는 pipeline aggregation이 있습니다. pipeline 에는 다른 버킷의 결과들을 다시 연산하는 min_bucket, max_bucket, avg_bucket, sum_bucket, stats_bucket, 이동 평균을 구하는 moving_avg, 미분값을 구하는 derivative, 값의 누적 합을 구하는 cumulative_sum 등이 있습니다. Pipeline aggregation 은 "buckets_path": "<버킷 이름>" 옵션을 이용해서 입력 값으로 사용할 버킷을 지정합니다.
// passangers 의 값을 입력으로 받는 cumulative_sum aggs 실행 GET my_stations/_search { "size": 0, "aggs": { "months": { "date_histogram": {// 한달별로 집계 "field": "date", "interval": "month" }, "aggs": { "sum_psg": {// 승객 합 "sum": { "field": "passangers" } }, "accum_sum_psg": { "cumulative_sum": {// 누적 "buckets_path": "sum_psg"// 승객합을 파이프 라인으로 사용 } } } } } }
 
💡
서로 다른 버킷에 있는 값들도 bucket_path에 > 기호를 이용해서 "부모>자녀" 형태로 지정이 가능합니다. 다음은 sum_bucket 을 이용해서 mon>sum_psg 버킷에 있는 passangers 필드값의 합을 구하는 예제입니다.
// 다른 부모의 자녀 버킷에 있는 필드를 입력으로 받는 pipeline aggs GET my_stations/_search { "size": 0, "aggs": { "mon": { "date_histogram": { "field": "date", "interval": "month" }, "aggs": { "sum_psg": { "sum": { "field": "passangers" } } } }, "bucket_sum_psg": { "sum_bucket": { "buckets_path": "mon>sum_psg" } } } } // 결과 { "took" : 4, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : { "value" : 10, "relation" : "eq" }, "max_score" : null, "hits" : [ ] }, "aggregations" : { "mon" : { "buckets" : [ { "key_as_string" : "2019-06-01T00:00:00.000Z", "key" : 1559347200000, "doc_count" : 2, "sum_psg" : { "value" : 7726.0 } }, { "key_as_string" : "2019-07-01T00:00:00.000Z", "key" : 1561939200000, "doc_count" : 2, "sum_psg" : { "value" : 12699.0 } }, { "key_as_string" : "2019-08-01T00:00:00.000Z", "key" : 1564617600000, "doc_count" : 2, "sum_psg" : { "value" : 11545.0 } }, { "key_as_string" : "2019-09-01T00:00:00.000Z", "key" : 1567296000000, "doc_count" : 3, "sum_psg" : { "value" : 9054.0 } }, { "key_as_string" : "2019-10-01T00:00:00.000Z", "key" : 1569888000000, "doc_count" : 1, "sum_psg" : { "value" : 971.0 } } ] }, "bucket_sum_psg" : { "value" : 41995.0 } } }
 
 

References::

Loading Comments...