티스토리 뷰

이번 포스팅은 사내에서 Elasticsearch 관련 내용 발표를 위해 "시작하세요! 엘라스틱서치"서적을 기반으로 학습하고 이해한 내용을 정리하는 포스팅이다. Elasticsearch 역시 내용이 많기 때문에 시리즈로 나눠서 정리할 예정이다. 모든 내용은 Elasticsearch 7.6 버전 기준이다.

 

오늘은 Elasticsearch 의 Aggregation 을 알아볼 예정이다.  

 

어그리게이션(Aggregation)

Aggregation 은 검색결과에 다양한 연산을 적용해서 출력하는 기능을 지원하기 위해 개발된 모듈이며 크게 버킷(bucket) 과 메트릭(metric) 어그리게이션으로 구분된다. 

  •  버킷 어그리게이션(bucket aggregation)
     bucket aggregation 은 주어진 조건에 해당하는 Document 를 bucket 이라는 저장소 단위로 구분해서 담아 새로운 데이터 집합을 형성한다. filter, missing, terms, range, histogram 이 bucket aggregation 에 속한다. 
    또한 버킷별로 다시 하위 aggregation 을 통해 버킷에 있는 데이터로 다시 새로운 aggregation 연산을 반복해서 수행할 수 있다. 버킷을 이용해 몇단계의 레벨로 중첩해서 처리할 수 있지만 레벨이 깊어질수록 서버 메모리와 같은 자원의 소비가 늘어나므로 주의가 필요하다. 

  • 메트릭 어그리게이션(metric aggregation)
     metric aggregation 은 주어진 조건으로 Document 를 계산해서 처리된 결과값을 도출한다. min, max, sum, avg 가 metric  aggregation 에 속한다. 

1. 최소, 최대, 합, 평균, 개수 어그리게이션(min, max, sum, avg, count)

 가장 기본적인 타입의 metric aggregation 이다. 

### 최소 ###
curl -H 'Content-Type: application/json' -X GET 'localhost:9200/user_bulk/_search?pretty' -d '
{
  "aggs": {
    "birth_min": {
      "min" : { "field" : "birth" }
    }
  }
}'
--- 반환값 ---
{ ...
  "aggregations" : {
    "birth_min" : { "value" : 1967.0 }
  }
}

### 최대 ###
curl -H 'Content-Type: application/json' -X GET 'localhost:9200/user_bulk/_search?pretty' -d '
{
  "aggs": {
    "birth_max": {
      "min" : { "field" : "birth" }
    }
  }
}'
--- 반환값 ---
{ ...
  "aggregations" : {
    "birth_max" : { "value" : 2002.0 }
  }
}

### 합 ###
curl -H 'Content-Type: application/json' -X GET 'localhost:9200/user_bulk/_search?pretty' -d '
{
  "aggs": {
  	"birth_sum": {
  	  "sum" : { "field" : "birth" }
  	}
  }
}'
--- 반환값 ---
{ ...
  "aggregations" : {
    "birth_sum" : { "value" : 19863.0 }
  }
}

### 평균 ###
curl -H 'Content-Type: application/json' -X GET 'localhost:9200/user_bulk/_search?pretty' -d '
{
  "aggs": {
  	"birth_avg": {
  	  "avg" : { "field" : "birth" }
  	}
  }
}'
--- 반환값 ---
{ ...
  "aggregations" : {
    "birth_avg" : { "value" : 1986.3 }
  }
}

### 수 ###
curl -H 'Content-Type: application/json' -X GET 'localhost:9200/user_bulk/_search?pretty' -d '
{
  "aggs": {
  	"birth_cnt": {
  	  "value_count" : { "field" : "birth" }
  	}
  }
}'
--- 반환값 ---
{ ...
  "aggregations" : {
    "birth_cnt" : { "value" : 10 }
  }
}

 

2. 상태 , 확장상태 어그리게이션(stats, extended_stats)

 상태 타입을 사용해서 최소, 최대, 합, 평균, 개수를 한번에 표시할 수 있다. 다음은 상태타입으로 birth 필드의 정보를 가져온 결과다. 

curl -H 'Content-Type: application/json' -X GET 'localhost:9200/user_bulk/_search?pretty' -d '
{
  "aggs": {
  	"birth_stats": {
  	  "stats" : { "field" : "birth" }
  	}
  }
}'
--- 반환값 ---
{ ...
  "aggregations" : {
    "birth_stats" : {
      "count" : 10,
      "min" : 1967.0,
      "max" : 2002.0,
      "avg" : 1986.3,
      "sum" : 19863.0
    }
  }
}

