오늘은 간단하게 클러스터 모니터링을 위한 API 몇개를 정리해본다.

 

  • http://es-host:9200/_cat/allocation?v -> 클러스터 디스크 현황
  • http://es-host:9200/_cluster/health?pretty -> 클러스터 헬스체크
  • http://es-host:9200/_cat/indices?v -> 인덱스 상태 확인
  • http://es-host:9200/_cat/shards -> 모든 샤드 상태 확인
  • http://es-host:9200/_cat/shards/{index_name}?v -> 특정 인덱스의 샤드 상태확인

 

https://brunch.co.kr/@alden/43

 

ElasticSearch status 바로 알기

ElasticSearch | 오늘은 ElasticSearch (이하 ES)의 status 에 대한 이야기를 해볼까 합니다. ES의 status는 무엇을 의미하는지, 그리고 어떤 값들이 있으며 어떻게 확인할 수 있는지 살펴보겠습니다. ES status ��

brunch.co.kr

 

posted by 여성게
:

 

 

[번역] Elasticsearch 퍼포먼스 튜닝 방법 - ebay

Elasticsearch에 대해 검색하다가 ebay에 퍼포먼스 튜닝방법에 대해 좋은 글이 있어서 간단하게 정리해봤다. 새롭게 알게된 사실이 많아서 좋았다. 정리 잘된 기술 블로그를 보는것은 책을 읽는거보�

wedul.site

 

posted by 여성게
:

이번에 다루어볼 포스팅은 도커로 ES를 띄우기전에 뭔가 커스텀한 이미지를 만들어서 올릴수없을까 하는 생각에 간단히 ES 기본 이미지에 한글 형태소 분석기(Nori) 플러그인이 설치가된 ES docker image를 커스텀하게 만들어보았다.

 

#Dockerfile

FROM docker.elastic.co/elasticsearch/elasticsearch:7.6.2

ENV ES_VOLUME=/usr/share/elasticsearch/data
ENV ES_BIN=/usr/share/elasticsearch/bin

RUN mkdir $ES_VOLUME/dictionary
RUN $ES_BIN/elasticsearch-plugin install --batch analysis-nori

 

간단히 설명하면, 베이스 이미지로 공식 elasticsearch image를 사용하였고, 나중에 사용자 사전이 위치할 도커 볼륨 디렉토리를 잡아주었고, 거기에 사전이 담기는 디렉토리를 생성했다. 그리고 마지막으로 한글 형태소분석기 플러그인을 설치하는 쉘을 실행시켰다. 이렇게 빌드된 elasticsearch image는 한글 형태소분석기가 이미 설치가된 elasticsearch image가 된다. 그래서 굳이 plugin directory를 마운트해서 직접 플러그인을 설치할 필요가 없다. 물론 추후에 필요에 의해서 설치해야한다면 어쩔수 없지만 말이다.

 

여기에 추후 더 커스텀할 내용을 넣으면 될듯하다.

posted by 여성게
:

오늘 다루어볼 내용은 Elasticsearch를 이용한 한글 자동완성 구현이다. 실습을 위한 Elasticsearch는 도커로 세팅을 진행할 것이다. 한글 형태소 분석기가 필요하기 때문에 Elasticsearch docker image를 조금 커스터마이징하여 한글 형태소 분석기(nori)가 설치된 ES 도커 이미지로 도커 컨테이너를 실행시킬 것이다.

 

ES 도커 이미지는 아래 링크를 참조해서 빌드해준다.

 

Elasticsearch - Elasticsearch custom docker image 빌드(엘라스틱서치 커스텀 도커 이미지 생성)

이번에 다루어볼 포스팅은 도커로 ES를 띄우기전에 뭔가 커스텀한 이미지를 만들어서 올릴수없을까 하는 생각에 간단히 ES 기본 이미지에 한글 형태소 분석기(Nori) 플러그인이 설치가된 ES docker image를 커스..

coding-start.tistory.com

docker run
#동의어 사전 사용을 위해 volume mount and data volume mount
> docker run --name elasticsearch -d -p 9200:9200 -p 9300:9300 \
  -e "discovery.type=single-node" \
  -v /home/deploy/elasticsearch_v/dictionary:/usr/share/elasticsearch/data/dictionary \
  -v /home/deploy/elasticsearch_v/data_v:/usr/share/elasticsearch/data \
  es_image_docker_hub

 

Elasticsearch index setting

토크나이저는 한글 형태소분석기인 노리(nori) 형태소 분석기를 이용했고, 자동완성 구현을 위해 edge_ngram filter를 이용하였다.

 

curl --location --request PUT 'localhost:9200/auto_complete' \
--header 'Content-Type: application/json' \
--data-raw '{
  "settings": {
    "index": {
      "analysis": {
        "analyzer": {
          "korean_analyzer": {
            "type": "custom",
            "tokenizer": "korean_tokenizer",
            "filter": [
              "lowercase",
              "korean_posfilter",
              "synonym_filter",
              "edge_ngram_filter_front",
              "edge_ngram_filter_back",
              "trim"
            ]
          }
        },
        "tokenizer": {
          "korean_tokenizer" : {
            "type" : "nori_tokenizer",
            "decompound_mode" : "mixed",
            "user_dictionary":"/usr/share/elasticsearch/data/dictionary/user_dict.txt"
          }
        },
        "filter": {
          "edge_ngram_filter_front": {
            "type": "edgeNGram",
            "min_gram": "1",
            "max_gram": "10",
            "side": "front"
          },
          "edge_ngram_filter_back": {
            "type": "edgeNGram",
            "min_gram": "1",
            "max_gram": "10",
            "side": "back"
          },
          "synonym_filter": {
            "type": "synonym",
            "lenient": true,
            "synonyms_path":"/usr/share/elasticsearch/data/dictionary/synonym.txt"
          },
          "korean_posfilter":{
                "type":"nori_part_of_speech",
                "stoptags":[
                    "E",
                    "IC",
                    "J",
                    "MAG",
                    "MM",
                    "NA",
                    "NR",
                    "SC",
                    "SE",
                    "SF",
                    "SP",
                    "SSC",
                    "SSO",
                    "SY",
                    "UNA",
                    "VA",
                    "VCN",
                    "VCP",
                    "XPN",
                    "XR",
                    "XSA",
                    "XSN",
                    "XSV"
                ]
            }
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "auto_complete": {
        "type": "text",
        "analyzer": "korean_analyzer"
      }
    }
  }
}'

 

만약 자동완성을 위한 필드에 색인할때, 생략할 품사들을 지정하기 위해서는 nori_part_of_speech 필터의 stoptags에 넣어주면 된다. 위 설정은 명사류 혹은 동사류만 색인되도록 품사지정을 하였다. 품사(nori_part_of_speech)에 대한 자세한 사항은 아래 링크를 참조하자.

 

 

Elasticsearch - 4.한글 형태소분석기(Nori Analyzer)

엘라스틱서치 혹은 솔라와 같은 검색엔진들은 모두 한글에는 성능을 발휘하기 쉽지 않은 검색엔진이다. 그 이유는 한글은 다른 언어와 달리 조사나 어미의 접미사가 명사,동사 등과 결합하기 ��

coding-start.tistory.com

 

색인 및 한글 자동완성 쿼리
#index document
curl --location --request POST 'http://localhost:9200/auto_complete/_doc' \
--header 'Content-Type: application/json' \
--data-raw '{
    "auto_complete" : "피자 주문할게요"
}'

 

위 요청으로 문서를 색인하고 아래 쿼리를 날려보자.

 

#match query
curl --location --request POST 'http://localhost:9200/auto_complete/_search' \
--header 'Content-Type: application/json' \
--data-raw '{
    "query" : {
        "match" : {
            "auto_complete" : {
                "query" : "피"
            }
        }
    }
}'

 

마지막으로 동의어를 넣기 위해서는 아래와 같이 index를 close 했다가 open해야한다. 아래 요청을 참조하자.

 

#index close
curl --location --request POST 'http://localhost:9200/auto_complete/_close' \
--data-raw ''
 
 
#index open
curl --location --request POST 'http://localhost:9200/auto_complete/_open' \
--data-raw ''

 

여기까지 아주 간단하게 한글 자동 완성을 구현해보았다. 사실 더 최적화할 것도 많고, 자소 분리등을 넣어서 자음만 넣어도 자동완성을 구현할 수도 있지만, 이번 포스팅에서는 그냥 한글 자동완성이 어떤 식으로 구현되는지 간단하게 다루어보았다.

posted by 여성게
:

 

파이프라인 집계(Pipeline Aggregations)는 다른 집계와 달리 쿼리 조건에 부합하는 문서에 대해 집계를 수행하는 것이 아니라, 다른 집계로 생성된 버킷을 참조해서 집계를 수행한다. 집계 또는 중첩된 집계를 통해 생성된 버킷을 사용해 추가적으로 계산을 수행한다고 보면 된다. 파이프라인 집계에는 부모(Parent), 형제(Sibling)라는 두 가지 유형이 있다.

 

파이프라인 집계를 수행할 때는 buckets_path 파라미터를 사용해 참조할 집계의 경로를 지정함으로써 체인 형식으로 집계 간의 연산이 이뤄진다. 파이프라인 집계는 모든 집계가 완료된 후에 생성된 버킷을 사용하기 때문에 하위 집계를 가질 수는 없지만 다른 파이프라인 집계와는 buckets_path를 통해 참조하도록 지정할 수 있다.

 

-형제 집계(Sibling)

