본문 바로가기
데이터 엔지니어( 실습 정리 )/elasticsearch

4. 데이터 다루기 (3, 4, 5)

by 세용용용용 2024. 12. 19.

[ 엘라스틱 서치 바이블 ] 공부한 후 정리한 내용 입니다!!!

 

 

3. 검색 API

  • 엘라스틱의 핵심인 검색 엔진

 

(3-1) 검색 대상 지정

  • GET, POST 메서드를 사용하며 _search 옵션 호출
  • 인덱스 미지정시 전체 인덱스에 대해 검색
  • 인덱스 명 지정시 와일드 카드 가능, 및 콤마를 구분해 여러 검색 대상 지정 가능
### 검색 대상 지정 테스트
curl -XGET "http://192.168.56.10:9200/*sy*,my_index2/_search?pretty"

>>> sy가 포함된 인덱스 + my_index2 검색 ( 지정 인덱스 모든 문서 hit )

 

 

(3-2) 쿼리 DSL 검색, 쿼리 문자열 검색

  • 검색 요청 본문에 엘라스틱서치 전용 쿼리 기술하는 방법, 요청 주소줄에 q라는 매개변수로 검색하는 두 방법이 있음
  • 두가지 방법 혼용은 안됨 ( q 매개변수 우선 작동 )

 

쿼리 DSL 검색

### 쿼리 DSL 검색
curl -XGET "http://192.168.56.10:9200/my_index/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "query": {"match": {"title": "hello"}}
}'

쿼리 검색 결과

  • _source를 해당 쿼리를 통한 유사도 확인 가능

 

쿼리 문자열 검색

  • 간단한 요청을 이용하는 경우 사용
### 쿼리 문자열 검색 테스트
curl -XGET "http://192.168.56.10:9200/my_index/_search?pretty&q=title:hello"

### 쿼리 문자열 문법
1) _search?q=hello : 전체 필드 대상 검색
2) _search?q=title:hello : 지정 필드 대상 검색 ( title 필드 대상 )
3) _search?q=_exists_:title : 특정 필드 존재하는 문서 검색

4) _search?q=[필드 명]:[시작 TO 끝] : 지정필드 시작 ~ 끝 사이 문서 검색
[] 는 경계값 포함 {} 는 경계값 포함 X
경계값 없는 경우 * 사용
ex) 
date:[2024-12-01 TO 2024-12-19] : 2024-12-01 <= date 필드 데이터 <= 2024-12-19
date:{2024-12-01 TO 2024-12-19} : 2024-12-01 < date 필드 데이터 < 2024-12-19
date:[* TO 2024-12-19] : date 필드 데이터 <= 2024-12-19
date:[2024-12-01 TO *] : 2024-12-01 <= date 필드 데이터

5) 질의에 와일드카드, ? 사용
_search?q=title:hello*
와일드 카드 포함 쿼리는 매우 느리며 위험.. ㅠㅠ

6) 쿼리 and, or 연산 적용
_search?q=_exists_:type%20AND%20title:hello
_search?q=title:syoung%20OR%20title:hello

 

 

(3-3) match_all 쿼리

  • 모든 문서를 매치하는 쿼리 ( query 부분 비워드면 기본값으로 지정되는 쿼리 )
### match_all 쿼리 문법
curl -XGET "http://192.168.56.10:9200/my_index/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "query": {"match_all": {}}
}'

 

 

(3-4) match 쿼리

  • 필드 내용이 질의어와 매치되는 문서 찾는 쿼리
  • 필드 type이 text이면 질의어도 애널라이저로 분석
  • 애널라이저 분석의 경우 각 텀은 or 조건으로 매칭 하는데 operartor를 and로 지정하며 모든 텀이 매치된 문서만 검색되도록 변경 가능
### match 쿼리 문법
curl -XGET "http://192.168.56.10:9200/[인덱스 명]/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "query": {"match": {"fieldName": {"query": "test query sentence", "operator": "and"}}}
}'

 

 

