﻿---
title: Percentile ranks aggregation
description: A multi-value metrics aggregation that calculates one or more percentile ranks over numeric values extracted from the aggregated documents. These values...
url: https://www.elastic.co/elastic/docs-builder/docs/2821/reference/aggregations/search-aggregations-metrics-percentile-rank-aggregation
products:
  - Elasticsearch
---

# Percentile ranks aggregation
A `multi-value` metrics aggregation that calculates one or more percentile ranks over numeric values extracted from the aggregated documents. These values can be extracted from specific numeric or [histogram fields](https://www.elastic.co/elastic/docs-builder/docs/2821/reference/elasticsearch/mapping-reference/histogram) in the documents.
<note>
  Please see [Percentiles are (usually) approximate](/elastic/docs-builder/docs/2821/reference/aggregations/search-aggregations-metrics-percentile-aggregation#search-aggregations-metrics-percentile-aggregation-approximation), [Compression](/elastic/docs-builder/docs/2821/reference/aggregations/search-aggregations-metrics-percentile-aggregation#search-aggregations-metrics-percentile-aggregation-compression) and [Execution hint](/elastic/docs-builder/docs/2821/reference/aggregations/search-aggregations-metrics-percentile-aggregation#search-aggregations-metrics-percentile-aggregation-execution-hint) for advice regarding approximation, performance and memory use of the percentile ranks aggregation
</note>

Percentile rank show the percentage of observed values which are below certain value. For example, if a value is greater than or equal to 95% of the observed values it is said to be at the 95th percentile rank.
Assume your data consists of website load times. You may have a service agreement that 95% of page loads complete within 500ms and 99% of page loads complete within 600ms.
Let’s look at a range of percentiles representing load time:
```json

{
  "size": 0,
  "aggs": {
    "load_time_ranks": {
      "percentile_ranks": {
        "field": "load_time",   <1>
        "values": [ 500, 600 ]
      }
    }
  }
}
```

The response will look like this:
```json
{
  ...

 "aggregations": {
    "load_time_ranks": {
      "values": {
        "500.0": 90.01,
        "600.0": 100.0
      }
    }
  }
}
```

From this information you can determine you are hitting the 99% load time target but not quite hitting the 95% load time target.

## Keyed Response

By default the `keyed` flag is set to `true` associates a unique string key with each bucket and returns the ranges as a hash rather than an array. Setting the `keyed` flag to `false` will disable this behavior:
```json

{
  "size": 0,
  "aggs": {
    "load_time_ranks": {
      "percentile_ranks": {
        "field": "load_time",
        "values": [ 500, 600 ],
        "keyed": false
      }
    }
  }
}
```

Response:
```json
{
  ...

  "aggregations": {
    "load_time_ranks": {
      "values": [
        {
          "key": 500.0,
          "value": 55.0
        },
        {
          "key": 600.0,
          "value": 64.0
        }
      ]
    }
  }
}
```


## Script

If you need to run the aggregation against values that aren’t indexed, use a [runtime field](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/2821/manage-data/data-store/mapping/runtime-fields). For example, if our load times are in milliseconds but we want percentiles calculated in seconds:
```json

{
  "size": 0,
  "runtime_mappings": {
    "load_time.seconds": {
      "type": "long",
      "script": {
        "source": "emit(doc['load_time'].value / params.timeUnit)",
        "params": {
          "timeUnit": 1000
        }
      }
    }
  },
  "aggs": {
    "load_time_ranks": {
      "percentile_ranks": {
        "values": [ 500, 600 ],
        "field": "load_time.seconds"
      }
    }
  }
}
```


## HDR Histogram

[HDR Histogram](https://github.com/HdrHistogram/HdrHistogram) (High Dynamic Range Histogram) is an alternative implementation that can be useful when calculating percentile ranks for latency measurements as it can be faster than the t-digest implementation with the trade-off of a larger memory footprint. This implementation maintains a fixed worse-case percentage error (specified as a number of significant digits). This means that if data is recorded with values from 1 microsecond up to 1 hour (3,600,000,000 microseconds) in a histogram set to 3 significant digits, it will maintain a value resolution of 1 microsecond for values up to 1 millisecond and 3.6 seconds (or better) for the maximum tracked value (1 hour).
The HDR Histogram can be used by specifying the `hdr` object in the request:
```json

{
  "size": 0,
  "aggs": {
    "load_time_ranks": {
      "percentile_ranks": {
        "field": "load_time",
        "values": [ 500, 600 ],
        "hdr": {                                  <1>
          "number_of_significant_value_digits": 3 <2>
        }
      }
    }
  }
}
```

The HDRHistogram only supports positive values and will error if it is passed a negative value. It is also not a good idea to use the HDRHistogram if the range of values is unknown as this could lead to high memory usage.

## Missing value

The `missing` parameter defines how documents that are missing a value should be treated. By default they will be ignored but it is also possible to treat them as if they had a value.
```json

{
  "size": 0,
  "aggs": {
    "load_time_ranks": {
      "percentile_ranks": {
        "field": "load_time",
        "values": [ 500, 600 ],
        "missing": 10           <1>
      }
    }
  }
}
```