형제 집계는 동일 선상의 위치에서 수행되는 새 집계를 의미한다. 즉, 형제 집계를 통해 수행되는 집계는 기존 버킷에 추가되는 형태가 아니라 동일 선상의 위치에서 새 집계가 생성되는 파이프라인 집계다. 형제 집계는 다음과 같은 집계들이 있다.

 

평균 버킷 집계(Avg Bucket Aggregation)
최대 버킷 집계(Max Bucket Aggregation)
최소 버킷 집계(Min Bucket Aggregation)
합계 버킷 집계(Sum Bucket Aggregation)
통계 버킷 집계(Stats Bucket Aggregation)
확장 통계 버킷 집계(Extended Stats Bucket Aggregation)
백분위수 버킷 집계(Percentiles Bucket Aggregation)
이동 평균 집계(Moving Average Aggregation)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
{
    "aggs":{
        "histo":{
            "date_histogram":{
                "field":"timestamp",
                "interval":"day"
            },
            "aggs":{ //중첩 집계 
                "bytes_sum":{
                    "sum":{
                        "field":"bytes"
                    }
                }
            }
        },
        "max_bytes":{ //파이프라인 집계
            "max_bucket":{
                "buckets_path":"histo>bytes_sum" //버킷 참조
            }
        }
    }
}
 
->result
{
    "took": 2,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 10001,
        "max_score": 0.0,
        "hits": []
    },
    "aggregations": {
        "histo": {
            "buckets": [
                {
                    "key_as_string": "2015-05-17T00:00:00.000Z",
                    "key": 1431820800000,
                    "doc_count": 1632,
                    "bytes_sum": {
                        "value": 4.14259902E8
                    }
                },
                {
                    "key_as_string": "2015-05-18T00:00:00.000Z",
                    "key": 1431907200000,
                    "doc_count": 2893,
                    "bytes_sum": {
                        "value": 7.88636158E8
                    }
                },
                {
                    "key_as_string": "2015-05-19T00:00:00.000Z",
                    "key": 1431993600000,
                    "doc_count": 2896,
                    "bytes_sum": {
                        "value": 6.65827339E8
                    }
                },
                {
                    "key_as_string": "2015-05-20T00:00:00.000Z",
                    "key": 1432080000000,
                    "doc_count": 2578,
                    "bytes_sum": {
                        "value": 8.78559106E8
                    }
                }
            ]
        },
        "max_bytes": {
            "value": 8.78559106E8,
            "keys": [
                "2015-05-20T00:00:00.000Z"
            ]
        }
    }
}
cs

 

위는 간단하게 2개의 집계를 중첩하였고, 형제 레벨로 histo 집계 밑의 bytes_sum의 버킷을 참조하여 최대값을 구하는 파이프라인 집계를 작성한 것이다. 결과값으로는 중첩된 집계결과와 마지막에 파이프라인의 집계가 나온다. 현재는 bytes_sum이 단일 메트릭 집계이기 때문에 집계 이름으로만 참조하고 있지만 stats 같은 다중 메트릭 집계일 경우 메트릭명까지 참조해줘야 한다. histo>bytes_sum.avg

 

Additional Sibling Aggregations

파이프라인 집계명 집계 쿼리
최대 버킷 집계 - 최대 값으로 버킷을 식별하고 버킷의 값과 키를 출력하는 형제 파이프 라인 집계입니다. 지정된 메트릭은 숫자 여야하고 형제 집계는 다중 버킷 집계 여야합니다.

{

  "max_bucket":{

    "bucket_path":"histo>bytes_sum"

  }

}

최소 버킷 집계 - 최소값으로 버킷을 식별하고 버킷의 값과 키를 모두 출력하는 형제 파이프 라인 집계이다. 지정된 메트릭은 숫자 여야하고 형제 집계는 다중 버킷 집계 여야한다.

{

  "min_bucket":{

    "bucket_path":"histo>bytes_sum"

  }

}

평균 버킷 집계 - 지정된 메트릭의 평균 값을 계산하는 파이프 라인 집계이다. 지정된 메트릭은 숫자 여야하고 형제 집계는 다중 버킷 집계여야한다.

{

  "avg_bucket":{

    "bucket_path":"histo>bytes_sum"

  }

}

통계 버킷 집계 - 모든 버킷에 대한 다양한 통계를 계산하는 형제 파이프 라인 집계이다. 지정된 메트릭은 숫자 여야하고 형제 집계는 다중 버킷 집계 여야한다.

{

  "stats_bucket":{

    "bucket_path":"histo>bytes_sum"

  }

}

확장 통계 버킷 집계 -

모든 버킷에 대한 다양한 통계를 계산하는 형제 파이프 라인 집계이다. 지정된 메트릭은 숫자 여야하고 형제 집계는 다중 버킷 집계 여야한다.

이 집계는 집계와 비교하여 몇 가지 통계 (제곱합, 표준 편차 등)를 제공한다.

{

  "extended_stats_bucket":{

    "bucket_path":"histo>bytes_sum"

  }

}

백분위수 버킷 집계 - 모든 버킷에서 백분위 수를 계산하는 형제 파이프 라인 집계이다.. 지정된 메트릭은 숫자 여야하고 형제 집계는 다중 버킷 집계 여야한다.

{

  "percentiles_bucket":{

    "bucket_path":"histo>bytes_sum"

  }

}

이동 평균 버킷 집계 - 이동 평균은 순차 데이터를 부드럽게하는 간단한 방법이다. 이동 평균은 일반적으로 주가 또는 서버 메트릭과 같은 시간 기반 데이터에 적용이다. 평활화는 고주파수 변동 또는 랜덤 노이즈를 제거하는 데 사용될 수 있으므로 계절 성과 같이 저주파수 추세를보다 쉽게 ​​시각화 할 수 있다.

다양한 옵션이 있으므로 자세한 사용법은 레퍼런스를 참고하자.

>https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-pipeline-movavg-aggregation.html

{

  "moving_avg_bucket":{

    "bucket_path":"histo>bytes_sum"

  }

}

 

이동 평균 버킷 집계는 부모에 histogram 혹은 date_histogram 집계가 있어야 한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
{
    "aggs":{
        "histo":{
            "date_histogram":{
                "field":"timestamp",
                "interval":"day"
            },
            "aggs":{
                "bytes_sum":{
                    "sum":{
                        "field":"bytes"
                    }
                },
                "moving_avg_agg":{
                    "moving_avg":{
                        "buckets_path":"bytes_sum"
                    }
                }
            }
        }
    }
}
 
->result
{
    "took": 7,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 10001,
        "max_score": 0.0,
        "hits": []
    },
    "aggregations": {
        "histo": {
            "buckets": [
                {
                    "key_as_string": "2015-05-17T00:00:00.000Z",
                    "key": 1431820800000,
                    "doc_count": 1632,
                    "bytes_sum": {
                        "value": 4.14259902E8
                    }
                },
                {
                    "key_as_string": "2015-05-18T00:00:00.000Z",
                    "key": 1431907200000,
                    "doc_count": 2893,
                    "bytes_sum": {
                        "value": 7.88636158E8
                    },
                    "moving_avg_agg": {
                        "value": 4.14259902E8
                    }
                },
                {
                    "key_as_string": "2015-05-19T00:00:00.000Z",
                    "key": 1431993600000,
                    "doc_count": 2896,
                    "bytes_sum": {
                        "value": 6.65827339E8
                    },
                    "moving_avg_agg": {
                        "value": 6.0144803E8
                    }
                },
                {
                    "key_as_string": "2015-05-20T00:00:00.000Z",
                    "key": 1432080000000,
                    "doc_count": 2578,
                    "bytes_sum": {
                        "value": 8.78559106E8
                    },
                    "moving_avg_agg": {
                        "value": 6.229077996666666E8
                    }
                }
            ]
        }
    }
}
cs

 

-부모 집계(Parent)

부모 집계는 집계를 통해 생성된 버킷을 사용해 계산을 수행하고, 그 결과를 기존 집계 결과에 반영한다. 집계의 종류는 아래와 같다.

 

파생 집계(Derivative Aggregation)
누적 집계(Cumulative Sum Aggregation)
버킷 스크립트 집계(Bucket Script Aggregation)
버킷 셀렉터 집계(Bucket Selector Aggregation)
시계열 차분 집계(Serial Differencing Aggregation)

 

아파치 웹 로그 등을 통해 수집된 데이터가 시간이 지남에 따라 변화하는 값의 변경폭 추이를 확인하고 싶은 경우 파생 집계를 활용할 수 있다. 파생 집계는 부모 히스토그램 또는 날짜 히스토그램 집계에서 지정된 메트릭의 파생값을 계산하는 상위 파이프라인 집계다. 이는 부모 히스토그램 집계 측정 항목에 대해 작동하고, 히스토그램 집계에 의한 각 버킷의 집계 값을 비교해서 차이를 계산한다. 반드시 지정된 메트릭은 숫자여야 하고, 상위에 해당하는 집계의 min_doc_count가 0보다 큰 값으로 설정되는 경우 일부 간격이 결과에서 생략될 수 있기에 min_doc_count 값을 0으로 설정해야 한다.

 

파생 집계의 경우에는 이처럼 선행되는 데이터가 존재하지 않으면 집계를 수행할 수 없는데, 실제 데이터를 다루다 보면 종종 노이즈가 포함되기도 하고, 필요한 필드에 값이 존재하지 않을 수 있다. 이러한 부분을 갭(Gap)이라고 할 수 있는데, 쉽게 말해 데이터가 존재하지 않는 부분을 의미한다.

 