(3-5) term 쿼리

  • 지정한 필드 값이 질의어와 정확히 일치하는 문서를 찾는 쿼리
  • text 타입 필드 대상 term 쿼리를 사용하는 경우 : 분석 결과 생성된 단일 텀과 노멀라이저를 거친 질의어가 완전히 같은 경우 검색
### term 쿼리 문법
curl -XGET "http://192.168.56.10:9200/my_index/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "query": {"term": {"title.keyword": {"value": "hello"}}}
}'

 

 

(3-6) terms 쿼리

  • 지정 필드 값이 질의어와 정확이 일치하는 문서 찾는 쿼리 ( 질의어 여러 개 지정 가능!! )
  • 하나 이상의 질의어가 일치시 검색 결과 포함
### terms 쿼리 문법
curl -XGET "http://192.168.56.10:9200/my_index/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "query": {"terms": {"title.keyword": ["hello", "syoung"]}}
}'

>>> title 필드값이 hello, syoung 문서 검색 ( 둘중 하나 이상 일치시 검색 )

 

 

(3-7) range 쿼리

  • 필드 값이 범위 내에 있는 문서 검색
  • 범위는 gt, lt, gte, lte 이용
  • gt 필드 값 lt : < 필드 값 <
  • gte 필드 값 lte : <= 필드 값 <=
  • 문자열 필드 대상의 range 쿼리는 부하가 큰 쿼리 ( 초심히 사용 )
### range 쿼리 문법
curl -XGET "http://192.168.219.20:9200/my_index2/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "query": {"range": {"point": {"gte": 500, "lte": 1800}}}
}'

 

 

(3-8) prefix 쿼리

  • 필드 값이 지정한 질의어로 시작하는 문서 찾는 쿼리
### prefix 쿼리 문법
curl -XGET "http://192.168.219.20:9200/my_index2/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "query": {"prefix": {"park_name": {"value": "sy"}}}
}'

 

  • prefix도 무거운 쿼리.. 서비스 성 호출로 사용하려면 매핑에 index_prefixes 설정 넣는 방법 사용
### 매핑에 index_prefixes 설정 넣기
curl -XPUT "http://192.168.219.20:9200/prefix_mapping_test?pretty" -H "Content-Type: application/json" -d \
'{
  "mappings": {
    "properties": {
      "prefixField": {"type": "text", "index_prefixes": {"min_chars": 3, "max_chars": 5}}
    }
  }
}'
>>> es 문서 색인시 min_chars ~ max_chars 사이 prefix를 미리 별도로 색인
>>> 색인에서 손해보는 대신 prefix 쿼리 성능 높이는 방법

 

 

(3-9) exists 쿼리

  • 지정한 필드를 포함한 문서 검색
### exists 쿼리
curl -XGET "http://192.168.219.20:9200/my_index2/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "query": {
    "exists": {"field": "park_name"}
  }
}'

 

 

(3-10) bool 쿼리

  • 여러 쿼리 조합하여 검색하는 쿼리 ( 4가지 종류 사용 )
  • must, filter 조건절에 들어간 하위 쿼리는 모두 AND 조건으로 만족해야 검색 결과 포함
  • must_not 조건절에 들어간 쿼리를 만족하는 문서는 최종 검색결과 제외
  • should 조건절에 들어간 쿼리는 minimum_should_match 지정 갯수 이상의 하위 쿼리를 만족하는 문서가 검색 결과에 포함 ( should 조건은 OR 조건 )
### bool 쿼리 문법
curl -XGET "http://192.168.219.20:9200/[인덱스 명]/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "query": {
    "bool": {
      "must": [
      	~~
      ],
      "must_not": [
      	~~
      ],
      "filter": [
      	~~
      ],
      "should": [
      	~~
      ]
      "minimum_should_match": 1
    }
  }
}'

 

 

쿼리 문맥과 필터 문맥

  • 필터 문맥 : 단순 조건을 만족하는 여부만 따지는 검색 과정 ( bool filter, must_not 조건, exists, range, constatnt_socre.. )
  • 쿼리 문맥 : 검색 조건에 유사도 점수를 매기는 검색 과정 ( bool must, should 조건, match, term.. )
  • 유사도 점수를 매길 필요가 없는 조건이면 필터 문맥이 성능상 유리 ( 점수 계산 비용 아낌, 쿼리 캐시에 저장해 재활용 가능 )

