본문 바로가기

Elasticsearch

[Elasticsearch] Aggregations 집계 총정리

반응형

Elasticsearch Aggregations, 집계

 

 

Elasticsearch 는 검색뿐 아니라 여러가지 연산을 할 수 있는 Aggregation 기능이 있다. Kibana에서 차트, 그래프 등으로 시각화시킬 때 사용하는 기능이 aggregation 이다. 

 

aggregations 에는 두 가지 종류가 있다. 

- Metrics aggregation : 숫자 또는 날짜 필드의 값으로 계산함

- Bucket aggregation : 범위나 keyword 값으로 그룹화함

 

그리고 확장하여 사용할 수 있는 aggregations 도 있다. 

- Sub-aggregation : bucket 하위 집계 

- Pipeline-aggregation : metrics aggregation 결과로 다시 집계 

 

 

 

Metrics aggregation

 

Metrics aggregation으로 가장 많이 쓰이는 것은 min, max, sum, avg 등이 있다.

min : 최소값

max : 최대값

sum : 합

avg : 평균값 

 

 

aggregation을 실습해볼 12개의 도큐먼트 넣어주면서 index 생성

PUT stations/_bulk
{"index": {"_id": 1}}
{"date": "2022-12-25", "line": "1호선", "station": "잠실", "passangers": 1000}
{"index": {"_id": 2}}
{"date": "2022-12-26", "line": "2호선", "station": "잠실새내", "passangers": 1000}
{"index": {"_id": 3}}
{"date": "2022-12-27", "line": "3호선", "station": "잠실", "passangers": 1000}
{"index": {"_id": 4}}
{"date": "2022-12-31", "line": "2호선", "station": "가락시장", "passangers": 2000}
{"index": {"_id": 5}}
{"date": "2023-01-01", "line": "1호선", "station": "잠실새내", "passangers": 2000}
{"index": {"_id": 6}}
{"date": "2023-02-10", "line": "2호선", "station": "가락시장", "passangers": 2000}
{"index": {"_id": 7}}
{"date": "2023-04-23", "line": "3호선", "station": "가락시장", "passangers": 2000}
{"index": {"_id": 8}}
{"date": "2023-09-22", "line": "1호선", "station": "잠실", "passangers": 3000}
{"index": {"_id": 9}}
{"date": "2023-10-25", "line": "3호선", "station": "잠실", "passangers": 3000}
{"index": {"_id": 10}}
{"date": "2023-10-17", "line": "2호선", "station": "잠실새내", "passangers": 3000}
{"index": {"_id": 11}}
{"date": "2023-11-04", "line": "1호선", "station": "잠실", "passangers": 3000}
{"index": {"_id": 12}}
{"date": "2023-12-11", "line": "3호선", "station": "가락시장", "passangers": 3000}

 

 

 

min, max, sum, avg 실습

 

GET stations/_search
{
  "size": 0,
  "aggs": {
    "all_passangers": {
      "sum": {
        "field": "passangers"
      }
    }
  }
}

"size": 0 을 안 넣게되면 모든 데이터가 매칭되어 나오는데 집계만 필요할 경우 size : 0으로 넣어서 hits되는 데이터가 아무것도 안나오게 하면 더 빠르고 효율적이다. 

 

"aggs": { "내가 정하는 필드명" { "계산할 수식(min or max or sum or avg)" { "field": "계산할 필드명" } } } 

 

sum, min, max, avg 모두 적용해보기

GET stations/_search
{
  "size": 0,
  "aggs": {
    "all_passangers": {
      "sum": {
        "field": "passangers"
      }
    },
    "min_passangers": {
      "min": {
        "field": "passangers"
      }
    },
    "max_passangers": {
      "max": {
        "field": "passangers"
      }
    },
    "avg_passangers": {
      "avg": {
        "field": "passangers"
      }
    }
  }
}

결과 : 

{
  "took" : 8,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 12,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "all_passangers" : {
      "value" : 26000.0
    },
    "avg_passangers" : {
      "value" : 2166.6666666666665
    },
    "max_passangers" : {
      "value" : 3000.0
    },
    "min_passangers" : {
      "value" : 1000.0
    }
  }
}

보통 검색 결과 데이터를 보여주는 "hits" (hits.hits X)  와 동일한 뎁스의 "aggregations" 라는 key가 생겼고 그 안에 집계 검색한 내용이 나온다. 

 

 

 

Stats 

min, max, sum, avg를 한 번에 보여주고 해당하는 도큐먼트들의 개수도 가져온다. 

 