갭(gap)이 발생되는 이유는 아래와 같다.

 

  1. 어느 하나의 버킷 안으로 포함되는 문서들에 요청된 필드가 포함되지 않은 경우
  2. 하나 이상의 버킷에 대한 쿼리와 일치하는 문서가 존재하지 않는 경우
  3. 다른 종속된 버킷에 값이 누락되어 계산된 메트릭이 값을 생성할 수 없는 경우

이러한 경우에는 파이프라인 집계에 원하는 동작을 알리는 메커니즘이 필요하다. 이 역할을하는 것이 갭 정책(gap_policy)이다. 모든 파이프라인 집계에서는 gap_policy 파라미터를 허용한다.

 

<갭정책>

skip 누락된 데이터를 버킷이 존재하지 않는 것으로 간주한다. 버킷을 건너뛰고 다음으로 사용 가능한 값을 사용해 계산을 계속해서 수행한다.
insert_zeros 누락된 값을 0으로 대체하며 파이프라인 집계 계산은 정상적으로 진행된다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
{
    "aggs":{
        "histo":{
            "date_histogram":{
                "field":"timestamp",
                "interval":"day"
            },
            "aggs":{
                "bytes_sum":{
                    "sum":{
                        "field":"bytes"
                    }
                },
                "sum_deriv":{
                    "derivative":{
                        "buckets_path":"bytes_sum"
                    }
                }
            }
        }
    }
}
 
->result
{
    "took": 5,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 10001,
        "max_score": 0.0,
        "hits": []
    },
    "aggregations": {
        "histo": {
            "buckets": [
                {
                    "key_as_string": "2015-05-17T00:00:00.000Z",
                    "key": 1431820800000,
                    "doc_count": 1632,
                    "bytes_sum": {
                        "value": 4.14259902E8
                    }
                },
                {
                    "key_as_string": "2015-05-18T00:00:00.000Z",
                    "key": 1431907200000,
                    "doc_count": 2893,
                    "bytes_sum": {
                        "value": 7.88636158E8
                    },
                    "sum_deriv": {
                        "value": 3.74376256E8
                    }
                },
                {
                    "key_as_string": "2015-05-19T00:00:00.000Z",
                    "key": 1431993600000,
                    "doc_count": 2896,
                    "bytes_sum": {
                        "value": 6.65827339E8
                    },
                    "sum_deriv": {
                        "value": -1.22808819E8
                    }
                },
                {
                    "key_as_string": "2015-05-20T00:00:00.000Z",
                    "key": 1432080000000,
                    "doc_count": 2578,
                    "bytes_sum": {
                        "value": 8.78559106E8
                    },
                    "sum_deriv": {
                        "value": 2.12731767E8
                    }
                }
            ]
        }
    }
}
cs

 

결과를 보면 파생 집계는 각 버킷 간의 차이를 값으로 보여준다. 첫번째 버킷은 이전 데이터가 존재하지 않으므로 파생 집계 결과가 포함되지 않는다.

 

Addtional Parent Aggregations

파이프라인 집계명 쿼리
파생 집계 - 상위 히스토그램 (또는 date_histogram) 집계에서 지정된 메트릭의 미분을 계산하는 상위 파이프 라인 집계이다. 지정된 메트릭은 숫자 여야하며 둘러싸는 막대 그래프는 ( 집계의 기본값 ) 으로 min_doc_count이 0으로 설정되어 있어야한다.

{

  "derivative":{

    "buckets_path":"bytes_sum"

  }

}

누적 집계 - 위 히스토그램 (또는 date_histogram) 집계에서 지정된 지표의 누적 합계를 계산하는 상위 파이프 라인 집계입니다. 지정된 메트릭은 숫자 여야하며 둘러싸는 막대 그래프는 ( 집계의 기본값 ) 으로 min_doc_count이 0으로 설정되어 있어야합니다 .

{

  "cumulative_sum":{

    "buckets_path":"bytes_sum"

  }

}

버킷 스크립트 집계 - 부모 다중 버킷 집계에서 지정된 메트릭에 대해 버킷 당 계산을 수행 할 수있는 스크립트를 실행하는 부모 파이프 라인 집계입니다. 지정된 메트릭은 숫자 여야하며 스크립트는 숫자 값을 반환해야합니다.

{

  "bucket_script":{

    "buckets_path":{

      "my_var1":"bytes_sum",

      "my_var2":"total_count"

    },

    "script":"params.my_var1/params.my_var2

  }

}

버킷 셀렉터 집계 - 현재 버킷을 상위 멀티 버킷 집계에 유지할지 여부를 결정하는 스크립트를 실행하는 상위 파이프 라인 집계입니다. 지정된 메트릭은 숫자 여야하며 스크립트는 부울 값을 반환해야합니다. 스크립트 언어 인 경우 expression숫자 반환 값이 허용됩니다. 이 경우 0.0은 그대로 평가되고 false 다른 모든 값은 true로 평가됩니다.

{

  "bucket_selector":{

    "buckets_path":{

      "my_var1":"bytes_sum",

      "my_var2":"total_count"

    },

    "script":"params.my_var1 > params.my_var2

  }

}

시계열 차분 집계 - 시계열의 값을 다른 시차 또는 기간에 차감하는 기술입니다. 예를 들어, 데이터 포인트 f (x) = f (x t )-f (x t-n ), 여기서 n은 사용되는 기간입니다.

{

  "serial_diff":{

    "buckets_path":"bytes_sum",

    "lag":"7"

  }

}

 

자세한 설명은 공식 레퍼런스를 참고하시길 바랍니다.

 

누적 집계

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
{
    "aggs":{
        "histo":{
            "date_histogram":{
                "field":"timestamp",
                "interval":"day"
            },
            "aggs":{
                "bytes_sum":{
                    "sum":{
                        "field":"bytes"
                    }
                },
                "sum_deriv":{
                      "cumulative_sum":{
                        "buckets_path":"bytes_sum"
                      }
                }
            }
        }
    }
}
 
->result
{
    "took": 4,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 10001,
        "max_score": 0.0,
        "hits": []
    },
    "aggregations": {
        "histo": {
            "buckets": [
                {
                    "key_as_string": "2015-05-17T00:00:00.000Z",
                    "key": 1431820800000,
                    "doc_count": 1632,
                    "bytes_sum": {
                        "value": 4.14259902E8
                    },
                    "sum_deriv": {
                        "value": 4.14259902E8
                    }
                },
                {
                    "key_as_string": "2015-05-18T00:00:00.000Z",
                    "key": 1431907200000,
                    "doc_count": 2893,
                    "bytes_sum": {
                        "value": 7.88636158E8
                    },
                    "sum_deriv": {
                        "value": 1.20289606E9
                    }
                },
                {
                    "key_as_string": "2015-05-19T00:00:00.000Z",
                    "key": 1431993600000,
                    "doc_count": 2896,
                    "bytes_sum": {
                        "value": 6.65827339E8
                    },
                    "sum_deriv": {
                        "value": 1.868723399E9
                    }
                },
                {
                    "key_as_string": "2015-05-20T00:00:00.000Z",
                    "key": 1432080000000,
                    "doc_count": 2578,
                    "bytes_sum": {
                        "value": 8.78559106E8
                    },
                    "sum_deriv": {
                        "value": 2.747282505E9
                    }
                }
            ]
        }
    }
}
cs

 

집계의 값을 계속 해서 누적하는 집계이다.

 

버킷 스크립트 집계

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
{
    "aggs":{
        "histo":{
            "date_histogram":{
                "field":"timestamp",
                "interval":"day"
            },
            "aggs":{
                "bytes_sum":{
                    "sum":{
                        "field":"bytes"
                    }
                },
                "sum_deriv":{
                      "bucket_script":{
                        "buckets_path":{
                          "my_var1":"bytes_sum",
                          "my_var2":"bytes_sum"
                        },
                        "script":"params.my_var1/params.my_var2"
                      }
                }
            }
        }
    }
}
 
->result
{
    "took": 106,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 10001,
        "max_score": 0.0,
        "hits": []
    },
    "aggregations": {
        "histo": {
            "buckets": [
                {
                    "key_as_string": "2015-05-17T00:00:00.000Z",
                    "key": 1431820800000,
                    "doc_count": 1632,
                    "bytes_sum": {
                        "value": 4.14259902E8
                    },
                    "sum_deriv": {
                        "value": 1.0
                    }
                },
                {
                    "key_as_string": "2015-05-18T00:00:00.000Z",
                    "key": 1431907200000,
                    "doc_count": 2893,
                    "bytes_sum": {
                        "value": 7.88636158E8
                    },
                    "sum_deriv": {
                        "value": 1.0
                    }
                },
                {
                    "key_as_string": "2015-05-19T00:00:00.000Z",
                    "key": 1431993600000,
                    "doc_count": 2896,
                    "bytes_sum": {
                        "value": 6.65827339E8
                    },
                    "sum_deriv": {
                        "value": 1.0
                    }
                },
                {
                    "key_as_string": "2015-05-20T00:00:00.000Z",
                    "key": 1432080000000,
                    "doc_count": 2578,
                    "bytes_sum": {
                        "value": 8.78559106E8
                    },
                    "sum_deriv": {
                        "value": 1.0
                    }
                }
            ]
        }
    }
}
cs

 

스크립트를 활용해 버킷의 결과 값을 스크립트로 조작가능하다.

 