쿼리 수행 순서

  • es는 검색요청 받으면 내부적으로 비용을 추정하고 유리할 것이라 생각되는 부분 먼저 수행
  • 문서 참, 거짓을 판별하는 과정을 거친 후 점수 계산 ( 필터 문맥 쿼리 점수 계산 하지 않음 )
  •  세부 쿼리 실행 순서를 원하는 대로 하려면 커스텀 쿼리 만들어야됨

 

(3-11) constant_score 쿼리

  • filter 부분에 지정한 쿼리를 필터 문맥에서 검색하는 쿼리
  • 해당 쿼리 매치된 문서 유사도 점수는 1로 지정
### constant_score 쿼리 테스트
curl -XGET "http://192.168.56.10:9200/[인덱스 명]/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "query": {
    "constant_score": {"filter": { ~~~ }}
  }
}'

 

 

 

(3-12) 검색 api 매개변수

라우팅 : 라우팅을 지정하여 성능 향상 ( routing=[라우팅 명] )

explain : 검색 점수가 어떻게 계산되는지 설명 ( explain=true )

search_type : 점수 계산 샤드 레벨 지정

  • query_then_fetch >>> 기본 설정, 각 샤드에서 점수 계산 끝냄
  • dfs_query_then_fetch >>> 모든 샤드 정보를 모아 유사도 점수 계산 ( 점수 향상되지만 검색 성능 떨어짐 ㅠㅠ )

 

 

(3-13) 검색 결과 정렬

  • 요청 본문에 sort를 지정해 검색 결과 정렬
  • 디폴트는 오름차순 ( desc : 내림차순, asc: 오름차순 )
  • text 타입 필드는 fielddata를 true로 지정시 정렬 사용 가능, but.. 역색인 정보를 메모리에 올려야되서 oom 야기... 위험
  • 필드 이름 이외 _score, _doc로 정렬 지정 가능 ( _score :  유사도 점수, _doc : 문서 번호 )
  • 정렬 옵션에 _score가 포함되지 않으면 점수 계산 안함
### 검색 정렬 문법
curl -XGET "http://192.168.56.10:9200/my_index/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "sort": [{"age": "desc"}]
}'

 

 

(3-14) 페이지네이션

from , size

  • from : 몇 번쨰 문서부터 결과 반환할지
  • size : 몇 개의 문서 반환할 것인지
  • from 값이 커지면 무거운 검색을 수행 해야됨 ㅠㅜ ( from +  size 합이 1만이 넘어가는 검색은 수행 불가, 윈도우 크기 늘려줘야됨 )
  • 특정 시점의 데이터를 검색하려면 페이지네이션 해야됨 ( 두 검색 요청 사이에 인덱스 상태가 달라질수 있음 )
### from, size 테스트
curl -XGET "http://192.168.56.10:9200/kibana_sample_data_ecommerce/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "from": 10,
  "size": 1
}'
>>> 10번쨰 문서부터 하나 검색

 

 

scroll

  • 검색 조건 매칭 문서 모두 순회
  • 순회하는 동안 최초 검색 문맥 유지 ( 검색 문맥 유지 시간 지정 )
### scroll 테스트
curl -XGET "http://192.168.56.10:9200/kibana_sample_data_ecommerce/_search?pretty&scroll=1m" -H "Content-Type: application/json" -d \
'{
  "size": 500
}' | grep _scroll_id > /data/work/scroll_id.txt

curl -XGET "http://192.168.56.10:9200/_search/scroll?pretty" -H "Content-Type: application/json" -d \
'{
  "scroll_id": "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFlBkVW1OeUVOUjhtSmgtLTFKN1cyWXcAAAAAAAAB0BZVbUppUExYZFNJNnVFR2Y3alc3enFn",
  "scroll": "1m"
}'

