백분위 순위 집계

백분위 순위 집계 (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
          }
        }
      }
    }
  }
}

더 알아보기 (Learn more)