버킷 셀렉터

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
{
    "aggs":{
        "histo":{
            "date_histogram":{
                "field":"timestamp",
                "interval":"day"
            },
            "aggs":{
                "bytes_sum":{
                    "sum":{
                        "field":"bytes"
                    }
                },
                "sum_deriv":{
                      "bucket_selector":{
                        "buckets_path":{
                          "my_var1":"bytes_sum",
                          "my_var2":"bytes_sum"
                        },
                        "script":"params.my_var1 < params.my_var2"
                      }
                }
            }
        }
    }
}
 
->result
{
    "took": 7,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 10001,
        "max_score": 0.0,
        "hits": []
    },
    "aggregations": {
        "histo": {
            "buckets": []
        }
    }
}
cs

 

불린을 결과값으로 하는 script를 작성해 결과에 노출시킬 버킷을 선택한다.

 

시계열 차분 집계

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
{
    "aggs":{
        "histo":{
            "date_histogram":{
                "field":"timestamp",
                "interval":"day"
            },
            "aggs":{
                "bytes_sum":{
                    "sum":{
                        "field":"bytes"
                    }
                },
                "thirtieth_difference":{
                      "serial_diff":{
                        "buckets_path":"bytes_sum",
                        "lag":2
                      }
                }
            }
        }
    }
}
 
->result
{
    "took": 1,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 10001,
        "max_score": 0.0,
        "hits": []
    },
    "aggregations": {
        "histo": {
            "buckets": [
                {
                    "key_as_string": "2015-05-17T00:00:00.000Z",
                    "key": 1431820800000,
                    "doc_count": 1632,
                    "bytes_sum": {
                        "value": 4.14259902E8
                    }
                },
                {
                    "key_as_string": "2015-05-18T00:00:00.000Z",
                    "key": 1431907200000,
                    "doc_count": 2893,
                    "bytes_sum": {
                        "value": 7.88636158E8
                    }
                },
                {
                    "key_as_string": "2015-05-19T00:00:00.000Z",
                    "key": 1431993600000,
                    "doc_count": 2896,
                    "bytes_sum": {
                        "value": 6.65827339E8
                    },
                    "thirtieth_difference": {
                        "value": 2.51567437E8
                    }
                },
                {
                    "key_as_string": "2015-05-20T00:00:00.000Z",
                    "key": 1432080000000,
                    "doc_count": 2578,
                    "bytes_sum": {
                        "value": 8.78559106E8
                    },
                    "thirtieth_difference": {
                        "value": 8.9922948E7
                    }
                }
            ]
        }
    }
}
cs

 

lag 값을 2로 주어 2번째 전 버킷과 현재 버킷의 차분을 계산하여 결과값에 포함시킨다.

 

여기까지 간단히 파이프라인 집계에 대해 다루어보았다. 사실 집계의 모든 것을 다 다루지는 못했다. 부족한 것은 공식레퍼런스와 서적을 더 참고해야겠다.

 

이번 포스팅말고 메트릭, 버킷 집계는 아래 링크를 참조하자.

2019/09/19 - [Search-Engine/Elasticsearch&Solr] - Elasticsearch - Aggregation API(엘라스틱서치 집계,메트릭(Metric Aggregations) 집계) -1

 

Elasticsearch - Aggregation API(엘라스틱서치 집계,메트릭(Metric Aggregations) 집계) -1

이번에 다루어볼 내용은 엘라스틱서치 Aggregation API이다. 해당 기능은 SQL과 비교하면 Group by의 기능과 아주 유사하다. 즉, 문서 데이터를 그룹화해서 각종 통계 지표 만들어 낼 수 있다. 엘라스틱서치의 집..

coding-start.tistory.com

2019/09/20 - [Search-Engine/Elasticsearch&Solr] - Elasticsearch - Aggregation API(엘라스틱서치 집계,버킷(Bucket Aggregations) 집계) -2

 

Elasticsearch - Aggregation API(엘라스틱서치 집계,버킷(Bucket Aggregations) 집계) -2

이번 포스팅은 엘라스틱서치 Aggregation(집계) API 두번째 글이다. 이번 글에서는 집계중 버킷집계(Bucket)에 대해 알아볼 것이다. 우선 버킷 집계는 메트릭 집계와는 다르게 메트릭을 계산하지 않고 버킷을 생..

coding-start.tistory.com

 

posted by 여성게
:

이번 포스팅은 엘라스틱서치 Aggregation(집계) API 두번째 글이다. 이번 글에서는 집계중 버킷집계(Bucket)에 대해 알아볼 것이다. 우선 버킷 집계는 메트릭 집계와는 다르게 메트릭을 계산하지 않고 버킷을 생성한다. 생성되는 버킷은 쿼리와 함께 수행되어 쿼리 결과에 따른 컨텍스트 내에서 집계가 이뤄진다. 이렇게 집계된 버킷은 또 다시 하위에서 집계를 한번 더 수행해서 집계된 결과에 대해 중첩된 집계 수행이 가능하다.

 

버킷이 생성되는 것은 집계 결과 집합을 메모리에 저장한다는 것이기 때문에 너무 많은 중첩 집계는 메모리 사용량을 점점 높히기에 성능에 악영향을 줄 수 있다. 이러한 문제때문에 엘라스틱서치는 설정으로 최대 버킷수를 조정할 수 있다. 

 

> search.max_buckets

 

버킷의 크기를 -1 혹은 10000 이상의 값을 지정할 경우 엘라스틱서치에서 경고메시지를 보낸다. 이 말은 여러가지 이유로 안정적인 집계 분석을 위해 버킷의 크기, 집계의 중첩양 등을 충분히 고려한 후에 집계 수행을 해야한다.

 

-범위 집계(Range Aggregations)

범위 집계는 사용자가 지정한 범위 내에서 집계를 수행하는 다중 버킷 집계이다. 집계가 수행되면 쿼리의 결과가 범위에 해당하는 지 체크하고, 범위에 해당되는 문서들에 대해서만 집계를 수행한다. from과 to 속성을 지정하고, to에 지정한 값을 결과에서 제외된다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
{
    "aggs":{
        "bytes_range":{
            "range":{
                "field":"bytes",
                "ranges":[{"from":1000,"to":2000}]
            }    
        }
    }
}
 
->result
{
    "took": 51,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 10001,
        "max_score": 0.0,
        "hits": []
    },
    "aggregations": {
        "bytes_range": {
            "buckets": [
                {
                    "key": "1000.0-2000.0",
                    "from": 1000.0,
                    "to": 2000.0,
                    "doc_count": 754
                }
            ]
        }
    }
}
cs

 

결과값에 대해 간단히 설명하면 "key"는 집계할 범위를 뜻하고, from은 시작,to는 끝,doc_count는 범위 내의 문서수를 의미한다. 또한 집계 쿼리에서 "ranges" 필드가 배열인 것으로 보아 여러개의 범위 지정이 가능한 것을 알 수 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
{
    "aggs":{
        "bytes_range":{
            "range":{
                "field":"bytes",
                "ranges":[
                    {"from":1000,"to":2000},
                    {"from":2000,"to":4000}
                ]
            }    
        }
    }
}
 
->result
{
    "took": 10,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 10001,
        "max_score": 0.0,
        "hits": []
    },
    "aggregations": {
        "bytes_range": {
            "buckets": [
                {
                    "key": "1000.0-2000.0",
                    "from": 1000.0,
                    "to": 2000.0,
                    "doc_count": 754
                },
                {
                    "key": "2000.0-4000.0",
                    "from": 2000.0,
                    "to": 4000.0,
                    "doc_count": 1004
                }
            ]
        }
    }
}
cs

 

그리고 키값을 더 의미있는 값으로 지정해 줄 수도 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
{
    "aggs":{
        "bytes_range":{
            "range":{
                "field":"bytes",
                "ranges":[
                    {"key":"small","from":1000,"to":2000},
                    {"key":"medium","from":2000,"to":4000}
                ]
            }    
        }
    }
}
 
->result
{
    "took": 3,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 10001,
        "max_score": 0.0,
        "hits": []
    },
    "aggregations": {
        "bytes_range": {
            "buckets": [
                {
                    "key": "small",
                    "from": 1000.0,
                    "to": 2000.0,
                    "doc_count": 754
                },
                {
                    "key": "medium",
                    "from": 2000.0,
                    "to": 4000.0,
                    "doc_count": 1004
                }
            ]
        }
    }
}
cs

 

-날짜 범위 집계

날짜 값을 범위로 집계를 수행한다. 날짜 포맷은 엘라스틱서치가 내부적으로 이해할 수 있는 날짜 타입이 와야한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
{
    "aggs":{
        "request_count_date":{
            "date_range":{
                "field":"timestamp",
                "ranges":[
                    {"from":"2015-05-04T05:16:00.000Z","to":"2015-05-18T05:16:00.000Z"}
                ]
            }    
        }
    }
}
 
->result
{
    "took": 6,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 10001,
        "max_score": 0.0,
        "hits": []
    },
    "aggregations": {
        "request_count_date": {
            "buckets": [
                {
                    "key": "2015-05-04T05:16:00.000Z-2015-05-18T05:16:00.000Z",
                    "from": 1.43071656E12, //시작날짜의 밀리초값
                    "from_as_string": "2015-05-04T05:16:00.000Z",
                    "to": 1.43192616E12, //끝날짜의 밀리초값
                    "to_as_string": "2015-05-18T05:16:00.000Z",
                    "doc_count": 2345 //날짜 범위에 해당되는 문서수
                }
            ]
        }
    }
}
cs

 

-히스토그램 집계(Histogram)