>>> 스크롤 id 로 검색을 반복
>>> 더 이상 문서가 반환되지 않으면 모든 검색 완료

### 검색 문맥 명시적 제거
curl -XDELETE "http://192.168.56.10:9200/_search/scroll?pretty" -H "Content-Type: application/json" -d \
'{
  "scorll_id": "스크롤id"
}'

 

 

search_after

  • 사용자가 검색 결과를 요청하고 결과에 페이지네이션 제공하는 용도 사용
  • sort를 지정해야 하며 동일 정렬 값이 등장할 수 없게 1개 이상의 동점 제거 필드 지정
  • 동점 제거용 필드는 doc_values가 켜져있는 필드로 지정하는게 좋음
### 페이지네이션 search_after 테스트
curl -XGET "http://192.168.56.10:9200/kibana_sample_data_ecommerce/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "size": 20,
  "query": {
    "term": {
      "currency": {"value": "EUR"}
    }
  },
  "sort": [{"order_date": "desc"}, {"order_id": "asc"}]
 }'
 >>> 응답 sort 값
 "sort" : [
          1736627990000,
          "591924"
        ]
 
 
 ### 첫 검색 응답으로 sort 기준값을 가져와 요청 본문 search_after 필드에 해당 값을 넣어 다음 요청 검색
 curl -XGET "http://192.168.56.10:9200/kibana_sample_data_ecommerce/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "size": 20,
  "query": {
    "term": {
      "currency": {"value": "EUR"}
    }
  },
  "search_after": [1736627990000, "591924"],
  "sort": [{"order_date": "desc"}, {"order_id": "asc"}]
 }'
  • 동점 제거용 필드 지정했더라도 인덱스 상태가 변하는 중 페이지네이션 과정이면 변동 사항 발생
  • point in time API를 사용해 search_after 사용시 인덱스 상태를 특정 시점으로 고정

 

point in time API

  • search_after 페이지네이션 사용시 인덱스 상태를 고정
  • keep_alive 매개변수에 상태유지 시간 지정
  • 별도 정렬을 지정할 필요 없음 ( pit는 _shard_doc를 사용해 문서의 물리적 저장 위치에 따라 결과를 고유하게 정렬 )
  • 정렬을 지정하게 되면 _shard_doc는 맨 마지막에 자동 추가
### point in time API 사용 테스트 ( 검색 대상 상태 고정 )
curl -XPOST "http://192.168.56.10:9200/kibana_sample_data_ecommerce/_pit?keep_alive=1m"
>>> 응답으로 pit id 값 반환
{"id":"697qAwEca2liYW5hX3NhbXBsZV9kYXRhX2Vjb21tZXJjZRZpX1djQ1M4UlJiYUY5dVRMakRoVnBnABZCNk42MFJDRVJ4LUtyS0Z3ZG9ZQy1nAAAAAAAAAAAEFnRZX3loQ1E1UTJLTzhPVExMUElyUUEAARZpX1djQ1M4UlJiYUY5dVRMakRoVnBnAAA="}


### 얻은 pit id 값을 이용해 검색 대상을 고정
### 검색시 인덱스 지정 안함, pit id를 통해 검색 대상 지정하기 때문
curl -XGET "http://192.168.56.10:9200/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "size": 20,
  "query": {
    "term": {
      "currency": {"value": "EUR"}
    }
  },
  "pit": {
    "id":"697qAwEca2liYW5hX3NhbXBsZV9kYXRhX2Vjb21tZXJjZRZpX1djQ1M4UlJiYUY5dVRMakRoVnBnABZCNk42MFJDRVJ4LUtyS0Z3ZG9ZQy1nAAAAAAAAAAAGFnRZX3loQ1E1UTJLTzhPVExMUElyUUEAARZpX1djQ1M4UlJiYUY5dVRMakRoVnBnAAA=",
    "keep_alive": "1m"
  },
  "sort": [{"order_date": "desc"}]
}'
>>> 응답으로 sort 값 리턴
"sort" : [
          1736627990000,
          4290
        ]


