Advanced
Window Statistics With WINDOW BY ... COMPUTE
`WINDOW BY ... COMPUTE` attaches window-level statistics back to individual events. Unlike `GROUP BY TumblingWindow`, it preserves per-event multiplicity and original event timestamps.
Guide
`WINDOW BY ... COMPUTE` attaches window-level statistics back to individual events. Unlike `GROUP BY TumblingWindow`, it preserves per-event multiplicity and original event timestamps.
Basic outlier query:
SELECT * INTO output
FROM input TIMESTAMP BY ts
WINDOW BY TumblingWindow(Duration(minute, 1))
COMPUTE avg = AVG(value), std = STDDEV(value)
WHERE (value - avg) / std > 1.7Tested input values:
{"ts":638712864000000000,"value":10}
{"ts":638712864100000000,"value":12}
{"ts":638712864200000000,"value":11}
{"ts":638712864300000000,"value":100}Tested behavior: only the `100` row is emitted, and the original event timestamp is preserved.
WINDOW BY ... COMPUTE Grammar
FROM <input> TIMESTAMP BY <field>
WINDOW BY [<partition-field>, ... ,] TumblingWindow(Duration(<unit>, <value>)[, Offset(<unit>, <value>)])
COMPUTE <alias> = <aggregate-expression>[, ...]
[WHERE <condition-using-original-fields-and-compute-aliases>]Constraints validated by tests:
- `WINDOW BY` requires `TIMESTAMP BY`.
- `COMPUTE` requires `WINDOW BY`.
- `WINDOW BY` requires `COMPUTE`.
- `WINDOW BY` queries cannot use `GROUP BY`.
- `WINDOW BY` queries cannot use `HAVING`.
- `COMPUTE` aliases must be unique.
- `COMPUTE` expressions must be aggregate expressions or derived from aggregates.
- Window compute queries cannot project aggregate expressions directly; project compute aliases instead.
Percentile
SELECT * INTO output
FROM input TIMESTAMP BY ts
WINDOW BY TumblingWindow(Duration(minute, 1))
COMPUTE p95 = PERCENTILE(value, 0.95)
WHERE value > p95Tested input values `1`, `2`, `3`, and `100` emit only the top-tail row:
{"ts":4,"value":100}Median and MAD
SELECT value, mad, ts INTO output
FROM input TIMESTAMP BY ts
WINDOW BY TumblingWindow(Duration(minute, 1))
COMPUTE med = MEDIAN(value), mad = MAD(value)
WHERE ABS(value - med) / mad > 3Tested input values `10`, `11`, `12`, `13`, and `100` emit the outlier row:
{"value":100,"mad":1,"ts":5}Regression
SELECT * INTO output
FROM input TIMESTAMP BY ts
WINDOW BY grouping, TumblingWindow(Duration(minute, 1))
COMPUTE slope = REGRESSION_SLOPE(ts, value)
WHERE ABS(slope) > 0.5The tests use two groups. The group with a rising value trend emits all four events from that group; the flat group is filtered out.
Regression intercept is also used in the presentation statistics tests:
SELECT ts, server.region, request.path, request.duration_ms, slope, intercept INTO output
FROM input TIMESTAMP BY ts
WINDOW BY server.region, request.path, TumblingWindow(Duration(minute, 1))
COMPUTE slope = REGRESSION_SLOPE(request.seq, request.duration_ms), intercept = REGRESSION_INTERCEPT(request.seq, request.duration_ms)
WHERE ABS(slope) > 15
AND ts >= 638713297200000000 AND ts < 638713297800000000Partitioned Window Compute
Window statistics can be partitioned by one or more fields.
SELECT device, value, avg, std, ts INTO output
FROM input TIMESTAMP BY ts
WINDOW BY device, TumblingWindow(Duration(minute, 1))
COMPUTE avg = AVG(value), std = STDDEV(value)
WHERE value >= avgTested behavior:
- Device `A` values `10`, `20`, `30` compute `avg = 20`; rows `20` and `30` emit.
- Device `B` values `100`, `100`, `100` compute `avg = 100`; all three rows emit.
{"device":"A","value":20,"avg":20,"std":...,"ts":2}
{"device":"A","value":30,"avg":20,"std":...,"ts":3}
{"device":"B","value":100,"avg":100,"std":...,"ts":4}
{"device":"B","value":100,"avg":100,"std":...,"ts":5}
{"device":"B","value":100,"avg":100,"std":...,"ts":6}Multiple Computed Statistics
SELECT region, value, median_value, mad_value, p95, ts INTO output
FROM input TIMESTAMP BY ts
WINDOW BY region, TumblingWindow(Duration(minute, 1))
COMPUTE median_value = MEDIAN(value), mad_value = MAD(value), p95 = PERCENTILE(value, 0.95)
WHERE value >= median_valueThis tested query emits rows at or above each region's median while carrying computed median, MAD, and percentile context.
Operational Statistics Examples
The statistical presentation tests include several production-style examples. These are useful website examples because they are realistic and test-backed.
Z-score latency outlier:
SELECT ts, server.region, request.path, request.duration_ms, avg, std INTO output
FROM input TIMESTAMP BY ts
WINDOW BY server.region, request.path, TumblingWindow(Duration(minute, 1))
COMPUTE avg = AVG(request.duration_ms), std = STDDEV(request.duration_ms)
WHERE (request.duration_ms - avg) / std > 2
AND ts >= 638713296000000000 AND ts < 638713296600000000Robust median/MAD outlier:
SELECT ts, server.region, request.path, request.duration_ms, med, mad INTO output
FROM input TIMESTAMP BY ts
WINDOW BY server.region, request.path, TumblingWindow(Duration(minute, 1))
COMPUTE med = MEDIAN(request.duration_ms), mad = MAD(request.duration_ms)
WHERE ABS(request.duration_ms - med) / mad > 6
AND ts >= 638713296600000000 AND ts < 638713297200000000Correlated latency, CPU, and memory anomaly:
SELECT ts, server.region, request.path, request.duration_ms, server.cpu, server.memory, latency_avg, latency_std, cpu_avg, mem_avg INTO output
FROM input TIMESTAMP BY ts
WINDOW BY server.region, request.path, TumblingWindow(Duration(minute, 1))
COMPUTE
latency_avg = AVG(request.duration_ms),
latency_std = STDDEV(request.duration_ms),
cpu_avg = AVG(server.cpu),
mem_avg = AVG(server.memory)
WHERE
(request.duration_ms - latency_avg) / latency_std > 1.1
AND server.cpu > cpu_avg * 1.15
AND server.memory > mem_avg * 1.10
AND ts >= 638713297800000000 AND ts < 638713298400000000Tail latency:
SELECT ts, server.region, request.path, request.duration_ms, p90 INTO output
FROM input TIMESTAMP BY ts
WINDOW BY server.region, request.path, TumblingWindow(Duration(minute, 1))
COMPUTE p90 = PERCENTILE(request.duration_ms, 0.90)
WHERE request.duration_ms > p90
AND ts >= 638713298400000000 AND ts < 638713299000000000