지정한 범위 간격으로 집계를 낸다. 만약 10000으로 지정하였다면, 0~10000(미포함), 10000~20000 의 간격으로 집계를 낸다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
{
    "aggs":{
        "bytes_histogram":{
            "histogram":{
                "field":"bytes", //집계필드
                "interval":10000, //집계 간격
                "min_doc_count":1 //최소 1개 이상되어야 결과에 포함
            }    
        }
    }
}
 
->result
{
    "took": 3,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 10001,
        "max_score": 0.0,
        "hits": []
    },
    "aggregations": {
        "bytes_histogram": {
            "buckets": [
                {
                    "key": 0.0,
                    "doc_count": 4196
                },
                {
                    "key": 10000.0,
                    "doc_count": 1930
                },
                {
                    "key": 20000.0,
                    "doc_count": 539
                },
                
                ...             
   
                
                {
                    "key": 5.43E7,
                    "doc_count": 24
                },
                {
                    "key": 6.525E7,
                    "doc_count": 2
                },
                {
                    "key": 6.919E7,
                    "doc_count": 2
                }
            ]
        }
    }
}
cs

 

대시보드에서 시각화할때도 아주 좋은 역할을 할듯하다.

 

-날짜 히스토그램 집계

날짜 히스토그램 집계는 분, 시간, 월, 연도를 구간으로 집계를 수행할 수 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
{
    "aggs":{
        "daily_request_count":{
            "date_histogram":{
                "field":"timestamp", //집계 필드
                "interval":"day", //집계 간격
                "format":"yyyy-MM-dd" //출력되는 날짜 포맷 변경
            }    
        }
    }
}
 
->result
{
    "took": 4,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 10001,
        "max_score": 0.0,
        "hits": []
    },
    "aggregations": {
        "daily_request_count": {
            "buckets": [
                {
                    "key_as_string": "2015-05-17",
                    "key": 1431820800000,
                    "doc_count": 1632
                },
                {
                    "key_as_string": "2015-05-18",
                    "key": 1431907200000,
                    "doc_count": 2893
                },
                {
                    "key_as_string": "2015-05-19",
                    "key": 1431993600000,
                    "doc_count": 2896
                },
                {
                    "key_as_string": "2015-05-20",
                    "key": 1432080000000,
                    "doc_count": 2578
                }
            ]
        }
    }
}
cs

 

key_as_string은 집계한 기준 날짜인데, UTC가 기본이며 "yyyy-MM-dd'T'HH:mm: ss.SSS 형식을 사용한다. 하지만 "format" 필드로 형식 포맷 변경이 가능하다. key는 집계 기준 날짜에 대한 밀리초이다.

 

구간 지정을 위해서 interval 속성을 사용하는데, 여기에 year, quarter, month, week, day, hour, minute, second 표현식을 사용할 수 있고, 더 세밀한 설정을 위해 30m(30분 간격), 1.5h(1시간 30분 간격) 같은 값도 사용가능하다. 

 

지금까지 사용한 예제에서 날짜는 모두 UTC 기준으로 기록됬다. 우리나라 사용자가 사용하기 위해서는 9시간을 더해서 계산해야 현재 시간이 되기 때문에 번거로울 수 있다. 하지만 엘라스틱서치는 타임존을 지원하기 때문에 한국 시간으로 변환된 결과를 받을 수 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
{
    "aggs":{
        "daily_request_count":{
            "date_histogram":{
                "field":"timestamp",
                "interval":"day",
                "format":"yyyy-MM-dd-HH:mm:ss",
                "time_zone":"+09:00"
            }    
        }
    }
}
 
->result
{
    "took": 3,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 10001,
        "max_score": 0.0,
        "hits": []
    },
    "aggregations": {
        "daily_request_count": {
            "buckets": [
                {
                    "key_as_string": "2015-05-17-00:00:00",
                    "key": 1431788400000,
                    "doc_count": 538
                },
                {
                    "key_as_string": "2015-05-18-00:00:00",
                    "key": 1431874800000,
                    "doc_count": 2898
                },
                {
                    "key_as_string": "2015-05-19-00:00:00",
                    "key": 1431961200000,
                    "doc_count": 2902
                },
                {
                    "key_as_string": "2015-05-20-00:00:00",
                    "key": 1432047600000,
                    "doc_count": 2862
                },
                {
                    "key_as_string": "2015-05-21-00:00:00",
                    "key": 1432134000000,
                    "doc_count": 799
                }
            ]
        }
    }
}
cs

 

타임존과는 다르게 offset을 사용해 집계 기준이 되는 날짜 값의 조정이 가능하다. 위에서 데일리로 집계했을 때, 00시 기준이었는데, 3시를 기준으로 하고 싶다면 아래와 같이 사용하면 된다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
{
    "aggs":{
        "daily_request_count":{
            "date_histogram":{
                "field":"timestamp",
                "interval":"day",
                "format":"yyyy-MM-dd-HH:mm:ss",
                "offset":"+3h"
            }    
        }
    }
}
 
->result
{
    "took": 4,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 10001,
        "max_score": 0.0,
        "hits": []
    },
    "aggregations": {
        "daily_request_count": {
            "buckets": [
                {
                    "key_as_string": "2015-05-17-03:00:00",
                    "key": 1431831600000,
                    "doc_count": 1991
                },
                {
                    "key_as_string": "2015-05-18-03:00:00",
                    "key": 1431918000000,
                    "doc_count": 2898
                },
                {
                    "key_as_string": "2015-05-19-03:00:00",
                    "key": 1432004400000,
                    "doc_count": 2895
                },
                {
                    "key_as_string": "2015-05-20-03:00:00",
                    "key": 1432090800000,
                    "doc_count": 2215
                }
            ]
        }
    }
}
cs

 

-텀즈 집계(terms)

텀즈 집계는 버킷이 동적으로 생성되는 다중 버킷 집계이다. 집계 시 지정한 필드에 대해 빈도수가 높은 텀의 순위로 결과가 반환된다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
{
    "aggs":{
        "request_count_country":{
            "terms":{
                "field":"geoip.country_name.keyword"
            }    
        }
    }
}
 
->result
{
    "took": 8,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 10001,
        "max_score": 0.0,
        "hits": []
    },
    "aggregations": {
        "request_count_country": {
            "doc_count_error_upper_bound": 48,
            "sum_other_doc_count": 2334,
            "buckets": [
                {
                    "key": "United States",
                    "doc_count": 3974
                },
                {
                    "key": "France",
                    "doc_count": 855
                },
                {
                    "key": "Germany",
                    "doc_count": 510
                },
                {
                    "key": "Sweden",
                    "doc_count": 440
                },
                {
                    "key": "India",
                    "doc_count": 428
                },
                {
                    "key": "China",
                    "doc_count": 416
                },
                {
                    "key": "United Kingdom",
                    "doc_count": 276
                },
                {
                    "key": "Spain",
                    "doc_count": 227
                },
                {
                    "key": "Canada",
                    "doc_count": 224
                },
                {
                    "key": "Russia",
                    "doc_count": 214
                }
            ]
        }
    }
}
cs

 

집계 필드는 "geoip.country_name" 필드인데, 해당 필드는 text와 keyword 타입 두개를 가지는 필드이며, 집계 필드로 "*.keyword"로 지정하였다. 이유는 text 데이터 타입의 경우 형태소 분석이 들어가기에 집계할때는 형태소 분석이 없는 keyword 데이터 타입을 사용해야만 한다. 물론 text 타입이 안되는 건 아니지만, 성능은.. 최악이 될것이다.

 

결과 값에 대해 설명하자면 "doc_count_error_upper_bound"는 문서 수에 대한 오류 상한선이다. 오류 상한선이 있는 이유는 각 샤드별로 계산되는 집계의 성능을 고려해 근사치를 계산하기에 문서 수가 정확하지 않아 최대 오류 상한선을 보여준다. "sum_other_doc_count"는 결과에 포함되지 않은 모든 문서수를 뜻한다.(size를 늘려 결과에 더 많은 집계 데이터를 포함시키면 된다. terms 안의 field와 같은 레벨로 size 옵션을 주면 된다.) key는 집계 필드 값이고, doc_count는 같은 필드 값의 문서수이다.

 

여기서 "doc_count_error_upper_bound" 값에 대해 조금 더 자세히 다루어보면, 내부 집계 처리 플로우는 각 샤드에서 집계를 한후에 모든 결과를 병합해서 집계 결과를 최종으로 반환한다. 하지만 아래와 같은 상황이 있다고 해보자.

  샤드 A 샤드 B 샤드 C
1 Product A(25) Product A(30) Product A(45)
2 Product B(18) Product B(25) Product C(44)
3 Product C(25)    

 

청크의 분포가 위와 같다라고 가정하고 집계 시 사이즈를 2로 지정하면 아래와 같은 결과를 반환할 것이다.

 

1 Product A(100)
2 Product B(43)
3 Product C(44)

 

결과는 나왔지만, Product C의 값에 오차가 생겼다. 즉, 쿼리 작성시 적절히 size값을 정해서 오차를 줄이거나 혹은 전부 포함시켜야한다. 하지만 역시나 사이즈를 키우면 키울 수록 집계 비용은 올라갈 것이다. 즉 위에서는 doc_count_error_upper_bound 값이 25가 될것이다.

 

집계와 샤드 크기

텀즈 집계가 수행될 때 각 샤드에게 최상위 버킷을 제공하도록 요청한 후에 모든 샤드로부터 결과를 받을 때까지 기다린다. 결과를 기다리다가 모든 샤드로부터 결과를 받으면 설정된 size에 맞춰 하나로 병합한 후 결과를 반환한다.