### 첫 검색 결과를 통해 받은 sort 값을 search_after필드 값으로 지정해 search_after 페이지네이션 수행
curl -XGET "http://192.168.56.10:9200/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "size": 20,
  "query": {
    "term": {
      "currency": {"value": "EUR"}
    }
  },
  "pit": {
    "id":"697qAwEca2liYW5hX3NhbXBsZV9kYXRhX2Vjb21tZXJjZRZpX1djQ1M4UlJiYUY5dVRMakRoVnBnABZCNk42MFJDRVJ4LUtyS0Z3ZG9ZQy1nAAAAAAAAAAAGFnRZX3loQ1E1UTJLTzhPVExMUElyUUEAARZpX1djQ1M4UlJiYUY5dVRMakRoVnBnAAA=",
    "keep_alive": "1m"
  },
  "search_after": [1736627990000, 4290],
  "sort": [{"order_date": "desc"}]
}'


### point in time API 명시적 삭제 ( pit_id 값을 지정해 명시적 삭제 가능 )
curl -XDELETE "http:///192.168.56.10:9200/_pit" -H "Content-Type: applicatoin/json" -d \
'{
  "id" :~~~~
}'

 

 

4. 집계

  • 검색을 수행한 후 >>> 집계를 수행하여 데이터 기반 문제 해결

 

(4-1)  집계 기본

  • es 집계는 검색의 연장선 ( 검색으로 데이터를 추려낸 후 >> 집계를 통해 인사이트 제공 )
  • 집계 요청 상세는 aggs 필드 밑에 기술
  • 여러 집계 요청할수 있어 구분을 위한 이름을 붙여야됨
  • es 집계는 크게 메트릭, 버킷, 파이프라인 집계로 구분
### 엘라스틱 집계 테스트
### sum 집계 : 검색 문서 지정한 필드 값을 모두 합친 값 반환
curl -XGET "http://192.168.56.10:9200/kibana_sample_data_ecommerce/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "size": 0,
  "query": {"term": {"currency": {"value": "EUR"}}},
  "aggs": {
    "my-sum-agg-name": {
      "sum": {
        "field": "taxless_total_price"
      }
    }
  }
}'
>>> 집계시 size는 0으로 설정하여 성능 이득 취할수 있음 ( 문서 내용 수집 X, 점수 계산 X )

 

 

(4-2)  메트릭 집계

  • 검색 결과에 대한 산술적인 연산 수행하는 집계

 

1) avg, max, min, sum 집계

  • 검색 문서 대상 지정한 필드 값을 평균, 최대값, 최솟값, 합 으로 반환
### avg, max, min, sum 집계 ( 메트릭 집계 )
curl -XGET "http://192.168.56.10:9200/kibana_sample_data_ecommerce/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "size": 0,
  "query": {"term": {"currency": {"value": "EUR"}}},
  "aggs": {
    "my-avg-name": {"avg": {"field": "taxless_total_price"}},
    "my-max-name": {"max": {"field": "taxless_total_price"}},
    "my-sum-name": {"sum": {"field": "taxless_total_price"}}
  }
}'
>>> 집계 요청 필드에 원하는 집계 요청 지정 ( avg, max, min, sum )

 

 

2) stats 집계

  • 지정한 필드의 평균, 최대, 최소, 합, 갯수 결과를 모두 반환
### stats 집계 ( 메트릭 집계 )
curl -XGET "http://192.168.56.10:9200/kibana_sample_data_ecommerce/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "size": 0,
  "query": {"term": {"currency": {"value": "EUR"}}},
  "aggs": {
    "my-stats-name": {"stats": {"field": "taxless_total_price"}}
  }
}'

>>> 지정 필드 평균, 최대, 최소, 합, 갯수 값을 응답
"aggregations" : {
    "my-stats-name" : {
      "count" : 4675,
      "min" : 6.98828125,
      "max" : 2250.0,
      "avg" : 75.05542864304813,
      "sum" : 350884.12890625
    }
  }

 

 