상태 어그리게이션의 자세한 정보는 여기서 확인 할 수 있다. 

확장상태 타입을 사용하면 상태정보 외에 추가로 값들의 정보를 확인할 수 있다. 

curl -H 'Content-Type: application/json' -X GET 'localhost:9200/user_bulk/_search?pretty' -d '
{
  "aggs": {
  	"birth_ex_stats": {
  	  "extended_stats" : { "field" : "birth" }
  	}
  }
}'
--- 반환값 ---
{ ...
  "aggregations" : {
    "birth_ex_stats" : {
      "count" : 10,
      "min" : 1967.0,
      "max" : 2002.0,
      "avg" : 1986.3,
      "sum" : 19863.0,
      "sum_of_squares" : 3.9455057E7,
      "variance" : 118.010000000149,
      "std_deviation" : 10.863240768764587,
      "std_deviation_bounds" : {
        "upper" : 2008.0264815375292,
        "lower" : 1964.5735184624707
      }
    }
  }
}

확장상태 어그리게이션의 자세한 정보는 여기서 확인 할 수 있다. 

 

3. 글로벌 어그리게이션(global)

 글로벌은 검색 범위의 인덱스나 타입에 해당하는 모든 Document를 하나의 bucket에 모두 담는 bucket aggregation 이며 query 에 영향을 받지 않는다.  다음 두 예제의 차이점을 보면서 이해해보자. 첫번째 예제는 country 필드가 san 을 포함하는 Document 들의 평균 birth 를 구하는 예제다. 

curl -H 'Content-Type: application/json' -X GET 'localhost:9200/user_bulk/_search?pretty' -d '
{
  "query": {
    "term" : { "country": "san" }
  },
  "aggs": {
  	"avg_birth": {
  	  "avg" : { "field" : "birth" }
  	}
  }
}'
--- 반환값 ---
{ ...
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    ...  
  }
  "aggregations" : {
    "avg_birth" : { "value" : 1995.0 }
  }
}

다음예제는 글로벌 어그리게이션을 이용해서 생성된 bucket 에서 다시 하위 어그리게이션으로 평균을 구한 것이다. 

curl -H 'Content-Type: application/json' -X GET 'localhost:9200/user_bulk/_search?pretty' -d '
{
  "query": {
    "term" : { "country": "san" }
  },
  "aggs": {
    "all_birth": {
      "global": {},
      "aggs" : {
        "avg_birth": {
  	      "avg" : { "field" : "birth" }
  	    }
      }
    }
  }
}'
--- 반환값 ---
{ ...
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "hits" : [
      {
        ...
        "_id" : "8",
        "_source" : {
          ...
          "country" : "San Francisco"
        }
      },
      {
        ...
        "_id" : "9",
        "_source" : {
          ...
          "country" : "San Diego"
        }
      }
    ]
    ...
  },
  "aggregations" : {
    "all_birth" : {
      "doc_count" : 10,
      "avg_birth" : {
        "value" : 1986.3
      }
    }
  }
}

글로벌 어그리게이션을 사용할경위 query 에 상관없이 글로벌 어그리게이션에 담긴 10개의 Document 전체의 평균인 1986.3 구했다. 

이처럼 글로벌 어그리게이션을 이용하면 한번의 검색으로 질의 내용과 별도의 어그리게이션을 동시에 사용 할 수 있다. 

자세한 내용은 여기서 확인 할 수 있다. 

 

4. 필터 어그리게이션(filter)

 필터 어그리게이션을 사용하면 주어진 필터에 해당하는 Document 를 담는 bucket 을 생성한다.

다음 예시는 term 필터를 사용해서 country 필드 값에 san 이 포함된 Document 를 bucket 에 담아 하위 어그리게이션으로 이용해 합을 구하는 예제이다. 

curl -H 'Content-Type: application/json' -X GET 'localhost:9200/user_bulk/_search?pretty' -d '
{
  "aggs":{
    "has_san_filter" : {
      "filter" : {
        "term" : { "country" : "san" }
      },
      "aggs" : {
        "sum_birth" : {
          "sum" : { "field" : "birth" }
        }
      }
    }
  }
}
--- 반환값 ---
{ ...
  "aggregations" : {
    "has_san_filter" : {
      "doc_count" : 2,
      "sum_birth" : { "value" : 3990.0 }
    }
  }
}