각 샤드는 size에 해당되는 갯수로 집계 결과를 반환하지 않는다. 각 샤드에서는 정확성을 위해 size의 크기가 아닌 샤드 크기를 이용한 경험적인 방법(샤드 크기*1.5+10)을 사용해 내부적으로 집계를 수행하는데, 텀즈 집계 결과로 받을 텀의 개수를 정확하게 파악할 수 있는 경우에는 shard_size 속성을 사용해 각 샤드에서 집계할 크기를 직접 지정해 불필요한 연산을 줄이면서 정확도를 높힐 수 있다.

앞서 설명한 바와 같이 shard_size가 기본값 -1로 되어있다면 엘라스틱서치가 샤드 크기를 기준으로 자동으로 추정한다. 만약 shard_size를 직접 설정할 경우에는 size보다 작은 값은 설정할 수 없다.

 

여기까지 간단히 버킷집계를 다루어보았고, 다음 포스팅에 이어 파이프라인 집계부터 다루어볼 것이다.

 

2019/09/19 - [Search-Engine/Elasticsearch&Solr] - Elasticsearch - Aggregation API(엘라스틱서치 집계,메트릭(Metric Aggregations) 집계) -1

 

Elasticsearch - Aggregation API(엘라스틱서치 집계,메트릭(Metric Aggregations) 집계) -1

이번에 다루어볼 내용은 엘라스틱서치 Aggregation API이다. 해당 기능은 SQL과 비교하면 Group by의 기능과 아주 유사하다. 즉, 문서 데이터를 그룹화해서 각종 통계 지표 만들어 낼 수 있다. 엘라스틱서치의 집..

coding-start.tistory.com

2019/09/20 - [Search-Engine/Elasticsearch&Solr] - Elasticsearch - Aggregation API(엘라스틱서치 집계,파이프라인(Pipeline Aggregations) 집계) -3

 

Elasticsearch - Aggregation API(엘라스틱서치 집계,파이프라인(Pipeline Aggregations) 집계) -3

파이프라인 집계(Pipeline Aggregations)는 다른 집계와 달리 쿼리 조건에 부합하는 문서에 대해 집계를 수행하는 것이 아니라, 다른 집계로 생성된 버킷을 참조해서 집계를 수행한다. 집계 또는 중첩된 집계를..

coding-start.tistory.com

 

posted by 여성게
:

이번에 다루어볼 내용은 엘라스틱서치 Aggregation API이다. 해당 기능은 SQL과 비교하면 Group by의 기능과 아주 유사하다. 즉, 문서 데이터를 그룹화해서 각종 통계 지표 만들어 낼 수 있다.

 

엘라스틱서치의 집계(Aggregation)

통계 분석을 위한 프로그램은 아주 많다. 하지만 실시간에 가깝게 어떠한 대용량의 데이터를 처리하여 분석 결과를 내놓은 프로그램은 많지 않다. 즉, RDBMS이나 하둡등의 대용량 데이터를 적재하고 배치등을 돌려 분석을 내는 것이 대부분이다. 하지만 엘라스틱서치는 많은 양의 데이터를 조각내어(샤딩)내어 관리하며 그 덕분에 다른 분석 프로그램보다 거의 실시간에 가까운 통계 결과를 만들어낼 수 있다.

 

하지만 집계기능은 일반 검색 기능보다 훨씬 더 많은 리소스를 소모한다. 성능 문제를 어느정도 효율적으로 해결하기 위해서는 캐시를 적절히 이용해야 하는 것이다. 물론 우리가 직접적으로 캐시를 조작하는 API를 사용하거나 하지는 않지만 어느정도 설정으로 조정가능하다. 그렇다면 엘라스틱서치에서 사용하는 캐시의 종류가 뭐가 있는지 간단히 알아보자.

 

캐시 종류 설명에 앞서 우선 엘라스틱서치의 캐시를 이용하면 질의의 결과를 캐시에 두고 다음에 동일한 요청이 오면 다시 한번 요청을 처리하는 것이 아닌 캐시에 있는 결과값을 그대로 돌려준다. 보통 캐시의 크기는 일반적으로 힙 메모리의 1%로 정도를 할당하며, 캐시에 없는 질의의 경우 성능 향상에 별다른 도움이 되지 못한다. 만약 엘라스틱서치가 사용하는 캐시 크기를 키우고 싶다면 아래와 같은 설정이 가능하다.

 

~/elasticsearch.yml

indices.requests.cache.size: n%

 

여기서 퍼센트(%)는 엘라스틱서치가 사용하는 힙메모리 중 몇 퍼센트를 나타내는 것이다. 다음은 엘라스틱서치가 사용하는 캐시 종류이다.

 

캐시명 설명
Node query Cache

노드의 모든 샤드가 공유하는 LRU(Least-Recently-Used)캐시다. 캐시 용량이 가득차면 사용량이 가장 적은 데이터를 삭제하고 새로운 결과값을 캐싱한다.

쿼리 캐싱 사용여부는 elasticsearch.yml 파일에 아래 옵션을 추가한다. 기본값은 true이다.

index.queries.cache.enabled: true

Shard request Cache 샤드는 데이터를 분산 저장하기 위한 단위로서, 사실 그 자체가 온전한 기능을 가지는 인덱스라고 볼 수 있다. 그래서 우리는 조회 기능을 특정 샤드에 요청해서 그 샤드에 있는 결과값만 얻어올 수 있는 이유가 그렇다. Shard request Cache는 바로 이 샤드에서 수행된 쿼리의 결과를 캐싱한다. 샤드의 내용이 변경되면 캐시도 삭제하기 때문에 문서 수정이 빈번한 인덱스에서는 오히려 성능 저하가 있을 수 있다.
Field data Cache 엘라스틱서치가 필드에서 집계 연산을 수행할 때는 모든 필드 값을 메모리에 로드한다. 이러한 이유로 엘라스틱서치에서 계산되는 집계 쿼리는 성능적인 측면에서 비용이 상당하다. Field data Cache는 집계 계산동안 필드의 값을 메모리에 보관한다.

 

Aggregation API

 

집계 쿼리 구조

 

GET>http://localhost:9200/indexName/_search?size=0

1
2
3
4
5
6
7
8
9
10
"aggregations":{
    "<aggregation_name>":{
        "<aggregation_type>":{
            "<aggregation_body>"
        }
        [,"meta":{[<meta_data_body>]}]?
        [,"aggregations":{[<sub_aggregation>]+}]?
    }
    ,[,"<aggregation_name_2>:{...}"]*
}
cs

 

집계쿼리는 위와 같은 구조를 갖는다. 각각의 키값에 대한 설명은 직접 예제 쿼리를 통해 다루어볼 것이다. 엘라스틱서치의 집계 기능이 강력한 이유중 하나는 위의 쿼리에서 보듯 여러 집계를 중첩하여 더 고도화된 데이터를 반환할 수 있다는 점이다. 물론 중첩이 될수록 성능은 떨어지지만 더 다양한 데이터를 집계할 수 있다. 또한 URL 요청을 보면 맨뒤에 size=0이 보일 것이다. 해당 쿼리스트링을 보내지 않으면 집계 스코프 대상(query)의 결과도 노출되니 집계 결과만 보고 싶다면 size=0으로 지정해주어야 한다.

 

집계 Scope

집계 API의 전체 요청 JSON구조를 보면 아래와 같다.

 

GET> http://localhost:9200/apache-web-log/_search?size=0

1
2
3
4
5
6
7
8
9
10
11
12
13
{
    "query":{
        "match_all":{}
    },
    "aggs":{
        "region_count":{
            "terms":{
                "field":"geoip.region_name.keyword",
                "size":20
            }
        }
    }
}
cs

 

위에 query라는 필드가 하나더 존재하는데, 해당 쿼리를 통해 나온 결과값을 이용하여 집계를 내겠다라는 집계 대상이 되는 Scope를 query를 이용하여 지정한다. 참고로 aggregations는 aggs로 줄여서 필드명을 작성할 수 있다. 그렇다면 아래와 같은 쿼리는 어떠한 결과를 낼까?

 

GET> http://localhost:9200/apache-web-log/_search?size=0

1
2
3
4
5
6
7
8
9
10
11
{
    "size":0,
    "aggs":{
        "region_count":{
            "terms":{
                "field":"geoip.region_name.keyword",
                "size":3
            }
        }
    }
}
cs

 

쿼리가 생략되면 내부적으로 match_all 쿼리를 수행한다. 또한 이러한 경우도 있다. 한번의 집계 쿼리를 통해 사용자가 지정한 질의에 해당하는 문서들 집계를 수행하고 전체 문서에 대해서도 집계를 수행해야 하는 경우는 아래와 같이 글로벌 버킷을 사용하면 된다.

 

GET> http://localhost:9200/apache-web-log/_search?size=0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
    "query":{
        "match":{
            "geoip.region_name":"California"
        }
    },
    "aggs":{
        "region_count":{
            "terms":{
                "field":"geoip.region_name.keyword",
                "size":3
            }
        },
        "global_aggs":{
            "global":{},
            "aggs":{
                "all_doc_aggs":{
                    "terms":{
                        "field":"geoip.region_name.keyword",
                        "size":3
                    }
                }
            }
        }
    }
}
cs

 

