feat: exact percentile and distinctCount aggregation ops

Add 'percentile' (with a 'p' fraction in [0,1]) and 'distinctCount' to the
aggregation engine. Both are exact, computed from a per-metric value multiset
(MetricState.valueCounts) maintained incrementally and delete-safe; percentile
uses numpy-linear interpolation. The multiset is JSON-serializable so results
survive persistence. 35 aggregation unit tests pass.
This commit is contained in:
David Snelling 2026-05-26 16:18:47 -07:00
parent bca3736f4c
commit fe4f5df8c9
3 changed files with 135 additions and 2 deletions

View file

@ -696,7 +696,18 @@ export interface TraverseParams {
/**
* Supported aggregation operations
*/
export type AggregationOp = 'sum' | 'count' | 'avg' | 'min' | 'max' | 'stddev' | 'variance'
export type AggregationOp =
| 'sum'
| 'count'
| 'avg'
| 'min'
| 'max'
| 'stddev'
| 'variance'
/** Exact percentile (requires `p` in `[0,1]` on the metric def) — value-multiset, delete-safe. */
| 'percentile'
/** Exact count of distinct values — value-multiset, delete-safe. */
| 'distinctCount'
/**
* Time window granularity for GROUP BY time dimensions
@ -752,8 +763,10 @@ export interface AggregateDefinition {
export interface AggregateMetricDef {
/** Aggregation operation */
op: AggregationOp
/** Metadata field to aggregate (required for sum/avg/min/max; optional for count) */
/** Metadata field to aggregate (required for all ops except count) */
field?: string
/** Percentile fraction in `[0, 1]` — required when `op === 'percentile'`, ignored otherwise. */
p?: number
}
/**
@ -767,6 +780,12 @@ export interface MetricState {
max: number
/** Running M2 for Welford's online variance (sum of squared differences from mean) */
m2?: number
/**
* Value multiset (String(value) occurrence count) for exact percentile + distinctCount.
* Maintained only for `percentile`/`distinctCount` metrics. JSON-serializable; mirrors
* Cortex's `value_counts` so JS and native agree bit-for-bit.
*/
valueCounts?: Record<string, number>
}
/**