5 분 소요

[ELK Stack]Elasticsearch 집계 -메트릭/버킷/조합/파이프라인 집계

1. 집계의 요청 - 응답 형태

  • Elasticsearch에서 집계는 검색 요청과 함께 _search API를 통해 요청함
  • 쿼리 요청 시 aggs 또는 aggregations 키워드를 사용함
  • 기본 구조:
GET index/_search
{
  "size": 0,
  "aggs": {
    "집계_이름": {
      "집계_타입": {
        "field": "필드명"
      }
    }
  }
}
  • size: 0을 통해 검색 결과는 제외하고 집계 결과만 확인 가능 (성능 최적화)

집계는 크게 두 가지로 나뉨:

유형 설명 예시
메트릭 집계 (Metric Aggregation) 필드값 기반으로 통계값 계산 평균, 합계, 최대/최소값, 중간값, 유니크 개수 등
버킷 집계 (Bucket Aggregation) 특정 조건에 따라 도큐먼트를 그룹핑 요일별, 범위별, 날짜별, 필터 조건 등

2. 메트릭 집계

자주 사용하는 메트릭 집계 종류

집계 타입 설명
avg 필드의 평균값
min 필드의 최솟값
max 필드의 최댓값
sum 필드의 합계
percentiles 1/4, 중간값(50), 상위 백분위 등
stats 평균/최소/최대/합계 등 통합 제공
cardinality 유니크 값 개수 (DISTINCT)
geo_centroid 좌표 필드 평균 중심점 계산

2.1 평균값 / 중간값 구하기

GET kibana_sample_data_ecommerce/_search
{
  "size": 0,
  "aggs": {
    "stats_aggs": {
      "avg": {
        "field": "products.base_price"
      }
    }
  }
}
  • 평균 집계는 정수/실수형 필드에만 적용 가능
  • size: 0 옵션으로 집계만 추출하여 리소스를 절감할 수 있음
GET kibana_sample_data_ecommerce/_search
{
  "size": 0,
  "aggs": {
    "stats_aggs": {
      "percentiles": {
        "field": "products.base_price",
        "percents": [25, 50]
      }
    }
  }
}
  • percentiles: 중간값(50%) 및 1사분위수(25%) 등의 위치 파악 가능
  • 실무에서는 가격 중앙값 등 데이터 분포 확인에 유용함

2.2 필드의 유니크한 값 개수 확인 (카디널리티)

GET kibana_sample_data_ecommerce/_search
{
  "size": 0,
  "aggs": {
    "cardi_aggs": {
      "cardinality": {
        "field" : "day_of_week",
        "precision_threshold": 100
      }
    }
  }
}
  • cardinality는 SQL의 COUNT(DISTINCT)처럼 동작함
  • precision_threshold: 정확도 조절 값으로 높을수록 정확하지만 리소스 사용량 증가
GET kibana_sample_data_ecommerce/_search
{
  "size": 0,
  "aggs": {
    "cardi_aggs": {
      "cardinality": {
        "field" : "day_of_week",
        "precision_threshold": 5
      }
    }
  }
}
  • 위 쿼리에서는 실제 7개의 요일이 존재하지만, 낮은 threshold로 인해 결과값이 8로 나올 수 있음;;
  • 그래서 이 파라미터는 실제결과보다 크게 잡아야한다는게 정설

2.3 검색 결과 내에서의 집계

GET kibana_sample_data_ecommerce/_search
{
  "size": 0,
  "query": {
    "term": {
      "day_of_week": {
        "value": "Monday"
      }
    }
  },
  "aggs": {
    "query_aggs": {
      "sum": {
        "field": "products.base_price"
      }
    }
  }
}
  • 집계하기전에 쿼리를 통해 도큐먼트 범위를 제한하고 용어수준 쿼리인 용어쿼리를 이용해 월요일도큐먼트값만 골라내서 이걸로 집계함
  • 쿼리를 먼저 실행한 뒤 해당 결과에만 집계를 적용하는 방식
  • 필터링된 문서만 대상으로 합계나 평균 계산이 가능함

3. 버킷 집계

자주 사용하는 버킷 집계 종류

집계 타입 설명
histogram 숫자형 필드 기준 간격 나누기
date_histogram 날짜 필드 기준 간격 나누기
range 사용자 정의 범위 버킷 구간 설정
date_range 날짜 범위 기반 그룹핑
terms 필드값으로 그룹핑 (예: 요일별)
significant_terms 통계적으로 특이한 용어 그룹화
filters 복수 필터 조건 기반 그룹화