우선 region_name이 California인 질의의 결과를 이용하여 region_count라는 집계를 수행하고 이것 이외로 global_aggs 글로벌 버킷의 all_doc_aggs 집계를 전체 문서를 대상으로 한번더 수행한다. 결과는 아래와 같다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
{
    "took": 10,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 756,
        "max_score": 0,
        "hits": []
    },
    "aggregations": {
        "global_aggs": {
            "doc_count": 10001,
            "all_doc_aggs": {
                "doc_count_error_upper_bound": 77,
                "sum_other_doc_count": 5729,
                "buckets": [
                    {
                        "key": "California",
                        "doc_count": 756
                    },
                    {
                        "key": "Texas",
                        "doc_count": 588
                    },
                    {
                        "key": "Virginia",
                        "doc_count": 424
                    }
                ]
            }
        },
        "region_count": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
                {
                    "key": "California",
                    "doc_count": 756
                }
            ]
        }
    }
}
cs

 

그렇다면 집계의 종류에는 무엇이 있을까?

 

집계 종류 설명
버킷 집계 쿼리 결과로 도출된 문서 집합에 대해 특정 기준으로 나눈 다음 나눠진 문서들에 대한 산술 연산을 수행한다. 이때 나눠진 문서들의 모음들이 각 버컷에 해당된다.
메트릭 집계 쿼리 결과로 도출된 문서 집합에서 필드의 값을 더하거나 평균을 내는 등의 산술 연산을 수행한다.
파이프라인 집계 다른 집계 또는 관련 메트릭 연산의 결과를 집계한다.
행렬 집계 버킷 대상이 되는 문서의 여러 필드에서 추출한 값으로 행렬 연산을 수행한다. 이를 토대로 다양한 통계정보를 제공한다.

 

이제 위의 집계 종류에 대하여 하나하나 간단히 다루어보자.

 

메트릭 집계

메트릭 집계(Metrics Aggregations)를 사용하면 특정 필드에 대해 합이나 평균을 계산하거나 다른 집계와 중첩해서 결과에 대해 특정 필드의 _score 값에 따라 정렬을 수행하거나 지리 정보를 통해 범위 계산을 하는 등의 다양한 집계를 수행할 수 있다. 이름에서도 알 수 있듯이 정수 또는 실수와 같이 숫자 연산을 할 수 있는 값들에 대한 집계를 수행한다.

 

메트릭 집계는 또한 단일 숫자 메트릭 집계와 다중 숫자 메트릭 집계로 나뉘는데, 단일 숫자 메트릭 집계는 집계를 수행한 결과값이 하나라는 의미로 sum과 avg 등이 속한다. 다중 숫자 메트릭 집계는 집계를 수행한 결과값이 여러개가 될 수 있고, stats나 geo_bounds가 이에 속한다.

 

-합산집계(sum)

합산집계는 단일 숫자 메트릭 집계에 해당한다.

 

apache 로그에 유입되는 데이터의 바이트 총합을 구하는 집계 쿼리이다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
{
    "aggs":{
        "total_bytes":{
            "sum":{
                "field":"bytes"
            }
        }
    }
}
 
->result
{
    "took": 12,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 10001,
        "max_score": 0,
        "hits": []
    },
    "aggregations": {
        "total_bytes": {
            "value": 2747282505
        }
    }
}
cs

 

만약 전체 데이터가 아닌 쿼리를 날려 매치되는 문서를 집계하기 위해서 특정 지역에서 유입된 apache 로그를 검색해 그 결과로 bytes 수를 총합하는 쿼리는 아래와 같다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
{
    "query":{
        "constant_score":{
            "filter":{
                "match":{
                    "geoip.city_name":"Paris"
                }
            }
        }
    },
    "aggs":{
        "total_bytes":{
            "sum":{
                "field":"bytes"
            }
        }
    }
}
 
->result
{
    "took": 3,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 21,
        "max_score": 0,
        "hits": []
    },
    "aggregations": {
        "total_bytes": {
            "value": 428964
        }
    }
}
cs

 

논외의 이야기이지만, 스코어 점수가 필요없는 어떠한 검색에 constant_score 쿼리를 사용하면 성능상 이슈가 있다. 자주 사용되는 필터 쿼리는 엘라스틱 서치에서 캐시하므로 성능에 이점이 있을 수 있다. 만약 위의 쿼리에서 바이트를 KB나 MB,GB 단위로 보고 싶다면 어떻게 하면 좋을까? 사실 집계 쿼리에 데이터 크기 단위를 조정하는 기능은 없다. 하지만 script를 이용하면 집계되는 데이터를 원하는 단위로 변환이 가능하다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
    "query":{
        "constant_score":{
            "filter":{
                "match":{
                    "geoip.city_name":"Paris"
                }
            }
        }
    },
    "aggs":{
        "total_bytes":{
            "sum":{
                "script":{
                    "lang":"painless",
                    "source":"doc.bytes.value"
                }
            }
        }
    }
}
cs

 

해당 쿼리는 위의 쿼리와 동일한 결과를 내놓는다. 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
{
    "query":{
        "constant_score":{
            "filter":{
                "match":{
                    "geoip.city_name":"Paris"
                }
            }
        }
    },
    "aggs":{
        "total_bytes":{
            "sum":{
                "script":{
                    "lang":"painless",
                    "source":"doc.bytes.value / params.divice_value",
                    "params":{
                        "divice_value":1000
                    }
                }
            }
        }
    }
}
 
->result
{
    "took": 30,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 21,
        "max_score": 0,
        "hits": []
    },
    "aggregations": {
        "total_bytes": {
            "value": 422
        }
    }
}
cs

 

이렇게 스크립트를 이용하면 결과값을 일부 후처리할 수 있다. 하지만 결과가 조금이상하다. 428964/1000 인데 422가 됬다. 분명 428이 되야하는데 말이다. 그 이유는 모든 합산 값에 대한 나누기가 아니라 각 문서의 개별적인 값을 1000으로 나눈 후에 더했기 때문이다. 즉, 1000보다 작은수는 모두 0이 되어 합산이 되었다. 이 문제를 해결하기 위해서는 정수가 아닌 실수로 값을 계산해야한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
{
    "query":{
        "constant_score":{
            "filter":{
                "match":{
                    "geoip.city_name":"Paris"
                }
            }
        }
    },
    "aggs":{
        "total_bytes":{
            "sum":{
                "script":{
                    "lang":"painless",
                    "source":"doc.bytes.value / (double)params.divice_value",
                    "params":{
                        "divice_value":1000
                    }
                }
            }
        }
    }
}
 
->result
{
    "took": 18,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 21,
        "max_score": 0,
        "hits": []
    },
    "aggregations": {
        "total_bytes": {
            "value": 428.96399999999994
        }
    }
}
cs

 

-평균 집계(avg)

평균 집계는 단일 숫자 메트릭 집계에 해당한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
{
    "query":{
        "constant_score":{
            "filter":{
                "match":{
                    "geoip.city_name":"Paris"
                }
            }
        }
    },
    "aggs":{
        "avg_bytes":{
            "avg":{
                "field":"bytes"
            }
        }
    }
}
 
->result
{
    "took": 2,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 21,
        "max_score": 0,
        "hits": []
    },
    "aggregations": {
        "total_bytes": {
            "value": 20426.85714285714
        }
    }
}
cs

 

-최소값 집계(min)

최소값 집계는 단일 숫자 메트릭 집계에 해당한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
{
    "query":{
        "constant_score":{
            "filter":{
                "match":{
                    "geoip.city_name":"Paris"
                }
            }
        }
    },
    "aggs":{
        "min_bytes":{
            "min":{
                "field":"bytes"
            }
        }
    }
}
 
->result
{
    "took": 3,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 21,
        "max_score": 0,
        "hits": []
    },
    "aggregations": {
        "min_bytes": {
            "value": 1015
        }
    }
}
cs

 

최대값 집계는 aggregation_type을 max로 바꾸어주면 된다.

 

-개수집계(count)

개수집계는 단일 숫자 메트릭 집계에 해당한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
{
    "query":{
        "constant_score":{
            "filter":{
                "match":{
                    "geoip.city_name":"Paris"
                }
            }
        }
    },
    "aggs":{
        "count_bytes":{
            "value_count":{
                "field":"bytes"
            }
        }
    }
}
 
->result
{
    "took": 3,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 21,
        "max_score": 0,
        "hits": []
    },
    "aggregations": {
        "count_bytes": {
            "value": 21
        }
    }
}
cs

 

-통계집계(Stats)

통계집계는 결과값이 여러 개인 다중 숫자 메트릭 집계에 해당한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
{
    "query":{
        "constant_score":{
            "filter":{
                "match":{
                    "geoip.city_name":"Paris"
                }
            }
        }
    },
    "aggs":{
        "stats_bytes":{
            "stats":{
                "field":"bytes"
            }
        }
    }
}
 
->result
{
    "took": 3,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 21,
        "max_score": 0,
        "hits": []
    },
    "aggregations": {
        "stats_bytes": {
            "count": 21,
            "min": 1015,
            "max": 53270,
            "avg": 20426.85714285714,
            "sum": 428964
        }
    }
}
cs

 

count,min,max,avg,sum 등 한번에 모든 집계 결과를 받을 수 있다.

 

-확장 통계 집계(extended Stats)

확장 통계 집계는 결과값이 여러 개인 다중 숫자 메트릭 집계에 해당한다. 앞의 통계 집계를 확장해서 표준편차 같은 통계값이 추가된다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
{
    "query":{
        "constant_score":{
            "filter":{
                "match":{
                    "geoip.city_name":"Paris"
                }
            }
        }
    },
    "aggs":{
        "count_bytes":{
            "extended_stats":{
                "field":"bytes"
            }
        }
    }
}
 