3) cardinality 집계

  • 지정 필드가 가진 고유한 값 갯수를 반한
  • 결과는 hyperloglog++ 알고리즘 사용해 추정한 근사값
  • 정확도 조절을 위해 precision_threshold 사용 ( 기본값은 3000, 값을 높이면 정확도 올라가지만 메모리 사용 증가 )
  • precision_threshold > cardinality : 정확도가 충분히 높음
  • precision_threshold < cardinality : 정확도가 떨어짐 ( 조정 필요 )
### cardinality 집계 ( 메트릭 집계 )
curl -XGET "http://192.168.56.10:9200/kibana_sample_data_ecommerce/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "size": 0,
  "query": {"term": {"currency": {"value": "EUR"}}},
  "aggs": {
    "my-cardinlity-name": {
      "cardinality": {"field": "customer_id", "precision_threshold": 3000}
    }
  }
}'

>>> 지정 필드 고유값 반환
"aggregations" : {
    "my-cardinlity-name" : {
      "value" : 46
    }
  }

 

 

(4-3)  버킷 집계

  • 검색한 문서를 특정 기준으로 쪼개 여러 부분으로 나눔
  • 나눠진 부분을 버킷이라 하며 각 버킷 별도로 하위 집계 수행
  • 여러 버킷으로 나눈 뒤 하위 집계 수행하는 것이 버킷 집계 핵심, but... 깊이가 너무 깊어지면 성능에 문제 ㅠㅠ

1) range 집계

  • 지정한 필드값 기준으로 문서를 원하는 버킷 구간으로 나눔
  • 버킷 구간을 나눌 필드기준 값을 요청 본문에 지정
  • range 밑에 aggs 하나 더 추가하여 하위 집계 지정 ( 미 지정시 doc_count 까지 세고 끝냄 )
### range 집계 ( 버킷 집계 )
curl -XGET "http://192.168.56.10:9200/kibana_sample_data_flights/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "size": 0,
  "query": {"match_all": {}},
  "aggs": {
    "distance-kilo-range": {
      "range": {
        "field": "DistanceKilometers",
        "ranges": [{"to": 5000},{"from": 5000, "to": 10000},{"from": 10000}]
      },
      "aggs": {
        "stats-tickete-price": {
          "stats": {"field": "AvgTicketPrice"}
        }
      }
    }
  }
}'
>>> DistanceKilometers 필드 range 기준 으로 버킷 생성후
>>> 각 버킷 AvgTicketPrice 필드 stats 집계

 

 

2) date_range 집계

  • date 타입 필드 대상으로 사용
### date_range 집계 ( 버킷 집계 )
curl -XGET "http://192.168.56.10:9200/kibana_sample_data_ecommerce/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "size": 0,
  "query": {"term": {"currency": {"value": "EUR"}}},
  "aggs": {
    "date-range-aggs": {
      "date_range": {
        "field": "order_date",
        "ranges": [{"to":"now-10d/d"},{"from": "now-10d/d", "to": "now"},{"from": "now"}]
      },
      "aggs": {
        "stats-taxless_total_price": {
          "stats": {"field": "taxless_total_price"}
        }
      }
    }
  }
}'
  • now 가 포함된 집계는 캐시에 올라가지 않음 ( 동일 집계 요청은 요청 본문이 동일한가로 구문하기 떄문 )

 

 

3) histogram 집계

  • range와 유사 하지만 경계값 기준을 직접 지정하는 것이 아닌 간격 ( interval ) 으로 지정
  • 위치 조정 하지 않으면 0을 기준으로 interval, offset을 사용해 위치 지정 가능
  • min_doc_count를 지정해 버킷 내 문서 개수가 일정 이하인 버킷 결과에서 제외 가능
### histogram 집계 ( 버킷 집계 )
curl -XGET "http://192.168.56.10:9200/kibana_sample_data_flights/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "size": 0,
  "query": {"match_all": {}},
  "aggs": {
    "my-histogram": {
      "histogram": {
        "field": "DistanceKilometers",
        "interval": 1000
      },
      "aggs": {
        "stats-ticket_price": {
          "stats": {"field": "AvgTicketPrice"}
        }
      }
    }
  }
}'


