'프로그래밍/elasticsearch' 카테고리의 글 목록 :: 잡다한 프로그래밍
반응형

1. 엘라스틱 서치 쿼리에대해 간단하게 정리하고자 한다.

 

기본적으로 아래와 같은 형태를 띄고 있다.

- query: 기존 DB의 where 조건문에 해당 (query, filter)

- size: 0으로 설정할경우 결과는 보지않고 집계결과만 보겠다는 의미

- aggs: 집계 부분 기존 쿼리의 Group by에 해당

GET _search
{
  "query":{
  },
  "size":0,
  "aggs": {
  }
}

 

집계 정리

1. SELECT count(*) FROM test group by userNo

- 유저 번호로 그룹핑한 결과를 보고 싶을때

{
  "size":0,
  "aggs": {
    "user_no (집계 대상 이름)" : {
      "terms": {
        "field": "user.no"
      }
    }
  }
}

결과

  "aggregations" : {
    "aa" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : 0,
          "doc_count" : 66
        },
        {
          "key" : 107,
          "doc_count" : 14
        }
        ...
        이하 생략

 

2. userNo 값으로 집계한 결과를 대상으로 특정 url로 집계하고 싶을때

{
  "size":0,
  "aggs": {
    "aa" : {
      "terms": {
        "field": "user.no"
      },
      "aggs": {
        "url_name": {
          "terms": {
            "field": "url.keyword"
          }
        }
      }
    }
  }
}

결과

  "aggregations" : {
    "user_no" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : 0,  # 유저별 그룹핑
          "doc_count" : 664745,
          "url" : {
            "doc_count_error_upper_bound" : 94,
            "sum_other_doc_count" : 4659,
            "buckets" : [ # url별 그룹핑
              {
                "key" : "http://aaa.com",
                "doc_count" : 655
              },
              {
                "key" : "https://test.com/",
                "doc_count" : 469
              },
              {
              .. 이하생략

 

3. 일별, 사용자별로 그룹핑 한다면? (2번은 집계한 결과의 집계, 3번과차이가 있음)

{
  "size":0,
  "aggs": {
    "abnormal_status" : {
      "composite": {
        "sources": [
         # time을 일별로 묶어줌, calendar_interval = day, week, hour..
          { "date": { "date_histogram": { "field": "time", "calendar_interval": "day", "format": "yyyy-MM-dd"}}},
          { "name": { "terms": { "field": "userNo" } } }
        ]
      }
    }
  }
}

 

결과

 "aggregations" : {
    "abnormal_status" : {
      "after_key" : {
        "date" : "2022-07-14",
        "name" : 2
      },
      "buckets" : [
        {
          "key" : {
            "date" : "2022-01-03",
            "name" : 0
          },
          "doc_count" : 1
        },
        {
          "key" : {
            "date" : "2022-05-30",
            "name" : 0
          },
          "doc_count" : 1
        }
        ... 이하생략

 

4. count(distinct column) > 사용자별로 (그룹핑) 몇개의 ip를 가지고있는가 (count(distint))

{
  "size":0,
  "aggs": {
    "user" : {
      "terms": {
        "field": "userNo"
      },
      "aggs": {
        "ip": {
          "cardinality": {
            "field": "ip"
          }
        }
      }
    }
  }
}

결과

"aggregations" : {
    "multi_ip_top_n" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : 0,
          "doc_count" : 45,
          "ip_cardinality" : {
            "value" : 3
          }
        },
        {
          "key" : 2,
          "doc_count" : 9,
          "ip_cardinality" : {
            "value" : 2
          }
        },
        {
          "key" : 25,
          "doc_count" : 5,
          "ip_cardinality" : {
            "value" : 2
          }
        },
        .. 이하 생략

 

5. sum, avg, min, max > status

status를 사용할경우 앞의 4가지를 전부 구할 수 있다.

  "size":0,
  "aggs": {
    "user_no" : {
      "terms": {
        "field": "user.no"
      },
      "aggs": {
        "sum": {
          "sum": {
            "field": "queryCnt"
          }
        },
        "avg": {
          "avg": {
            "field": "queryCnt"
          }
        },
        "min": {
          "min": {
            "field": "queryCnt"
          }
        },
        "max": {
          "max": {
            "field": "queryCnt"
          }
        }
      }
    }
  }
}
{
  "query":{
    "bool":{
      "filter": [
        { "range": { "reqTime": { "gte": 20210623000000, "lte": 20220723235959 }}}
      ]
    }
  },
  "size":0,
  "aggs": {
    "user_no" : {
      "terms": {
        "field": "user.no"
      },
      "aggs": {
        "stats": {
          "stats": {
            "field": "queryCnt"
          }
        }
      }
    }
  }
}

 

집계시 기억해야 할 점

 

엘라스틱 서치에서 제공하는 기본 집계의 수는 10000건이다. 이 이상으로 설정할 수 있지만 권장하지 않는다하고, 따라서 이에 맞게 결과를 도출하려 해야한다.

 

그럼에도 불구하고 10000건이상, 혹은 전체를 불러오고 싶을경우?(ex 페이징처리가 필요하다)

 

composite집계를 이용하여 처리할 수 있다.

앞선 composite 집계 결과를 보면 다음과 같이 after_key를 포함하고있다. 집계시 해당 키값을 넣어주게 되면 해당 키 다음부터 조회할 수 있다.

이런 방법으로 전체를 조회하거나 원하는 페이지를 조회할 수 있다.

 "aggregations" : {
    "abnormal_status" : {
      "after_key" : {
        "date" : "2022-07-14",
        "name" : 2
      },
      "buckets" : [
        {
          "key" : {
            "date" : "2022-01-03",
            "name" : 0
          },
          "doc_count" : 1
        },
        {
          "key" : {
            "date" : "2022-05-30",
            "name" : 0
          },
          "doc_count" : 1
        }
        ... 이하생략

 

{
  "size":0,
  "aggs": {
    "abnormal_status" : {
      "composite": {
        "sources": [
         # time을 일별로 묶어줌, calendar_interval = day, week, hour..
          { "date": { "date_histogram": { "field": "time", "calendar_interval": "day", "format": "yyyy-MM-dd"}}},
          { "name": { "terms": { "field": "userNo" } } }
        ],
        "size": 10000,
        "after": #해당부분에 afterKey값을 넣어주면 그 위치부터 시작함
      }
    }
  }
}

 

※ 이외에 알아둘만한 집계 함수

percentiles > 해당 퍼센트에 해당하는 기준값이 얼마인지 알 수 있다.

    "percentiles_bucket" : {
      "values" : {
        "75.0" : 75,
        "80.0" : 80,
        "85.0" : 85,
        "90.0" : 90,
        "95.0" : 95,
        "99.0" : 99
      }
    }

script사용

아래와 같이 집계중 script를 사용할 수 있는 집계들이 있다.

아래 집계는 time 필드를 HH형태로 바꾸어 집계한 결과이다.

ex 20220805124333 > 12

  "aggs": {
    "hourly_privacy_count" : {
      "terms": {
        "script": {"source": "doc['time'].value.getHour()"}
      }
 }
반응형

+ Recent posts