->result
{
    "took": 4,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 21,
        "max_score": 0,
        "hits": []
    },
    "aggregations": {
        "count_bytes": {
            "count": 21,
            "min": 1015,
            "max": 53270,
            "avg": 20426.85714285714,
            "sum": 428964,
            "sum_of_squares": 18371748404,
            "variance": 457588669.3605442,
            "std_deviation": 21391.32229107271,
            "std_deviation_bounds": {
                "upper": 63209.501725002556,
                "lower": -22355.787439288277
            }
        }
    }
}
cs

 

-카디널리티 집계(Cardinality)

카디널리티 집계는 단일 숫자 메트릭 집계에 해당한다. 개수 집합과 유사하게 횟수를 계산하는데, 중복된 값은 제외한 고유한 값에 대한 집계를 수행한다. 하지만 모든 문서에 대해 중복된 값을 집계하는 것은 성능에 큰 영향을 줄 수 있기에 근사치를 통해 집계한다. 근사치를 구하기 위해 HyperLogLog++ 알고리즘 기반으로 동작한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
{
    "query":{
        "bool":{
            "must":[
                {
                    "match":{
                        "geoip.country_name":"United"    
                    }
                },
                {
                    "match":{
                        "geoip.country_name":"States"
                    }
                }
            ]
        }
    },
    "aggs":{
        "us_city_names":{
            "cardinality":{
                "field":"geoip.city_name.keyword"
            }
        }
    }
}
 
->result
{
    "took": 25,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 3974,
        "max_score": 0,
        "hits": []
    },
    "aggregations": {
        "us_city_names": {
            "value": 206
        }
    }
}
cs

 

-백분위 수 집계(Percentiles)

역시나 근사치이고 TDigest 알고리즘을 이용한다. 카디날리티 집계와 마찬가지로 문서들의 집합 크기각 작을 수록 정확도는 높아지고, 문서의 집합이 클수록 오차범위가 늘어난다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
{
    "query":{
        "constant_score":{
            "filter":{
                "match":{
                    "geoip.city_name":"Paris"
                }
            }
        }
    },
    "aggs":{
        "bytes_percentiles":{
            "percentiles":{
                "field":"bytes"
            }    
        }
    }
}
 
->result
{
    "took": 14,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 21,
        "max_score": 0,
        "hits": []
    },
    "aggregations": {
        "bytes_percentiles": {
            "values": {
                "1.0": 1015,
                "5.0": 1015,
                "25.0": 3638,
                "50.0": 6146,
                "75.0": 50662.75,
                "95.0": 53270,
                "99.0": 53270
            }
        }
    }
}
cs

 

아래와 같이 백분율을 명시할 수도 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
{
    "query":{
        "constant_score":{
            "filter":{
                "match":{
                    "geoip.city_name":"Paris"
                }
            }
        }
    },
    "aggs":{
        "bytes_percentiles":{
            "percentiles":{
                "field":"bytes",
                "percents":[0,10,20,30,40,50,60,70,80,90,100]
            }    
        }
    }
}
 
->result
{
    "took": 2,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 21,
        "max_score": 0,
        "hits": []
    },
    "aggregations": {
        "bytes_percentiles": {
            "values": {
                "0.0": 1015,
                "10.0": 1015,
                "20.0": 3638,
                "30.0": 4629.2,
                "40.0": 4877,
                "50.0": 6146,
                "60.0": 17147,
                "70.0": 37258.399999999994,
                "80.0": 52315,
                "90.0": 52697,
                "100.0": 53270
            }
        }
    }
}
cs

 

-백분위 수 랭크 집계

위의 랭크 집계와는 달리 특정 값을 주고 어느 백분위 범위에 속하는지를 결과값으로 돌려준다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
{
    "query":{
        "constant_score":{
            "filter":{
                "match":{
                    "geoip.city_name":"Paris"
                }
            }
        }
    },
    "aggs":{
        "bytes_percentiles_rank":{
            "percentile_ranks":{
                "field":"bytes",
                "values":[4000,6900]
            }    
        }
    }
}
 
->result
{
    "took": 5,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 21,
        "max_score": 0,
        "hits": []
    },
    "aggregations": {
        "bytes_percentiles_rank": {
            "values": {
                "4000.0": 26.592105768861217,
                "6900.0": 53.03370689244701
            }
        }
    }
}
cs

 

-지형 경계 집계

지형 좌표를 포함하고 있는 필드에 대해 해당 지역 경계 상자를 계산하는 메트릭 집계다. 해당 집계를 사용하기 위해서는 계산하려는 필드의 타입이 geo_point여야 한다.

 

 

필드 매핑타입이다.

 

해당 필드에 들어간 값의 예제이다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
{
    "aggs":{
        "viewport":{
            "geo_bounds":{
                "field":"geoip.location",
                "wrap_longitude":true
            }    
        }
    }
}
 
->result
{
    "took": 14,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 10001,
        "max_score": 0,
        "hits": []
    },
    "aggregations": {
        "viewport": {
            "bounds": {
                "top_left": {
                    "lat": 69.34059997089207,
                    "lon": -159.76670005358756
                },
                "bottom_right": {
                    "lat": -45.88390002027154,
                    "lon": 176.91669998690486
                }
            }
        }
    }
}
cs

 

추후 키바나에서 이러한 지형집계로 시각화를 할 수 있다.

 

 

-지형 중심 집계

지형 경계 집계 범위에서 정가운데의 위치를 반환한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
{
    "aggs":{
        "centroid":{
            "geo_centroid":{
                "field":"geoip.location"
            }    
        }
    }
}
 
->result
{
    "took": 10,
    "timed_out": false,
    "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": 10001,
        "max_score": 0,
        "hits": []
    },
    "aggregations": {
        "centroid": {
            "location": {
                "lat": 38.715619301146354,
                "lon": -22.189867686554656
            },
            "count": 9993
        }
    }
}
cs

 

여기까지 메트릭 집계에 대해 간단히 다루어봤다. 글이 길어져 다음 포스팅에 이어서 집계 API를 다루어보도록 한다.

 

2019/09/20 - [Search-Engine/Elasticsearch&Solr] - Elasticsearch - Aggregation API(엘라스틱서치 집계,버킷(Bucket Aggregations) 집계) -2

 

Elasticsearch - Aggregation API(엘라스틱서치 집계,버킷(Bucket Aggregations) 집계) -2

이번 포스팅은 엘라스틱서치 Aggregation(집계) API 두번째 글이다. 이번 글에서는 집계중 버킷집계(Bucket)에 대해 알아볼 것이다. 우선 버킷 집계는 메트릭 집계와는 다르게 메트릭을 계산하지 않고 버킷을 생..

coding-start.tistory.com

2019/09/20 - [Search-Engine/Elasticsearch&Solr] - Elasticsearch - Aggregation API(엘라스틱서치 집계,파이프라인(Pipeline Aggregations) 집계) -3

 

Elasticsearch - Aggregation API(엘라스틱서치 집계,파이프라인(Pipeline Aggregations) 집계) -3

파이프라인 집계(Pipeline Aggregations)는 다른 집계와 달리 쿼리 조건에 부합하는 문서에 대해 집계를 수행하는 것이 아니라, 다른 집계로 생성된 버킷을 참조해서 집계를 수행한다. 집계 또는 중첩된 집계를..

coding-start.tistory.com

 

posted by 여성게
:

 

오늘 간단히 다루어볼 내용은 엘라스틱서치의 REST 자바 클라이언트인 Rest High Level Client를 이용하여 Index Template을 생성해보는 예제이다. 바로 예제로 들어간다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public void indexTemplate() throws IOException {
        
        String typeName = "_doc";
        
        if(!existTemplate()) {
            
            try(RestHighLevelClient client = createConnection();){
                PutIndexTemplateRequest templateRequest = new PutIndexTemplateRequest("log-template");
                
                templateRequest.patterns(Arrays.asList("logstash-*"));
                
                XContentBuilder mapping = XContentFactory.jsonBuilder()
                                                         .startObject()
                                                             .startObject(typeName)
                                                                 .startObject("properties")
                                                                     .startObject("date")
                                                                           .field("type","date")
                                                                      .endObject()
                                                                      .startObject("fieldName")
                                                                          .field("type","keyword")
                                                                      .endObject()
                                                                 .endObject()
                                                             .endObject()
                                                         .endObject();
                
                templateRequest.mapping("_doc", mapping);
                
                AcknowledgedResponse templateResponse = client.indices().putTemplate(templateRequest, RequestOptions.DEFAULT);
                
                if(!templateResponse.isAcknowledged()) throw new ElasticsearchException("Create Index Template Failed !");
                
            }
        }
        
    }
cs

 

해당 인덱스 템플릿으로 생성될 수 있는 인덱스 패턴은 배열로 여러개 지정가능하다. 현재 설정은 단순 mapping만 설정하였지만, settings 정보까지 인덱스 템플릿 설정으로 넣어줄 수 있다. 만약 로그스태시나 비트 프레임워크를 엘라스틱과 연동하여 일자별 로그를 수집하는 기능을 구현한다면 미리 인덱스 템플릿으로 생성될 인덱스의 정의를 잡아주는 것이 좋을 것이다.

 

이제 해당 인덱스 템플릿을 구성한 이후에 logstash-*로 시작하는 인덱스가 생성될때 위와 같은 mapping 설정대로 필드가 생성될 것이다.

posted by 여성게
: