|
| 1 | +--- |
| 2 | +title: percentiles_array |
| 3 | +description: 'This page explains how to use the percentiles_array function in APL.' |
| 4 | +--- |
| 5 | + |
| 6 | +Use the `percentiles_array` aggregation function in APL to calculate multiple percentile values over a numeric expression in one pass. This function is useful when you want to understand the distribution of numeric data points, such as response times or durations, by summarizing them at several key percentiles like the 25th, 50th, and 95th. |
| 7 | + |
| 8 | +You can use `percentiles_array` to: |
| 9 | + |
| 10 | +- Analyze latency or duration metrics across requests or operations. |
| 11 | +- Identify performance outliers. |
| 12 | +- Visualize percentile distributions in dashboards. |
| 13 | + |
| 14 | +## For users of other query languages |
| 15 | + |
| 16 | +If you come from other query languages, this section explains how to adjust your existing queries to achieve the same results in APL. |
| 17 | + |
| 18 | +<AccordionGroup> |
| 19 | +<Accordion title="Splunk SPL users"> |
| 20 | + |
| 21 | +In Splunk, you typically calculate percentiles one at a time using the `perc` function. To get multiple percentiles, you repeat the function with different percentile values. In APL, `percentiles_array` lets you specify multiple percentiles in a single function call and returns them as an array. |
| 22 | + |
| 23 | +<CodeGroup> |
| 24 | +```sql Splunk example |
| 25 | +... | stats perc95(duration), perc50(duration), perc25(duration) by service |
| 26 | +``` |
| 27 | + |
| 28 | +```kusto APL equivalent |
| 29 | +['otel-demo-traces'] |
| 30 | +| summarize percentiles_array(duration, 25, 50, 95) by ['service.name'] |
| 31 | +``` |
| 32 | +</CodeGroup> |
| 33 | + |
| 34 | +</Accordion> |
| 35 | +<Accordion title="ANSI SQL users"> |
| 36 | + |
| 37 | +Standard SQL typically lacks a built-in function to calculate multiple percentiles in a single operation. Instead, you use `PERCENTILE_CONT` or `PERCENTILE_DISC` with `WITHIN GROUP`, repeated for each desired percentile. In APL, `percentiles_array` simplifies this with a single function call that returns all requested percentiles as an array. |
| 38 | + |
| 39 | +<CodeGroup> |
| 40 | +```sql SQL example |
| 41 | +SELECT |
| 42 | + service, |
| 43 | + PERCENTILE_CONT(0.25) WITHIN GROUP (ORDER BY duration) AS p25, |
| 44 | + PERCENTILE_CONT(0.50) WITHIN GROUP (ORDER BY duration) AS p50, |
| 45 | + PERCENTILE_CONT(0.95) WITHIN GROUP (ORDER BY duration) AS p95 |
| 46 | +FROM traces |
| 47 | +GROUP BY service |
| 48 | +``` |
| 49 | + |
| 50 | +```kusto APL equivalent |
| 51 | +['otel-demo-traces'] |
| 52 | +| summarize percentiles_array(duration, 25, 50, 95) by ['service.name'] |
| 53 | +``` |
| 54 | +</CodeGroup> |
| 55 | + |
| 56 | +</Accordion> |
| 57 | +</AccordionGroup> |
| 58 | + |
| 59 | +## Usage |
| 60 | + |
| 61 | +### Syntax |
| 62 | + |
| 63 | +```kusto |
| 64 | +percentiles_array(Field, Percentile1, Percentile2, ...) |
| 65 | +``` |
| 66 | + |
| 67 | +### Parameters |
| 68 | + |
| 69 | +- `Field` is the name of the field for which you want to compute percentile values. |
| 70 | +- `Percentile1`, `Percentile2`, ... are numeric percentile values between 0 and 100. |
| 71 | + |
| 72 | +### Returns |
| 73 | + |
| 74 | +An array of numbers where each element is the value at the corresponding percentile. |
| 75 | + |
| 76 | +## Use case examples |
| 77 | + |
| 78 | +<Tabs> |
| 79 | +<Tab title="Log analysis"> |
| 80 | + |
| 81 | +Use `percentiles_array` to understand the spread of request durations per HTTP method, highlighting performance variability. |
| 82 | + |
| 83 | +**Query** |
| 84 | + |
| 85 | +```kusto |
| 86 | +['sample-http-logs'] |
| 87 | +| summarize percentiles_array(req_duration_ms, 25, 50, 95) by method |
| 88 | +``` |
| 89 | + |
| 90 | +[Run in Playground](https://play.axiom.co/axiom-play-qf1k/query?initForm=%7B%22apl%22%3A%22%5B'sample-http-logs'%5D%20%7C%20summarize%20percentiles_array(req_duration_ms%2C%2025%2C%2050%2C%2095)%20by%20method%22%7D) |
| 91 | + |
| 92 | +**Output** |
| 93 | + |
| 94 | +| method | P25 | P50 | P95 | |
| 95 | +|--------|-----------|-----------|----------| |
| 96 | +| GET | 0.3981 ms | 0.7352 ms | 1.981 ms | |
| 97 | +| POST | 0.3261 ms | 0.7162 ms | 2.341 ms | |
| 98 | +| PUT | 0.3324 ms | 0.7772 ms | 1.341 ms | |
| 99 | +| DELETE | 0.2332 ms | 0.4652 ms | 1.121 ms | |
| 100 | + |
| 101 | +This query calculates the 25th, 50th, and 95th percentiles of request durations for each HTTP method. It helps identify performance differences between different methods. |
| 102 | + |
| 103 | +</Tab> |
| 104 | +<Tab title="OpenTelemetry traces"> |
| 105 | + |
| 106 | +Use `percentiles_array` to analyze the distribution of span durations by service to detect potential bottlenecks. |
| 107 | + |
| 108 | +**Query** |
| 109 | + |
| 110 | +```kusto |
| 111 | +['otel-demo-traces'] |
| 112 | +| summarize percentiles_array(duration, 50, 90, 99) by ['service.name'] |
| 113 | +``` |
| 114 | + |
| 115 | +[Run in Playground](https://play.axiom.co/axiom-play-qf1k/query?initForm=%7B%22apl%22%3A%22%5B'otel-demo-traces'%5D%20%7C%20summarize%20percentiles_array(duration%2C%2050%2C%2090%2C%2099)%20by%20%5B'service.name'%5D%22%7D) |
| 116 | + |
| 117 | +**Output** |
| 118 | + |
| 119 | +| service.name | P50 | P90 | P99 | P99 | |
| 120 | +|-----------------------|----------|-----------|-----------|-----------| |
| 121 | +| recommendationservice | 1.96 ms | 2.965 ms | 3.477 ms | 3.477 ms | |
| 122 | +| frontendproxy | 3.767 ms | 13.101 ms | 39.735 ms | 39.735 ms | |
| 123 | +| shippingservice | 2.119 ms | 3.085 ms | 9.739 ms | 9.739 ms | |
| 124 | +| checkoutservice | 1.454 ms | 12.342 ms | 29.542 ms | 29.542 ms | |
| 125 | + |
| 126 | +This query shows latency patterns across services by computing the median, 90th, and 99th percentile of span durations. |
| 127 | + |
| 128 | +</Tab> |
| 129 | +<Tab title="Security logs"> |
| 130 | + |
| 131 | +Use `percentiles_array` to assess outlier response times per status code, which can reveal abnormal activity or service issues. |
| 132 | + |
| 133 | +**Query** |
| 134 | + |
| 135 | +```kusto |
| 136 | +['sample-http-logs'] |
| 137 | +| summarize percentiles_array(req_duration_ms, 50, 95, 99) by status |
| 138 | +``` |
| 139 | + |
| 140 | +[Run in Playground](https://play.axiom.co/axiom-play-qf1k/query?initForm=%7B%22apl%22%3A%22%5B'sample-http-logs'%5D%20%7C%20summarize%20percentiles_array(req_duration_ms%2C%2050%2C%2095%2C%2099)%20by%20status%22%7D) |
| 141 | + |
| 142 | +**Output** |
| 143 | + |
| 144 | +| status | P50 | P95 | P99 | |
| 145 | +|--------|-----------|----------|----------| |
| 146 | +| 200 | 0.7352 ms | 1.981 ms | 2.612 ms | |
| 147 | +| 201 | 0.7856 ms | 1.356 ms | 2.234 ms | |
| 148 | +| 301 | 0.8956 ms | 1.547 ms | 2.546 ms | |
| 149 | +| 500 | 0.6587 ms | 1.856 ms | 2.856 ms | |
| 150 | + |
| 151 | +This query helps identify whether requests resulting in errors (like 500) are significantly slower than successful ones. |
| 152 | + |
| 153 | +</Tab> |
| 154 | +</Tabs> |
| 155 | + |
| 156 | +## List of related functions |
| 157 | + |
| 158 | +- [avg](/apl/aggregation-function/avg): Returns the average value. Use it when a single central tendency is sufficient. |
| 159 | +- [percentile](/apl/aggregation-function/percentile): Returns a single percentile value. Use it when you only need one percentile. |
| 160 | +- [percentile_if](/apl/aggregation-function/percentileif): Returns a single percentile value for the records that satisfy a condition. |
| 161 | +- [percentiles_arrayif](/apl/aggregation-function/percentiles-arrayif): Returns an array of percentile values for the records that satisfy a condition. |
| 162 | +- [sum](/apl/aggregation-function/sum): Returns the sum of a numeric column. |
0 commit comments