Repository navigation
Arithmetic over an approximate quantile has no accuracy guarantee, so with guarantees enforced the ratio-of-quantiles query plans only exact (1 of 49 Pass 1 DAGs valid) #1034
Description
Problem, by example
Workload tools/dag-viewer/memo-examples/promql/ratio-of-quantiles-5m.json: one query every minute, with ε = 0.01, δ = 0.001 and no metric set.
avg by (job) (quantile_over_time(0.5, data[5m]) / quantile_over_time(0.5, data[5m]) + quantile_over_time(0.9, data[5m]))
Measured on main (f49900b) with guarantees enforced and every Pass 1 DAG costed:
stage_pipeline --workload tools/dag-viewer/memo-examples/promql/ratio-of-quantiles-5m.json \
--deployment-capabilities '{"raw_data_retained":true,"query_time_results_retained":false}' \
--cost-model aws-fargate-us-east-1 --enforce-accuracy-guarantees --price-enumerated 49 --out ratio.json| Pass 1 DAGs | Valid | Rejected |
|---|---|---|
| 49 (7 quantile 0.5 candidates × 7 quantile 0.9 candidates) | 1: the all-exact one | 48, all with no_accuracy_guarantee |
Every DAG that uses a sketch (KLL or DDSketch) for either quantile is rejected:
Q1: the output has no guarantee, and the deployment has no evidence for it, so it cannot meet target AccuracyTarget { accuracy_metric: None, max_error: 0.01, failure_probability: Some(0.001), accuracy_scope: WholeResult }
In DAG E2 (KLL for quantile 0.9, the rest exact), the guarantee is lost at the +:
| Node | Guarantee |
|---|---|
q0.5 / q0.5 (BinaryOp Div, exact operands) |
exact |
quantile 0.9 (SummaryEstimate, KLL) |
rank error, KLL |
… + q0.9 (BinaryOp Add) |
none |
avg by (job) and the root |
none |
So with guarantees enforced, any query that does arithmetic on an approximate quantile can only be planned exact. Without enforcement, the same search picks sketch plans freely: 169 of 169 Pass 2 DAGs were valid, and the selected plan cost 78.93/s against 237.63/s for the exact plan (#1004 measurements).
Why
arithmetic_guarantee (crates/logical-asap-optimization/src/per_computation_candidates.rs:2735) composes value errors only. Its doc says so: "a relative error shifted by a constant or added to another, a rank error … has none".
- A rank error (KLL) says nothing about how far the returned value is from the true quantile's value. Adding it to another value gives no bound.
- A relative error (DDSketch) added to another value has no closed-form bound either.
operand_domain_statisticalready leaves products and quotients of value errors symbolic, so that Stage 3 can bind them from declared source facts. Rank errors are excluded ("an operand's error has no value form").
This is sound behaviour, not a wrong result. It does mean the planner never uses a sketch for these queries.
Options
- Keep as is, and say so. Document in
planner-layering.mdthat arithmetic over a rank or relative error has no guarantee, so such queries plan exact under enforcement. The viewer already shows the rejection reason per enumerated DAG. - Relative + value, through declared bounds. Leave
x + ywith a relative-errorxsymbolic on|x|'s upper bound, asoperand_domain_statisticdoes for products. Stage 3 then binds the bound from declared source facts (for example a declared value range). This covers DDSketch. - Rank → value, through a declared distribution fact. Turn a rank error ε into a value error using a declared bound on the value distribution (for example the largest gap between the values at ranks q ± ε), then compose as an absolute error. This covers KLL, but needs a new source fact.
Recommendation: (1) now, since it costs nothing and is correct. (2) after that, since it reuses the existing symbolic-statistic path. (3) only with a workload that needs it.
Scope and acceptance
- For (1): the doc paragraph, plus a test that the ratio workload under
--enforce-accuracy-guaranteesselects the all-exact plan with the 48no_accuracy_guaranteerejections. - For (2): a unit test in
per_computation_candidates.rswhereDDSketch q0.9 + exactgets a symbolic absolute bound, and a stage-pipeline test where declaring the value bound makes a DDSketch DAG valid on this workload.
Related
- Found by
--price-enumerated(stage_pipeline: price every enumerated candidate DAG and flag any cheaper than the selected plan #1004 / feat(devtools): stage_pipeline --price-enumerated prices each enumerated memo choice and flags any cheaper than the selected plan #1028). - Workload from Memo: convert memo-group candidates into the vector of all candidate DAGs #1002 / stage_pipeline: write the memo after each step, the selected choice and the enumeration #1003; the memo example is in Tracking: DAG viewer shows the memo after each step and every candidate DAG it stands for #1008.
Activity
zzylol commentedon Oct 29, 2026
More evidence, with a rank target this time (main
61ee27f30,--max-error 0.01 --failure-probability 0.001 --accuracy-metric rank --enforce-accuracy-guarantees --series-count 10000 --sample-interval-ms 15000):quantile_over_time(0.5, a[5m])quantile_over_time(0.5, a[5m]) - quantile_over_time(0.5, a[5m])no_accuracy_guaranteequantile_over_time(0.99, a[5m]) - quantile_over_time(0.5, a[5m])no_accuracy_guaranteeThe memo offers half-budget sketches for the two-quantile difference:
Kll(failure_probability=0.0005 k=746),Kll(… k=1184)andDDSketch(alpha=0.004962809790010847)at budget_share 2. But none can be used, because the difference has no guarantee:From the code, this is intended, not a missing rule.
arithmetic_guarantee(per_computation_candidates.rs:2728-2729) gives no guarantee to "a rank error" under arithmetic.metric_meets(accuracy/mod.rs:55-69) says that "a rank error has no distribution-free value error". A rank target onq0.99 − q0.5is also not well defined: the difference is a value, not a rank, so no rank-error bound applies to it. A rank target on a difference can only be met by exact. The useful path is still options 2 and 3 here: state the target in value terms, and turn the rank error into a value error from a declared distribution fact.So this adds a data point for option (1), documenting it: a rank target on arithmetic over quantiles always plans exact. The stage viewer shows only
no_accuracy_guarantee, which does not tell the user that the target metric is the reason.🤖 Generated with Claude Code