필터 어그리게이션에 대한 자세한 내용은 여기서 확인 할 수 있다. 

 

5. 텀즈 어그리게이션(terms)

텀즈 어그리게이션을 사용하면 검색된 텀(term) 마다 bucket 을 생성한다. 다음 예제는 birth 필드의 텀 값으로 bucket 을 생성하고 bucket 마다 birth 필드의 개수를 계산한 결과이다. 

curl -H 'Content-Type: application/json' -X GET 'localhost:9200/user_bulk/_search?pretty' -d '
{
  "aggs":{
    "term_birth" : {
      "terms" : { 
        "field" : "birth",
        "order" : {"_term": "desc" }
      },
      "aggs" : {
        "birth_cnt" : {
          "value_count" : { "field" : "birth" }
        }
      }
    }
  }
}'

--- 반환값 ---
{ ...
  "aggregations" : {
    "term_birth" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : 2002,
          "doc_count" : 1,
          "birth_cnt" : {
            "value" : 1
          }
        },
        {
          "key" : 1997,
          "doc_count" : 1,
          "birth_cnt" : {
            "value" : 1
          }
        },
        {
          "key" : 1994,
          "doc_count" : 1,
          "birth_cnt" : {
            "value" : 1
          }
        },
        {
          "key" : 1991,
          "doc_count" : 1,
          "birth_cnt" : {
            "value" : 1
          }
        },
        {
          "key" : 1989,
          "doc_count" : 1,
          "birth_cnt" : {
            "value" : 1
          }
        },
        {
          "key" : 1988,
          "doc_count" : 2,
          "birth_cnt" : {
            "value" : 2
          }
        },
        {
          "key" : 1977,
          "doc_count" : 1,
          "birth_cnt" : {
            "value" : 1
          }
        },
        {
          "key" : 1970,
          "doc_count" : 1,
          "birth_cnt" : {
            "value" : 1
          }
        },
        {
          "key" : 1967,
          "doc_count" : 1,
          "birth_cnt" : {
            "value" : 1
          }
        }
      ]
    }
  }
}

order 필드를 이용해서 버킷의 출력될 순서를 정렬 할 수 있다. 사용할 수 있는 옵션은 다음과 같으며 ASC, DESC 를 사용한다. 

  • _count : bucket 에 담긴 Document 개수로 정렬한다. 
  • _term : bucket 을 구분하는 term 값의 이름순으로 정렬한다. 
  • 하위 어그리게이션 이름 : 하위 어그리게이션의 결과값 기준으로 정렬한다. 

텀즈 어그리게이션에 대한 자세한 설명은 여기서 확인 할 수 있다. 

 

6.  범위 어그리게이션(range)

범위(range) 어그리게이션을 사용해서 설정한 값의 범위 별로 bucket 을 생성 할 수 있다. 

다음은 birth 를 "~ 1980 , 1980 ~ 2000 , 2000 ~" 으로 구분해서 bucket 을 생성하고 bucket 별로 birth 의 평균을 구한 결과이다. 

curl -H 'Content-Type: application/json' -X GET 'localhost:9200/user_bulk/_search?pretty' -d '
{
  "aggs":{
    "range_birth" : {
      "range" : { 
        "field" : "birth",
        "ranges" : [{"to": 1980}, {"from": 1980, "to": 2000}, {"from":2000}]
      },
      "aggs" : {
        "birth_avg" : {
          "avg" : { "field" : "birth" }
        }
      }
    }
  }
}'
--- 반환값 ---
{ ...
  "aggregations" : {
    "range_birth" : {
      "buckets" : [
        {
          "key" : "*-1980.0",
          "to" : 1980.0,
          "doc_count" : 3,
          "birth_avg" : {
            "value" : 1971.3333333333333
          }
        },
        {
          "key" : "1980.0-2000.0",
          "from" : 1980.0,
          "to" : 2000.0,
          "doc_count" : 6,
          "birth_avg" : {
            "value" : 1991.1666666666667
          }
        },
        {
          "key" : "2000.0-*",
          "from" : 2000.0,
          "doc_count" : 1,
          "birth_avg" : {
            "value" : 2002.0
          }
        }
      ]
    }
  }
}

범위 어그리게이션에 대한 자세한 설명은 여기서 확인 할 수 있다. 

그 외에도 날짜 어그리게이션, 히스토그램 어그리게이션 등이 있지만 여기서 설명하진 않겠다.  

 

오늘은 여기까지~

누군가에게 도움이 되었길 바라면서 오늘의 포스팅 끝~

댓글