GET stations/_search
{
  "size": 0,
  "aggs": {
    "station_passangers_stats": {
      "stats": {
        "field": "passangers"
      }
    }
  }
}

min, max..를 넣어주는 부분에 stats를 넣어주면 결과 : 

{
  "took" : 7,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 12,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "station_passangers_stats" : {
      "count" : 12,
      "min" : 1000.0,
      "max" : 3000.0,
      "avg" : 2166.6666666666665,
      "sum" : 26000.0
    }
  }
}

count : 아래 집계에 계산할 때 쓰인 도큐먼트 수를 보여준다. hits에 이 도큐먼트들이 안나오는 이유는 검색 query에 도큐먼트는 0개 보여줘 라고 요청했기 때문이다. 

 

 

 

 

Cardinality

필드의 값의 집합 (종류)를 알아볼 때 사용하는 cardinality

일반적으로 text 필드보다 숫자 필드, keyword, ip 등 에서 사용한다. 사용자 접속 로그에서 ip 주소 필드를 가지고 접속한 유저 파악 시에 주로 사용된다. 

 

위에서 입력한 station 데이터들 중 line 필드가 총 몇 종류가 있는지 계산해보기 

GET stations/_search
{
  "size": 0,
  "aggs": {
    "line_types": {
      "cardinality": {
        "field": "line.keyword"
      }
    }
  }
}

"field": "line" 만으로 검색하면 에러가 난다. 

 

결과 :

{
  "took" : 14,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 12,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "line_types" : {
      "value" : 3
    }
  }
}

 

총 3개의 line 호선이 있는 걸 알 수 있다. 

 

 

 

 

 

Percentiles, Percentile_ranks

값들을 백분위 별로 보는 방법 

- percentiles : % 구간 별 값을 보기 

- percentil_ranks : 값으로 그 값이 위치 해 있는 백분위 보기 

 

 

percentiles

GET stations/_search
{
  "size": 0,
  "aggs": {
    "passanger_percentiles": {
      "percentiles": {
        "field": "passangers"
      }
    }
  }
}

결과 : 

{
  "took" : 10,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 12,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "passanger_percentiles" : {
      "values" : {
        "1.0" : 1000.0,
        "5.0" : 1000.0,
        "25.0" : 1500.0,
        "50.0" : 2000.0,
        "75.0" : 3000.0,
        "95.0" : 3000.0,
        "99.0" : 3000.0
      }
    }
  }
}

디폴트로 1,5,25,50,75,95,99% 구간에 위치 해 있는 값들을 표시해 준다. 구간을 커스텀하고 싶다면 아래와 같이 옵션을 주면 된다. 

GET stations/_search
{
  "size": 0,
  "aggs": {
    "passanger_percentiles": {
      "percentiles": {
        "field": "passangers",
        "percents": [0,1,50,99,100]
      }
    }
  }
}

결과 : 

  "aggregations" : {
    "passanger_percentiles" : {
      "values" : {
        "0.0" : 1000.0,
        "1.0" : 1000.0,
        "50.0" : 2000.0,
        "99.0" : 3000.0,
        "100.0" : 3000.0
      }
    }
  }

 

 

 

percentile_ranks

 

GET stations/_search
{
  "size": 0,
  "aggs": {
    "passanger_percentile_ranks": {
      "percentile_ranks": {
        "field": "passangers",
        "values": [1000,2000,3000]
      }
    }
  }
}

결과  : 

  "aggregations" : {
    "passanger_percentile_ranks" : {
      "values" : {
        "1000.0" : 16.666666666666664,
        "2000.0" : 50.0,
        "3000.0" : 100.0
      }
    }
  }

 

1000,2000,3000 값이 위치한 백분위가 나온다. 위의 방식은 성적이 상위 몇%인지 파악할 때 편리하게 사용이 가능하다. 

 

 

 

 

 


 

 

 

 

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 형식은 -> 여기 포스팅 에 확인 가능

 

[Elasticsearch] Data Math 개념과 계산하는 방법

Elasticsearch range queries에서 또는 datarange aggregations에서 사용되는 Date Math 알아보기 1) 기본 단위들 기본 단위들은 아래와 같다. supported units y Years M Months w Weeks d Days h Hours H Hours m Minutes s Seconds 그리

blckchainetc.tistory.com

 

 

결과 : 

  "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 에 입력한 잠실, 잠실새내, 가락시장 값들이 정리되어서 나왔다. 

 

 

 

 

 


 

 

 

 

sub-aggregations

bucket aggregation으로 만든 버킷 내부에 다시 aggregation 집계 (metrics or bucket 모두 가능)를 하는 방식이다. 

 

역 명으로 버킷(그룹)화 해서 그 내부에 passangers 필드의 평균 값 또한 나타내기 

GET stations/_search
{
  "size": 0,
  "aggs": {
    "stations": {
      "terms": {
        "field": "station.keyword"
      },
      "aggs": {
        "avg_psg_per_station": {
          "avg": {
            "field": "passangers"
          }
        }
      }
    }
  }
}

결과 : 

  "aggregations" : {
    "stations" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "가락시장",
          "doc_count" : 5,
          "avg_psg_per_station" : {
            "value" : 1860.0
          }
        },
        {
          "key" : "잠실",
          "doc_count" : 5,
          "avg_psg_per_station" : {
            "value" : 2200.0
          }
        },
        {
          "key" : "잠실새내",
          "doc_count" : 3,
          "avg_psg_per_station" : {
            "value" : 2000.0
          }
        }
      ]
    }
  }

결과 aggregations > stations (사용자 임의 버킷명) > terms 버킷 & 그 안의 passangers 평균 값 이 같은 뎁스에 나와있다. 

 

 

line, 호선 별로 버킷을 만들고 그 안에 호선 별 역명 버킷화, 각 호선별 평균 승객 수 구하기 

GET stations/_search
{
  "size": 0,
  "aggs": {
    "lines": {
      "terms": {
        "field": "line.keyword"
      },
      "aggs": {
        "avg_psg_per_line": {
          "avg": {
            "field": "passangers"
          }
        },
        "stations_per_line": {
          "terms": {
            "field": "station.keyword"
          }
        }

      }
    }
  }
}

결과 : 

  "aggregations" : {
    "lines" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "3호선",
          "doc_count" : 5,
          "stations_per_line" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : "가락시장",
                "doc_count" : 3
              },
              {
                "key" : "잠실",
                "doc_count" : 2
              }
            ]
          },
          "avg_psg_per_line" : {
            "value" : 1860.0
          }
        },
        {
          "key" : "1호선",
          "doc_count" : 4,
          "stations_per_line" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : "잠실",
                "doc_count" : 3
              },
              {
                "key" : "잠실새내",
                "doc_count" : 1
              }
            ]
          },
          "avg_psg_per_line" : {
            "value" : 2250.0
          }
        },
        {
          "key" : "2호선",
          "doc_count" : 4,
          "stations_per_line" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : "가락시장",
                "doc_count" : 2
              },
              {
                "key" : "잠실새내",
                "doc_count" : 2
              }
            ]
          },
          "avg_psg_per_line" : {
            "value" : 2000.0
          }
        }
      ]
    }
  }

 

버킷 안 버킷 끝없이 만들 순 있겠지만 뎁스가 증가할수록 elasticsearch의 작업량, 메모리 소모량이 기하급수적으로 늘어나 오류가 날 수도 있어서, 보통 2레벨 정도까지 사용하는 게 좋다고 한다. 

 

 

 

 


 

 

 

 

Pipeline-Aggregation

 

sub-aggregation이 버킷 안에서 다시 버킷을 만들거나 집계를 하는 것이었다면 pipieline-aggregation은 버킷 결과들을 다시 연산하여 새로게 입력하는 방법이다. metrics에서 사용한 min, max, avg, sum, stats 등과 비슷하게 다른 버킷의 결과들을 min_bucket, max_bucket, avg_bucket, sum_bucket, stats_bucket, moving_avg(이동 평균을 구하는), derivative(미분값을 구하는), cumulative_sum(값의 누적 합을 구하는) 등이 있다. 

 

 

stations 인덱스에서 date_histogram을 사용하여 month 월별로 나눈 passangers의 합을 다시 cumulative_sum을 이용해 누적값을 구하기 (date_histogram 등의 사용 설명 및 예제는 Bucket aggregation참고)

GET stations/_search
{
  "size": 0,
  "aggs": {
    "bucket_monthly": {
      "date_histogram": {
        "field": "date",
        "interval": "month"
      },
      "aggs": {
        "sum_psg": {
          "sum": {
            "field": "passangers"
          }
        },
        "acc_sum_psg": {
          "cumulative_sum": {
            "buckets_path": "sum_psg"
          }
        }
      }
    }
  }
}

