percentile-rank-aggregation.asciidoc 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. [[search-aggregations-metrics-percentile-rank-aggregation]]
  2. === Percentile ranks aggregation
  3. ++++
  4. <titleabbrev>Percentile ranks</titleabbrev>
  5. ++++
  6. A `multi-value` metrics aggregation that calculates one or more percentile ranks
  7. over numeric values extracted from the aggregated documents. These values can be
  8. extracted from specific numeric or <<histogram,histogram fields>> in the documents.
  9. [NOTE]
  10. ==================================================
  11. Please see <<search-aggregations-metrics-percentile-aggregation-approximation>>
  12. and <<search-aggregations-metrics-percentile-aggregation-compression>> for advice
  13. regarding approximation and memory use of the percentile ranks aggregation
  14. ==================================================
  15. Percentile rank show the percentage of observed values which are below certain
  16. value. For example, if a value is greater than or equal to 95% of the observed values
  17. it is said to be at the 95th percentile rank.
  18. Assume your data consists of website load times. You may have a service agreement that
  19. 95% of page loads complete within 500ms and 99% of page loads complete within 600ms.
  20. Let's look at a range of percentiles representing load time:
  21. [source,console]
  22. --------------------------------------------------
  23. GET latency/_search
  24. {
  25. "size": 0,
  26. "aggs": {
  27. "load_time_ranks": {
  28. "percentile_ranks": {
  29. "field": "load_time", <1>
  30. "values": [ 500, 600 ]
  31. }
  32. }
  33. }
  34. }
  35. --------------------------------------------------
  36. // TEST[setup:latency]
  37. <1> The field `load_time` must be a numeric field
  38. The response will look like this:
  39. [source,console-result]
  40. --------------------------------------------------
  41. {
  42. ...
  43. "aggregations": {
  44. "load_time_ranks": {
  45. "values": {
  46. "500.0": 90.01,
  47. "600.0": 100.0
  48. }
  49. }
  50. }
  51. }
  52. --------------------------------------------------
  53. // TESTRESPONSE[s/\.\.\./"took": $body.took,"timed_out": false,"_shards": $body._shards,"hits": $body.hits,/]
  54. // TESTRESPONSE[s/"500.0": 90.01/"500.0": 55.00000000000001/]
  55. // TESTRESPONSE[s/"600.0": 100.0/"600.0": 64.0/]
  56. From this information you can determine you are hitting the 99% load time target but not quite
  57. hitting the 95% load time target
  58. ==== Keyed Response
  59. 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:
  60. [source,console]
  61. --------------------------------------------------
  62. GET latency/_search
  63. {
  64. "size": 0,
  65. "aggs": {
  66. "load_time_ranks": {
  67. "percentile_ranks": {
  68. "field": "load_time",
  69. "values": [ 500, 600 ],
  70. "keyed": false
  71. }
  72. }
  73. }
  74. }
  75. --------------------------------------------------
  76. // TEST[setup:latency]
  77. Response:
  78. [source,console-result]
  79. --------------------------------------------------
  80. {
  81. ...
  82. "aggregations": {
  83. "load_time_ranks": {
  84. "values": [
  85. {
  86. "key": 500.0,
  87. "value": 90.01
  88. },
  89. {
  90. "key": 600.0,
  91. "value": 100.0
  92. }
  93. ]
  94. }
  95. }
  96. }
  97. --------------------------------------------------
  98. // TESTRESPONSE[s/\.\.\./"took": $body.took,"timed_out": false,"_shards": $body._shards,"hits": $body.hits,/]
  99. // TESTRESPONSE[s/"value": 90.01/"value": 55.00000000000001/]
  100. // TESTRESPONSE[s/"value": 100.0/"value": 64.0/]
  101. ==== Script
  102. If you need to run the aggregation against values that aren't indexed, use
  103. a <<runtime,runtime field>>. For example, if our load times
  104. are in milliseconds but we want percentiles calculated in seconds:
  105. [source,console]
  106. ----
  107. GET latency/_search
  108. {
  109. "size": 0,
  110. "runtime_mappings": {
  111. "load_time.seconds": {
  112. "type": "long",
  113. "script": {
  114. "source": "emit(doc['load_time'].value / params.timeUnit)",
  115. "params": {
  116. "timeUnit": 1000
  117. }
  118. }
  119. }
  120. },
  121. "aggs": {
  122. "load_time_ranks": {
  123. "percentile_ranks": {
  124. "values": [ 500, 600 ],
  125. "field": "load_time.seconds"
  126. }
  127. }
  128. }
  129. }
  130. ----
  131. // TEST[setup:latency]
  132. // TEST[s/_search/_search?filter_path=aggregations/]
  133. ////
  134. [source,console-result]
  135. --------------------------------------------------
  136. {
  137. "aggregations": {
  138. "load_time_ranks": {
  139. "values": {
  140. "500.0": 100.0,
  141. "600.0": 100.0
  142. }
  143. }
  144. }
  145. }
  146. --------------------------------------------------
  147. ////
  148. ==== HDR Histogram
  149. NOTE: This setting exposes the internal implementation of HDR Histogram and the syntax may change in the future.
  150. https://github.com/HdrHistogram/HdrHistogram[HDR Histogram] (High Dynamic Range Histogram) is an alternative implementation
  151. that can be useful when calculating percentile ranks for latency measurements as it can be faster than the t-digest implementation
  152. with the trade-off of a larger memory footprint. This implementation maintains a fixed worse-case percentage error (specified as a
  153. number of significant digits). This means that if data is recorded with values from 1 microsecond up to 1 hour (3,600,000,000
  154. microseconds) in a histogram set to 3 significant digits, it will maintain a value resolution of 1 microsecond for values up to
  155. 1 millisecond and 3.6 seconds (or better) for the maximum tracked value (1 hour).
  156. The HDR Histogram can be used by specifying the `hdr` object in the request:
  157. [source,console]
  158. --------------------------------------------------
  159. GET latency/_search
  160. {
  161. "size": 0,
  162. "aggs": {
  163. "load_time_ranks": {
  164. "percentile_ranks": {
  165. "field": "load_time",
  166. "values": [ 500, 600 ],
  167. "hdr": { <1>
  168. "number_of_significant_value_digits": 3 <2>
  169. }
  170. }
  171. }
  172. }
  173. }
  174. --------------------------------------------------
  175. // TEST[setup:latency]
  176. <1> `hdr` object indicates that HDR Histogram should be used to calculate the percentiles and specific settings for this algorithm can be specified inside the object
  177. <2> `number_of_significant_value_digits` specifies the resolution of values for the histogram in number of significant digits
  178. 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
  179. the HDRHistogram if the range of values is unknown as this could lead to high memory usage.
  180. ==== Missing value
  181. The `missing` parameter defines how documents that are missing a value should be treated.
  182. By default they will be ignored but it is also possible to treat them as if they
  183. had a value.
  184. [source,console]
  185. --------------------------------------------------
  186. GET latency/_search
  187. {
  188. "size": 0,
  189. "aggs": {
  190. "load_time_ranks": {
  191. "percentile_ranks": {
  192. "field": "load_time",
  193. "values": [ 500, 600 ],
  194. "missing": 10 <1>
  195. }
  196. }
  197. }
  198. }
  199. --------------------------------------------------
  200. // TEST[setup:latency]
  201. <1> Documents without a value in the `load_time` field will fall into the same bucket as documents that have the value `10`.