### offset을 사용해 interval 위치 지정 가능
curl -XGET "http://192.168.56.10:9200/kibana_sample_data_flights/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "size": 0,
  "query": {"match_all": {}},
  "aggs": {
    "my-histogram": {
      "histogram": {
        "field": "DistanceKilometers",
        "interval": 1000,
        "offset": 50
      },
      "aggs": {
        "stats-ticket_price": {
          "stats": {"field": "AvgTicketPrice"}
        }
      }
    }
  }
}'


### min_doc_count를 지정해 버킷 문서 갯수가 1000 이하인 버킷 결과에서 제외
curl -XGET "http://192.168.56.10:9200/kibana_sample_data_flights/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "size": 0,
  "query": {"match_all": {}},
  "aggs": {
    "my-histogram": {
      "histogram": {
        "field": "DistanceKilometers",
        "interval": 1000,
        "min_doc_count": 1000
      },
      "aggs": {
        "stats-ticket_price": {
          "stats": {"field": "AvgTicketPrice"}
        }
      }
    }
  }
}'

 

 

4) date_histogram 집계

  • histogram 집계와 유사하지만 date 타입 필드 기준으로 사용
  • calendar_interval, fixed_interval 사용
  • offset과 min_doc_count 설정 지정 가능
### date_histogram 집계 ( 버킷 집계 )
### calendar_interval : 1분, 1시간, 하루, 한달 ... interval
### fixed_interval : 지정 간격 단위 interval (ex.. 3시간, 4일, 2달 ....)

### date_histogram 집계 >> calendar_interval
curl -XGET "http://192.168.56.10:9200/kibana_sample_data_ecommerce/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "size": 0,
  "query": {"match_all": {}},
  "aggs": {
    "my-date-histogram": {
      "date_histogram": {
        "field": "order_date",
        "calendar_interval": "day"
      },
      "aggs": {
        "day_interval_max_taxless_total_price": {
          "max": {"field": "taxless_total_price"}
        }
      }
    }
  }
}'
>>> calendar_interval 지정 값
minute ( 분 ), hour ( 시간 ), day ( 일 ),
month ( 월 ), quarter ( 분기 ), year ( 년 )


### date_histogram 집계 >> fixed_interval
curl -XGET "http://192.168.56.10:9200/kibana_sample_data_ecommerce/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "size": 0,
  "query": {"match_all": {}},
  "aggs": {
    "my-date-histogram": {
      "date_histogram": {
        "field": "order_date",
        "fixed_interval": "3d"
      },
      "aggs": {
        "day_interval_max_taxless_total_price": {
          "max": {"field": "taxless_total_price"}
        }
      }
    }
  }
}'
>>> 3일 간격 버킷 집계
>>> fixed_interval 지정 값
ms, s, m, h, d

 

 

5) terms 집계

  • 지정 필드 기준 빈도수가 높은 term 순서대로 버킷 생성
  • 버킷 생성 size를 지정하는데 각 샤드에서 size 갯수 만큼 term을 뽑아 빈도수를 센다
  • 각 샤드에서 수행된 계산을 한곳에 모아 합산후 size 개수만큼 버킷을 뽑음 ( 즉, 정확하지 않을수 있음... )
  • 응답에서 doc_count_error_upper_bound 필드가 오차 상한선을 나타냄 ( 해당 값이 크면 size 크기 고려, size 높이면 성능은 하락 )
  • 응답에서 sum_other_doc_count는 최종적으로 버킷에 포함되지 않은 문서 수
  • 모든 term에 대해 전부 순회하여 집계 원할시 composite 집계 사용하는 것이 좋음
### terms 집계 ( 버킷 집계 )
curl -XGET "http://192.168.56.10:9200/kibana_sample_data_logs/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "size": 0,
  "query": {"match_all": {}},
  "aggs": {
    "terms-aggs": {
      "terms": {
        "field": "host.keyword",
        "size": 10
      }
    }
  }
}'

 

 