먼저 첫 번째 aggs에서 monthly 로 나눈 버킷을 date_histogram을 사용해서 나눠준 후 그 안에 다시 두 번째 aggs를 넣어 sum_psg(각 월별 총 승객 수)와 acc_sum_psg (각 월별 총 승객 수의 누적 합)을 설정해 주었다. 

 

결과 : 

"aggregations" : {
    "bucket_monthly" : {
      "buckets" : [
        {
          "key_as_string" : "2022-12-01T00:00:00.000Z",
          "key" : 1669852800000,
          "doc_count" : 4,
          "sum_psg" : {
            "value" : 5000.0
          },
          "acc_sum_psg" : {
            "value" : 5000.0
          }
        },
        {
          "key_as_string" : "2023-01-01T00:00:00.000Z",
          "key" : 1672531200000,
          "doc_count" : 1,
          "sum_psg" : {
            "value" : 2000.0
          },
          "acc_sum_psg" : {
            "value" : 7000.0
          }
        },
        {
          "key_as_string" : "2023-02-01T00:00:00.000Z",
          "key" : 1675209600000,
          "doc_count" : 1,
          "sum_psg" : {
            "value" : 2000.0
          },
          "acc_sum_psg" : {
            "value" : 9000.0
          }
        },
        {
          "key_as_string" : "2023-03-01T00:00:00.000Z",
          "key" : 1677628800000,
          "doc_count" : 0,
          "sum_psg" : {
            "value" : 0.0
          },
          "acc_sum_psg" : {
            "value" : 9000.0
          }
        },
        {
          "key_as_string" : "2023-04-01T00:00:00.000Z",
          "key" : 1680307200000,
          "doc_count" : 1,
          "sum_psg" : {
            "value" : 2000.0
          },
          "acc_sum_psg" : {
            "value" : 11000.0
          }
        },
        {
          "key_as_string" : "2023-05-01T00:00:00.000Z",
          "key" : 1682899200000,
          "doc_count" : 0,
          "sum_psg" : {
            "value" : 0.0
          },
          "acc_sum_psg" : {
            "value" : 11000.0
          }
        },
        {
          "key_as_string" : "2023-06-01T00:00:00.000Z",
          "key" : 1685577600000,
          "doc_count" : 0,
          "sum_psg" : {
            "value" : 0.0
          },
          "acc_sum_psg" : {
            "value" : 11000.0
          }
        },
        {
          "key_as_string" : "2023-07-01T00:00:00.000Z",
          "key" : 1688169600000,
          "doc_count" : 0,
          "sum_psg" : {
            "value" : 0.0
          },
          "acc_sum_psg" : {
            "value" : 11000.0
          }
        },
        {
          "key_as_string" : "2023-08-01T00:00:00.000Z",
          "key" : 1690848000000,
          "doc_count" : 0,
          "sum_psg" : {
            "value" : 0.0
          },
          "acc_sum_psg" : {
            "value" : 11000.0
          }
        },
        {
          "key_as_string" : "2023-09-01T00:00:00.000Z",
          "key" : 1693526400000,
          "doc_count" : 1,
          "sum_psg" : {
            "value" : 3000.0
          },
          "acc_sum_psg" : {
            "value" : 14000.0
          }
        },
        {
          "key_as_string" : "2023-10-01T00:00:00.000Z",
          "key" : 1696118400000,
          "doc_count" : 2,
          "sum_psg" : {
            "value" : 6000.0
          },
          "acc_sum_psg" : {
            "value" : 20000.0
          }
        },
        {
          "key_as_string" : "2023-11-01T00:00:00.000Z",
          "key" : 1698796800000,
          "doc_count" : 1,
          "sum_psg" : {
            "value" : 3000.0
          },
          "acc_sum_psg" : {
            "value" : 23000.0
          }
        },
        {
          "key_as_string" : "2023-12-01T00:00:00.000Z",
          "key" : 1701388800000,
          "doc_count" : 2,
          "sum_psg" : {
            "value" : 3300.0
          },
          "acc_sum_psg" : {
            "value" : 26300.0
          }
        }
      ]
    }
  }

bucket_monthly라는 key 안의 bucket 배열 값으로 쭉 나열 됨

acc_sum_psg . value를 보면 각 이전 배열 값들이 계속해서 누적되어 합한 걸 알 수 있다. 

 

 

서로 다른 버킷의 pipeline-aggregation