3.1 히스토그램 집계

GET kibana_sample_data_ecommerce/_search
{
  "size": 0,
  "aggs": {
    "histogram_aggs": {
      "histogram": {
        "field": "products.base_price",
        "interval": 100
      }
    }
  }
}
  • 숫자형 필드를 일정 간격 단위로 나눠 그룹핑
  • interval: 각 버킷의 간격
  • 히스토그램과 비슷하게 날짜 히스토그램집계도 있음 (날짜/시간필드사용하면서 간격이 숫자가 아닌 날짜/필드)

3.2 범위 집계

  • 히스토그램은 각 버킷의 단위를 동일하게 지정할 수밖에 없는게 단점인데, 범위집계는 특정구간에 데이터가 몰려있거나, 데이터 편차가 큰 경우도 비효율적
GET kibana_sample_data_ecommerce/_search
{
  "size": 0,
  "aggs": {
    "histogram_aggs": {
      "range": {
        "field": "products.base_price",
        "ranges": [
          {"from":0,"to":50},
          {"from":50,"to":100},
          {"from":100,"to":200},
          {"from":200,"to":1000}
        ]
      }
    }
  }
}
  • 범위에 맞게 버킷을 유연하게 나누는 방식
  • 데이터가 비선형적으로 분포되어 있을 경우 적합함

3.3 용어 집계 (Terms Aggregation)

GET kibana_sample_data_ecommerce/_search
{
  "size": 0,
  "aggs": {
    "term_aggs": {
      "terms": {
        "field": "day_of_week",
        "size": 6
      }
    }
  }
}
  • 범주형 필드(문자열) 기준으로 집계
  • size 설정을 잘못하면 일부 값이 누락되며, sum_other_doc_count로 묶임

용어집계가 정확하지 않은 이유

  • 용어집계가 부정확도를 표시하는 이유는 분산시스템의 집계 과정에서 발생하는 잠재적인 오류 가능성 때문임

  • 분산시스템은 데이터를 여러 노드에서 분산하고 취합하는 과정에서 오류 발생 가능성

  • 엘라스틱서치는 샤드에 도큐먼트를 저장하고 이를 분산하는데 size설정값과 샤드 개수등에 의해 집계오류 발생할수 있음

  • 예를들어 실제결과와 용어집계가 다르다 -> 집게가 모든 도큐먼트를 가져와 한번에 집계하는게 아니라 분산되어있는 개별 노드단에서 먼저 집계를 하고 그 결과를 취합해 다시 집계를 하기 때문! 그래서 이러한 응답결과가 “doc_count_error_upper_bound”에 표시됨

    용어 집계 정확성 높이기

    고속처리를 위한 리소스와 속도간 트레이드오프의 일환으로 리소스 소비량을 늘리면 정확도를 높일 수 있음

GET kibana_sample_data_ecommerce/_search
{
  "size": 0,
  "aggs": {
    "term_aggs": {
      "terms": {
        "field": "day_of_week",
        "size": 6,
        "show_term_doc_count_error": true
      }
    }
  }
}
  • “show_term_doc_count_error”파라미터를 추가하면 버킷마다 “doc_count_error_upper_bound”값을 확인가능!!!
  • 만약 확인결과 이상값이; 나올 경우에는 샤드 크기 파라미터를 늘릴 필요가 있음 “shard_size”
  • 샤드 크기는 용어집계과정에서 개별 샤드에서 집계를 위해 처리하는 개수, 높게 설정하면 정확도가 올라가지만 리소스사용량도 업업-> 성능 떨어질수 있음
  • 정확한 카운트를 보장하기 위해 show_term_doc_count_error, shard_size 등을 활용해야 함
  • 오차범위가 발생하는 이유: 각 샤드에서 병렬로 집계된 값을 중앙에서 병합하는 방식 때문

4. 집계의 조합

4.1 버킷 집계 + 메트릭 집계

GET kibana_sample_data_ecommerce/_search
{
  "size": 0,
  "aggs": {
    "term_aggs": {
      "terms": {
        "field": "day_of_week",
        "size": 5
      },
      "aggs": {
        "avg_aggs": {
          "avg": {
            "field": "products.base_price"
          }
        },
        "sum_aggs": {
          "sum": {
            "field": "products.base_price"
          }
        }
      }
    }
  }
}
  • 요일별 버킷으로 나눈 후 각 버킷마다 평균, 합계를 계산함
  • 버킷마다 여러 개의 메트릭 집계를 중첩 가능

