백분위 순위 집계
백분위 순위 집계 (Percentile rank aggregation)
percentile_ranks 집계는 관측된 값 중 주어진 임계값보다 작거나 같은 값의 비율을 백분율로 추정해요. 이는 특정 값이 값들의 분포에서 상대적으로 어떤 위치에 있는지 이해하는 데 유용해요.
예를 들어, 백분위 순위 집계를 사용해 거래 금액 45가 데이터셋의 다른 거래 값들과 어떻게 비교되는지 알 수 있어요. 백분위 순위 집계는 82.3 같은 값을 반환하는데, 이는 거래의 82.3%가 45보다 작거나 같다는 뜻이에요.
출처: 문서
본문
파라미터
percentile_ranks 집계는 다음과 같은 파라미터를 받아요.
| 파라미터 | 데이터 타입 | 필수/선택 | 설명 |
|---|---|---|---|
field |
String | 필수 | 백분위 순위를 계산하는 데 사용할 숫자 필드예요. |
values |
Double 배열 | 필수 | 백분위 순위를 계산하는 데 사용할 값들이에요. |
keyed |
Boolean | 선택 | false로 설정하면 결과를 배열로 반환해요. 그 외에는 결과를 JSON 객체로 반환해요. 기본값은 true예요. |
tdigest.compression |
Double | 선택 | tdigest 알고리즘의 정확도와 메모리 사용량을 제어해요. tdigest를 이용한 정밀도 조정 섹션을 참고하세요. |
hdr.number_of_significant_value_digits |
Integer | 선택 | HDR 히스토그램의 정밀도 설정이에요. HDR 히스토그램 섹션을 참고하세요. |
missing |
Number | 선택 | 문서에 대상 필드가 없을 때 사용할 기본값이에요. |
script |
Object | 선택 | 필드 대신 사용자 지정 값을 계산하는 데 사용할 스크립트예요. 인라인(inline) 및 저장된(stored) 스크립트를 지원해요. |
예제
먼저 샘플 인덱스를 생성해 봐요:
PUT /transaction_data
{
"mappings": {
"properties": {
"amount": {
"type": "double"
}
}
}
}
백분위 순위 계산을 설명하기 위해 샘플 숫자 값을 추가해요:
POST /transaction_data/_bulk
{ "index": {} }
{ "amount": 10 }
{ "index": {} }
{ "amount": 20 }
{ "index": {} }
{ "amount": 30 }
{ "index": {} }
{ "amount": 40 }
{ "index": {} }
{ "amount": 50 }
{ "index": {} }
{ "amount": 60 }
{ "index": {} }
{ "amount": 70 }
특정 값들이 전체 분포와 어떻게 비교되는지 계산하는 percentile_ranks 집계를 실행해 봐요:
GET /transaction_data/_search
{
"size": 0,
"aggs": {
"rank_check": {
"percentile_ranks": {
"field": "amount",
"values": [25, 55]
}
}
}
}
응답은 값의 28.6%가 25보다 작거나 같고 71.4%가 55보다 작거나 같다는 것을 보여줘요:
{
...
"hits": {
"total": {
"value": 7,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"aggregations": {
"rank_check": {
"values": {
"25.0": 28.57142857142857,
"55.0": 71.42857142857143
}
}
}
}
키 기반 응답 (Keyed response)
keyed 파라미터를 false로 설정하면 반환되는 집계 형식을 JSON 객체에서 키-값 쌍 목록으로 바꿀 수 있어요:
GET /transaction_data/_search
{
"size": 0,
"aggs": {
"rank_check": {
"percentile_ranks": {
"field": "amount",
"values": [25, 55],
"keyed": false
}
}
}
}
응답에 객체 대신 배열이 포함돼요:
{
...
"hits": {
"total": {
"value": 7,
"relation": "eq"
},
"max_score": null,
"hits": []
},
"aggregations": {
"rank_check": {
"values": [
{
"key": 25,
"value": 28.57142857142857
},
{
"key": 55,
"value": 71.42857142857143
}
]
}
}
}
tdigest를 이용한 정밀도 조정 (Precision tuning with tdigest)
기본적으로 백분위 순위는 tdigest 알고리즘을 사용해 계산돼요. tdigest.compression 파라미터를 지정하면 정확도와 메모리 사용량 사이의 트레이드오프를 제어할 수 있어요. 값이 높을수록 정확도는 좋아지지만 메모리를 더 많이 사용해요. tdigest가 어떻게 동작하는지 자세한 내용은 tdigest를 이용한 정밀도 조정 문서를 참고하세요.
다음 예제는 tdigest.compression을 200으로 설정했어요:
GET /transaction_data/_search
{
"size": 0,
"aggs": {
"rank_check": {
"percentile_ranks": {
"field": "amount",
"values": [25, 55],
"tdigest": {
"compression": 200
}
}
}
}
}
HDR 히스토그램
tdigest의 대안으로, 많은 수의 버킷과 빠른 처리에 더 적합한 HDR(High Dynamic Range) 히스토그램 알고리즘을 사용할 수 있어요. HDR 히스토그램이 어떻게 동작하는지 자세한 내용은 HDR 히스토그램 문서를 참고하세요.
다음과 같은 경우 HDR을 사용해야 해요:
- 많은 버킷에 걸쳐 집계하는 경우
- 꼬리 백분위수에서 극단적인 정밀도를 요구하지 않는 경우
- 충분한 메모리를 사용할 수 있는 경우
다음과 같은 경우 HDR을 피해야 해요:
- 꼬리 정확도가 중요한 경우
- 왜곡되거나 희소한 데이터 분포를 분석하는 경우
다음 예제는 hdr.number_of_significant_value_digits를 3으로 설정했어요:
GET /transaction_data/_search
{
"size": 0,
"aggs": {
"rank_check": {
"percentile_ranks": {
"field": "amount",
"values": [25, 55],
"hdr": {
"number_of_significant_value_digits": 3
}
}
}
}
}
누락 값 처리 (Missing values)
일부 문서에 대상 필드가 없는 경우, missing 파라미터를 설정해 쿼리가 대체(fallback) 값을 사용하도록 지시할 수 있어요. 다음 예제는 amount 필드가 없는 문서를 값이 0인 것으로 간주해 백분위 순위 계산에 포함되도록 보장해요:
GET /transaction_data/_search
{
"size": 0,
"aggs": {
"rank_check": {
"percentile_ranks": {
"field": "amount",
"values": [25, 55],
"missing": 0
}
}
}
}
스크립트 (Script)
필드를 지정하는 대신 스크립트를 사용해 값을 동적으로 계산할 수 있어요. 통화 변환 또는 가중치 적용 같은 변환을 적용해야 할 때 유용해요.
인라인 스크립트 (Inline script)
다음 예제는 인라인 스크립트를 사용해 amount 필드의 값을 10% 증가시킨 값들에 대해 변환된 값 30과 60의 백분위 순위를 계산해요:
GET /transaction_data/_search
{
"size": 0,
"aggs": {
"rank_check": {
"percentile_ranks": {
"values": [30, 60],
"script": {
"source": "doc['amount'].value * 1.1"
}
}
}
}
}
저장된 스크립트 (Stored script)
저장된 스크립트를 사용하려면 먼저 다음 요청으로 생성해요:
POST _scripts/percentile_script
{
"script": {
"lang": "painless",
"source": "doc[params.field].value * params.multiplier"
}
}
그런 다음 percentile_ranks 집계에서 저장된 스크립트를 사용해요:
GET /transaction_data/_search
{
"size": 0,
"aggs": {
"rank_check": {
"percentile_ranks": {
"values": [30, 60],
"script": {
"id": "percentile_script",
"params": {
"field": "amount",
"multiplier": 1.1
}
}
}
}
}
}