Skip to content

feat(promql): native-histogram accessor functions (#43) - #78

Merged
zzylol merged 4 commits into
mainfrom
feat/histogram-accessors
Jul 3, 2026
Merged

zzylol merged 4 commits into
mainfrom
feat/histogram-accessors

Conversation

@zzylol

@zzylol zzylol commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Closes #43 — the largest un-implemented function family (~282 corpus rejections).

What

histogram_count / histogram_sum / histogram_avg / histogram_stddev / histogram_stdvar / histogram_fraction parsed but were rejected. They now lower to per-series intents. (histogram_quantile was already handled and — unlike these — also covers the classic le-bucket form, so it's unchanged.)

How

Each histogram_<accessor>(v) extracts one float per series from a native histogram, so it lowers to a per-series Aggregate{[accessor]} directly over the (instant) argument vector — the same shape as histogram_quantile. histogram_fraction(lower, upper, v) reads its bounds from args 0/1 and the vector from arg 2, carrying the bounds in the intent.

  • L3 AggIntent: + HistogramCount/Sum/Avg/StdDev/StdVar/Fraction{lower,upper}; requires()=TimeSeries, is_per_series()=true, float output columns.
  • L2 AggFunc: mirror variants; converter maps each.
  • Front end: walk_histogram_accessor + dispatch (mirrors walk_histogram_quantile).

Verified

histogram_count(rate(http_req[5m]))Aggregate{HistogramCount} over Aggregate{Rate} over TimeRange; histogram_fraction(0, 0.2, v) carries {lower:0, upper:0.2}; sum by (job)(histogram_count(v)) preserves the label. + conformance tests. Full suite green (29 binaries), clippy clean.

Note: this models intent (extract count/sum/… from a native histogram); actual native-histogram execution is an L4/runtime concern, deliberately not encoded at L3.

🤖 Generated with Claude Code

zz_y and others added 4 commits July 2, 2026 16:44
`histogram_count`/`histogram_sum`/`histogram_avg`/`histogram_stddev`/
`histogram_stdvar`/`histogram_fraction` parsed but were rejected. They now
lower to per-series intents — the largest un-implemented function family
(~282 corpus rejections, dominated by histogram_fraction).

Each `histogram_<accessor>(v)` extracts one float per series from a native
histogram, so it lowers to a per-series `Aggregate{[accessor]}` directly over
the (instant) argument vector — mirroring `histogram_quantile`, which was
already handled and (unlike these) also covers the classic `le`-bucket form.
`histogram_fraction(lower, upper, v)` carries its bounds in the intent.

- L3 `AggIntent`: + HistogramCount/Sum/Avg/StdDev/StdVar/Fraction{lower,upper};
  requires()=TimeSeries, is_per_series()=true, float output columns.
- L2 `AggFunc`: mirror variants; converter maps each.
- Front end: `walk_histogram_accessor` + dispatch.

+ conformance tests (per-series intents, fraction bounds). Full workspace
suite green; clippy --all-targets clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Collapse the two `Expr::Call` histogram arms into one
`starts_with("histogram_")` guard routing to a `walk_histogram` dispatcher
(histogram_quantile → Quantile; accessors → Histogram* intents). Same
behavior; one arm.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…s native)

Per review feedback: keep two lowerings of histogram_quantile instead of
collapsing both to a generic Quantile.

- Classic `le`-bucket form (recognised by a `by (le)` grouping, e.g.
  `histogram_quantile(φ, sum by (le) (rate(x_bucket[5m])))`) → a new
  `HistogramQuantile{q}` intent: exact cumulative-bucket interpolation, not a
  sketch-able quantile (no accuracy target).
- Native-histogram form (any other argument) → the generic `Quantile` intent
  (sketch-able), unchanged.

We can't see sample types at lowering, so the classic form is detected by its
distinctive `by (le)` grouping (`groups_by_le`).

L3 AggIntent + L2 AggFunc + converter mapping added. Updated the three tests
that asserted the classic form → Quantile, added
`histogram_quantile_classic_bucket_vs_native`, and refreshed the module
doc-table. Full workspace suite green; clippy --all-targets clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The bucket-vs-sketch discriminator recognised only a `by (le)` grouping, so a
genuinely bucketed query without an explicit `sum by (le)` fell to the
sketch-able generic `Quantile` — wrong for pre-aggregated bucket counts.

`is_classic_bucket_arg` now recurses the argument and treats it as the classic
cumulative-bucket form when it finds any of: a `by (le)` grouping, a selector
on a `_bucket` metric (bare name or `__name__`), or an `le` label matcher.
Native histograms and raw samples (no le/bucket signal) still lower to the
sketch-able `Quantile{q, accuracy}`.

Verified: `rate(x_bucket[5m])` and `rate(x{le="0.5"}[5m])` → HistogramQuantile;
native/raw metrics → Quantile. Updated the two `_bucket`-without-`sum-by-le`
tests + strengthened the classic-vs-native test. Full suite green; clippy clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@zzylol
zzylol merged commit ab5449c into main Jul 3, 2026
1 check passed
@zzylol
zzylol deleted the feat/histogram-accessors branch July 3, 2026 15:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PromQL: native-histogram accessor functions (histogram_*) unsupported

1 participant