서로 다른 버킷에 있는 값들도 pipeline-aggregation으로 집계가 가능하다. 이 경우에는 ">" 이 기호를 사용해서 해당 버킷 > 목표 버킷 안의 집계 이름(사용자 정의 필드명)을 적어주면 된다. 

 

위와 동일하게 monthly 월 별로 버킷을 생성 후, 그 안에 승객의 합계를 넣고 다른 sum 버킷을 생성하기 

GET stations/_search
{
  "size": 0,
  "aggs": {
    "bucket_monthly": {
      "date_histogram": {
        "field": "date",
        "interval": "month"
      },
      "aggs": {
        "sum_psg": {
          "sum": {
            "field": "passangers"
          }
        }
      }
    },
    "bucket_sum_psg": {
      "sum_bucket": {
        "buckets_path": "bucket_monthly>sum_psg"
      }
    }
  }
}

 

결과 : 

 "aggregations" : {
    "bucket_monthly" : {
      "buckets" : [
        {
          "key_as_string" : "2022-12-01T00:00:00.000Z",
          "key" : 1669852800000,
          "doc_count" : 4,
          "sum_psg" : {
            "value" : 5000.0
          }
        },
        {
          "key_as_string" : "2023-01-01T00:00:00.000Z",
          "key" : 1672531200000,
          "doc_count" : 1,
          "sum_psg" : {
            "value" : 2000.0
          }
        },
        {
          "key_as_string" : "2023-02-01T00:00:00.000Z",
          "key" : 1675209600000,
          "doc_count" : 1,
          "sum_psg" : {
            "value" : 2000.0
          }
        },
        {
          "key_as_string" : "2023-03-01T00:00:00.000Z",
          "key" : 1677628800000,
          "doc_count" : 0,
          "sum_psg" : {
            "value" : 0.0
          }
        },
        {
          "key_as_string" : "2023-04-01T00:00:00.000Z",
          "key" : 1680307200000,
          "doc_count" : 1,
          "sum_psg" : {
            "value" : 2000.0
          }
        },
        {
          "key_as_string" : "2023-05-01T00:00:00.000Z",
          "key" : 1682899200000,
          "doc_count" : 0,
          "sum_psg" : {
            "value" : 0.0
          }
        },
        {
          "key_as_string" : "2023-06-01T00:00:00.000Z",
          "key" : 1685577600000,
          "doc_count" : 0,
          "sum_psg" : {
            "value" : 0.0
          }
        },
        {
          "key_as_string" : "2023-07-01T00:00:00.000Z",
          "key" : 1688169600000,
          "doc_count" : 0,
          "sum_psg" : {
            "value" : 0.0
          }
        },
        {
          "key_as_string" : "2023-08-01T00:00:00.000Z",
          "key" : 1690848000000,
          "doc_count" : 0,
          "sum_psg" : {
            "value" : 0.0
          }
        },
        {
          "key_as_string" : "2023-09-01T00:00:00.000Z",
          "key" : 1693526400000,
          "doc_count" : 1,
          "sum_psg" : {
            "value" : 3000.0
          }
        },
        {
          "key_as_string" : "2023-10-01T00:00:00.000Z",
          "key" : 1696118400000,
          "doc_count" : 2,
          "sum_psg" : {
            "value" : 6000.0
          }
        },
        {
          "key_as_string" : "2023-11-01T00:00:00.000Z",
          "key" : 1698796800000,
          "doc_count" : 1,
          "sum_psg" : {
            "value" : 3000.0
          }
        },
        {
          "key_as_string" : "2023-12-01T00:00:00.000Z",
          "key" : 1701388800000,
          "doc_count" : 2,
          "sum_psg" : {
            "value" : 3300.0
          }
        }
      ]
    },
    "bucket_sum_psg" : {
      "value" : 26300.0
    }
  }

결과도 두 개의 버킷이 생성되었다. Bucket_sum_psg는 다른 버킷이었던 bucket_monthly의 sum_psg 승객 수 합계를 모두 합한 값이다. 

 

 

 

 

Reference : es의 아주 좋은 가이드북 :  https://esbook.kimjmin.net/08-aggregations

 

8.1 메트릭 - Metrics Aggregations - Elastic 가이드북

percentiles aggregation은 디폴트로 1%, 5%, 25%, 50%, 75%, 95%, 99% 구간에 위치 해 있는 값들을 표시 해 줍니다. 백분위 구간을 직접 지정하고 싶으면 percents 옵션을 이용해서 지정이 가능합니다. 다음은 20%,

esbook.kimjmin.net

반응형