Conversation
…eadout
Aggregate{TopK} now derives partition keys + item identity + value, the
shape #579 gave sketch readouts, so every top-k realization of one query
has one schema and an aggregate over a pass-through top-k composes.
The keyed-heap state column keeps its topk_<k> name.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sult A top-k readout now reports min(input rows, k x groups) rows, as exact Sort -> Limit does, so its consumers are priced alike whichever realization is chosen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tire MajorPass The facade's default pass is now StagePipeline: Stage 1 inventory, selection by a dynamic program over target nesting priced through Stage 2 + Stage 3, then the winner built with identical producers merged and checked in full. The program checks that every target and the target beneath it combine additively and admissibly; otherwise it enumerates (at most 64 combinations) or flags the result as not guaranteed optimal. - PlanningModels moves into plan_selection; Stage 3 does not read cost. - Choice enumeration moves into logical_candidates; the devtool reuses select_exhaustive. - Build, check and pricing failures reject one candidate, not the plan. - PlanOutput carries the Selection. - Sharing tests that depend on Pass 2 or on summaries being selected are ignored with #580. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
#572 (update of 2026-10-04): following #509, only Stage 3 prices plans.
MajorPassis retired, and the facade runs the stage pipeline (Stage 1logical_candidates→ Stage 2physical_candidates→ Stage 3plan_selection). Selection uses a tree dynamic program, not greedy search.What
StagePipeline(pass/stage_pipeline.rs) replacesMajorPass. It is the registry built-in"stage-pipeline"and the facade default.select_plan, and merges identical producers after composition.PlanOutput.selectionreports how the plan was chosen.plan_selection::select_planis the tree DP; see Selection algorithm below.plan_selection::select_exhaustivebuilds and prices every combination, in mixed-radix order, capped at 64. The devtoolstage_pipelineand the tests use it; the enumeration now lives inlogical_candidates(enumerate_choices,choice_index).PlanningModelsmoves toplan_selectionand is re-exported frompass. Its doc states thatcostis unused because Stage 3 prices analytically.SelectionErrornow has onlyNoValidCandidate.Aggregate{TopK}now derives the selected-rows schema that fix(ir): top-k sketch readouts return selected rows; Example 1 expectations follow planner output #579 gave sketch readouts: partition keys + item identity +value: Float64. It previously had a packedtopk_<k>: Utf8column, which madecount(topk …)over a pass-through top-k fail to compose.pass/major.rsis deleted.Selection algorithm
best(t, c) = local(t, c) + Σ_{u beneath t, read by c} min_c' best(u, c')local(t, c)is the change in workload cost when onlyttakes alternativec.The program is exact under three assumptions:
pricesums per-node costs.Guard. For every target and the target beneath it, every pair of choices is built. The pair must cost
base + local + local(relative tolerance 1e-9) and be admissible exactly when both single choices are. On a mismatch:SelectionMethod::Exhaustive);TreeDpNotGuaranteedOptimal { reason }.Full check. The winner is then built with identical producers merged and checked by Stage 3. If that fails, every combination is built (≤ 64), or the result is flagged.
Probe of assumption 2: every combination is priced and compared with base + the sum of single-target changes. Ingestion is 1 row/s.
count(topk by (job) (10, sum_over_time(m[1m])))sum(topk by (job) …)quantile(0.5, topk by (job) …)max(topk(3, …))/count(topk(3, …))sum by (job) (rate(m[1m]))topk by (job) (10, sum_over_time(m[1m]))Equivalence tests (
planner/tests/stage_pipeline_selection.rs) check that the program's choice equals the exhaustive winner's, with methodTreeDp:sum by (job) (rate(x[1m]))[1, 0]count(topk by (job) (10, sum_over_time(m[1m]))), 3 and 1M series[0,0,1]and[0,0,0][1,1,0,1][0, 0]Each guard path has a unit test: coupling with ≤ 64 combinations → exhaustive; coupling with > 64 → flagged; uncoupled →
TreeDp. The Example 1 program needs 9 builds where enumeration needs 24.Before / after (#509 Example 1 through
e2e_plan)Before this PR.
MajorPassran the replacement search withDefaultCostModel.SummaryAgg(Sum)overFinalizeExactAccumulator(Rate).Limit ← Sort ← FinalizeExactAccumulator ← SummaryAgg.After this PR.
StagePipelineselects P20 byTreeDp, at 79.4011 cpu_ms per workload evaluation.FinalizeExactAccumulator(Sum)overFinalizeExactAccumulator(Rate).Limit ← Sort ← FinalizeExactAccumulator ← SummaryAgg.PlanOutput.selectionreports the choice.The regenerated viewer fixture selects the same plan (P20, same total). Only the top-k schemas in it changed.
Behaviour changes (follow-up: #580)
Aggregate{TopK}schema:topk_<k>: Utf8→ partition keys +$promql_series_identity(SQL: item columns) +value: Float64$promql_series_identityMajorPasschose summariesSUMbatchsummary_sharing.rsPlanningModels.costunused by the default passTests:
quantiles_share_one_producer_sized_for_the_strictest_consumer,cross_series_p50_and_p99_share_one_producer,sql_p50_and_p99_share_one_producer.quantiles_with_equal_params_share_one_producer,different_producers_are_not_shared,identical_ungrouped_queries_share_their_producers,identical_sql_percentiles_share_one_producer.operator_design_examples::batch_planning_replaces_and_shares_summary_operators→batch_planning_selects_and_executes_each_plan: Stage 3 picks the raw SUM, and both plans still execute to 31 and 60.e2e_plan::facade_plans_match_cost_only_selection→facade_plans_match_exhaustive_stage_pipeline_selection: it no longer asserts that summaries are chosen.planspace_series_identity_heap::carries_identityignores the root, because a top-k root now returns identity whatever realizes it.pass/major.rshad no tests.planner_layering_example1.rsand its acceptance doc are untouched; they still copy the enumeration and could switch toenumerate_choices. Gate:fmt,clippy -D warnings,cargo test --workspace(1533 passed, 12 ignored) and the viewer tests are green.🤖 Generated with Claude Code