6) composite 집계

  • sources로 지정된 하위 집계 버킷 모두 페이지네이션을 이용해 효율적으로 순회하는 집계
  • size는 페이지네이션 한번에 몇 개의 버킷을 반환 할것인지 지정
  • sources에 버킷을 조합하여 순회할 하위 집계 지정 ( 일부 집계만 지정 가능 )
  • 응답의 마지막 key를 다음 요청에 넣어 페이지네이션
### composite 집계 ( 버킷 집계 )
curl -XGET "http://192.168.56.10:9200/kibana_sample_data_logs/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "size": 0,
  "query": {"match_all": {}},
  "aggs": {
    "composite-aggs": {
      "composite": {
        "size": 100,
        "sources": [
		  {
            "terms-aggs": {
              "terms": {
                "field": "host.keyword"
              }
            }
          },
          {
            "date-histogram-aggs": {
              "date_histogram": {
                "field": "timestamp",
                "calendar_interval": "day"
              }
            }
          }
        ]
      }
    }
  }
}'


### composite 집계 페이지네이션
curl -XGET "http://192.168.56.10:9200/kibana_sample_data_logs/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "size": 0,
  "query": {"match_all": {}},
  "aggs": {
    "composite-aggs": {
      "composite": {
        "size": 100,
        "sources": [
		  {
            "terms-aggs": {
              "terms": {
                "field": "host.keyword"
              }
            }
          },
          {
            "date-histogram-aggs": {
              "date_histogram": {
                "field": "timestamp",
                "calendar_interval": "day"
              }
            }
          }
        ],
        "after": {
          "terms-aggs": "cdn.elastic-elastic-elastic.org",
          "date-histogram-aggs": 1737504000000
        }
      }
    }
  }
}'

 

 

(4-4)  파이프라인 집계

  • 다른 집계 결과를 집계 대상으로 함
  • buckets_path라는 인자를 통해 다른 집계 결과를 가져옴

 

1) cumulative_sum 집계

  • 다른 집계의 값을 누적하여 합산
  • buckets_path로 누적 합산할 집계명 지정
### cumulative_sum 집계 ( 파이프라인 집계 )
### 다른 집계 값을 누적합산
curl -XGET "http://192.168.219.20:9200/kibana_sample_data_ecommerce/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "size": 0,
  "query": {"match_all": {}},
  "aggs": {
    "daily-timestamp": {
      "date_histogram": {
        "field": "order_date",
        "calendar_interval": "day"
      },
      "aggs": {
        "daily-total-avg": {
          "avg": {
            "field": "total_quantity"
          }
        },
        "pipeline-sum": {
          "cumulative_sum": {
            "buckets_path": "daily-total-avg"
          }
        }
      }
    }
  }
}'
>>> date_histogram 으로 일 단위 버킷으로 나눈 뒤 하위 집계로 total_quantity 평균을 구함
>>> 이후 cumulative_sum을 하위로 두고 buckets_path를 daily-total-avg로 지정하여 평균값 누적 합산

 

 

2) max_bucket 집계

  • 다른 집계 결과를 받아 가장 큰 버킷의 key와 결과값 반환하는 집계
### max_bucket 집계 ( 파이프라인 집계 )
curl -XGET "http://192.168.219.20:9200/kibana_sample_data_ecommerce/_search?pretty" -H "Content-Type: application/json" -d \
'{
  "size": 0,
  "query": {"match_all": {}},
  "aggs": {
    "daily-timestamp-bucket": {
      "date_histogram": {
        "field": "order_date",
        "calendar_interval": "day"
      },
      "aggs": {
        "daily-quantity-avg": {
          "avg": {
            "field": "total_quantity"
          }
        }
      }
    },
    "max-total-quantity": {
      "max_bucket": {
        "buckets_path": "daily-timestamp-bucket>daily-quantity-avg"
      }
    }
  }
}'
  • 누적합은 특정 버킷내 값을 순차적으로 누적하지만 max bucket은 버킷을 종합적으로 참조하기에 date_histogram 하위에 둘수 없다..
  • 즉, max_bucket 집계가 위치한 계층에서 "daily-timestamp-bucket>daily-quantity-avg" 경로를 지정해줘야함