4.2 서브 버킷 집계 (Nested Bucket)

  • 서브버킷은 버킷 안에서 다시 버킷 집계를 요청하는 집계임 트리구조를 떠올리면 됨
GET kibana_sample_data_ecommerce/_search
{
  "size": 0,
  "aggs": {
    "histogram_aggs": {
      "histogram": {
        "field": "products.base_price",
        "interval": 100
      },
      "aggs" : {
        "term_aggs": {
          "terms": {
            "field": "day_of_week",
            "size" : 2
          }
        }
      }
    }
  }
}
  • 가격을 기준으로 히스토그램 집계를 한 뒤, 각 가격대에서 요일별로 재집계
  • 서브버킷을 과도하게 중첩하면 클러스터 부하로 이어질 수 있음 (2단계 이상은 주의)

5. 파이프라인 집계 (Pipeline Aggregation)

  • 이전결과를 다음단계에서 이용하는 파이프라인 개념을 사용한 집계방식, 이전 집계결과를 입력으로 삼아 다시 집게하는 방식

  • 그래서 부모집계, 형제집계라는 두가지 유형이 있음, 이 두가지 차이는 집계가 작성되는 위치임.

    Elasticsearch 파이프라인 집계 종류 정리

    구분 집계 명 설명
    형제집계 (Sibling Pipeline Aggregation) min_bucket 하위 버킷들 중 가장 작은 값을 가진 버킷의 값을 반환
      max_bucket 하위 버킷들 중 가장 큰 값을 가진 버킷의 값을 반환
      avg_bucket 하위 버킷들의 값의 평균값을 계산
      sum_bucket 하위 버킷들의 값의 총합을 계산
      stats_bucket 하위 버킷들의 값으로부터 count, min, max, avg, sum 등의 통계치를 제공
      percentiles_bucket 하위 버킷들 값의 퍼센타일 값을 계산 (예: 50%, 90% 등)
      moving_fn moving_avg moving_sum 이동 평균, 합계, 사용자 정의 함수를 적용한 버킷 기반 시계열 스무딩 처리
      bucket_script 버킷 값들에 대해 사용자 정의 수식을 적용할 수 있음
    부모집계 (Parent Pipeline Aggregation) derivative 시계열 값의 변화량(차분)을 계산 (ex: 오늘 - 어제)
      cumulative_sum 이전 값들을 누적하여 누적합을 계산
      serial_diff 시계열에서 n개 전 값과의 차이 계산
  • 형제 집계동일한 레벨의 버킷 결과들을 기반으로 함 (ex: date_histogram 결과 각각에 대해 처리).
  • 부모 집계자식 집계 결과를 바탕으로 상위 집계 단계에서 후처리하는 방식임.
  • moving_avg는 Elasticsearch 8.0부터 deprecated 되었고, moving_fn 으로 대체됨.
  • bucket_script는 복수의 버킷 값을 조합한 계산 가능 (ex: A / B)

5.1 부모 집계 (Parent Pipeline)

GET kibana_sample_data_ecommerce/_search
{
  "size": 0,
  "aggs": {
    "histogram_aggs": {
      "histogram": {
        "field": "products.base_price",
        "interval": 100
      },
      "aggs": {
        "sum_aggs": {
          "sum": {
            "field": "taxful_total_price"
          }
        },
        "cum_sum": {
          "cumulative_sum": {
            "buckets_path": "sum_aggs"
          }
        }
      }
    }
  }
}
  • 누적합(cumulative_sum)은 이전 메트릭 결과를 기반으로 집계하는 방식
  • 반드시 buckets_path로 입력값 메트릭을 참조해야 함

5.2 형제 집계 (Sibling Pipeline)

GET kibana_sample_data_ecommerce/_search
{
  "size": 0,
  "aggs": {
    "term_aggs": {
      "terms": {
        "field": "day_of_week",
        "size": 2
      },
      "aggs": {
        "sum_aggs": {
          "sum": {
            "field": "products.base_price"
          }
        }
      }
    },
    "sum_total_price": {
      "sum_bucket": {
        "buckets_path": "term_aggs>sum_aggs"
      }
    }
  }
}
  • 형제 파이프라인 집계는 최상단에서 참조된 집계 경로를 따라 새로운 계산 수행
  • 이 경우 각 요일별 sum_aggs의 값을 모두 더해 하나의 결과로 반환
  • buckets_path: 중첩 경로는 버킷명>집계명으로 표현

끄읕

댓글남기기