Change Point Detection at 0.99 Recall in Elasticsearch ES|QL
Source: Elastic Search Labs — 2026-07-24
Summary
Elastic detailed the new CHANGE_POINT command in ES|QL (Elasticsearch's piped query language), currently in technical preview, which detects structural shifts, variance changes, and spikes/dips in any time-series metric in roughly 1ms per series with no per-series tuning required. Because it runs as an ordinary pipeline stage, its output — typed and ranked change events with p-values — can be filtered, joined against deploy markers, or fed into further aggregations using the rest of ES|QL, rather than being a one-off aggregation result. The command requires at least 22 bucketed values per series to run, and its BY clause lets it evaluate many series (e.g., every service's latency, every host's error rate) side by side in a single query.
Key Takeaways
CHANGE_POINTdetects three families of change: structural step/trend changes (a structural detector), point spikes and dips (a pulse detector), and distribution/variance changes (a level shift in a dispersion channel, relabeled as a "distribution change").- Reported accuracy: roughly 0.99 recall on labeled change events, with a measured point-wise accuracy around 0.995 for correctly classifying points as no-change, spike, or dip.
- Performance: detection runs in ~1ms per series with no manual tuning of thresholds or windows per series — a meaningful shift from traditional anomaly detection setups that need per-metric configuration.
- Minimum data requirement: at least 22 bucketed values are needed for the detector to run meaningfully; Elastic recommends staying under roughly 1,000 points per series for best results.
- Because
CHANGE_POINTemits ordinary rows in the ES|QL pipeline (not a terminal aggregation), results — including apvaluecolumn indicating statistical significance — can be filtered, ranked by significance, joined to other events like deploy markers, or aggregated further downstream in the same query. - The
BYclause lets one query evaluate many series simultaneously (e.g., one change-point scan per service or per host), instead of requiring a separate call per series as with the older change-point aggregation.
Reel Script
Hook A metric quietly shifts baseline at 3am — not a spike, just a new normal — and nobody notices until a postmortem three weeks later. Elasticsearch just shipped a query command that catches that shift in about 1 millisecond, with zero tuning.
Core Concept
CHANGE_POINT is a new command in ES|QL, Elasticsearch's pipe-based query language, that finds structural shifts, variance changes, and spikes or dips in any time-series metric. The technical trick is that change-point detection is usually finicky — you tune thresholds per metric, per service, because a "normal" swing in checkout latency looks nothing like a "normal" swing in CPU usage. CHANGE_POINT skips that setup entirely: point it at a metric with at least 22 data buckets and it classifies each point as no-change, a spike/dip, or part of a structural or distribution shift, with a p-value showing how statistically significant the change is. And because it's a pipeline stage rather than a standalone aggregation, its output rows flow straight into the rest of ES|QL — you can filter them to a time window, join them against deploy markers to see if a change lines up with a release, or rank them by significance, all in one query.
Hands-On
The reported numbers are the story here: about 0.99 recall on labeled change events, and roughly 0.995 point-wise accuracy classifying individual points as no-change, spike, or dip — meaning the detector rarely misses a real change and rarely mislabels stable points. It runs in about 1ms per series, with no per-series threshold configuration. The BY clause is what makes it operationally useful at scale: instead of running one change-point query per service, you run a single query with BY service.name and get a change-point scan across every service's latency simultaneously, each with its own detected events and p-values. The realistic workflow this enables: scan every host's error rate in one query, rank the resulting change events by p-value, then join the top hits against your deploy log to see which service regressed right after which release — all without hand-tuning a single anomaly threshold.
Takeaway
The real win isn't the detection algorithm itself, it's that Elastic made it composable — a first-class pipeline stage instead of a bolt-on aggregation you have to post-process externally. For any team running dashboards or alerting on Elasticsearch metrics, this replaces hand-rolled threshold alerts with a query you can run across every series in your fleet at once. Try CHANGE_POINT ... BY <dimension> on your noisiest metric today and see what it flags before your next on-call rotation does.
Discussion
(No questions yet — ask follow-ups via a Claude Code chat session on this repo; answers get appended here.)