Repository navigation
Conversation
102ad03 to
bca78d8
Compare
fb30215 to
d133a1d
Compare
bca78d8 to
ce188ad
Compare
d133a1d to
d61bf7b
Compare
ce188ad to
ba07130
Compare
d61bf7b to
130fc54
Compare
681ba3a to
6f174e1
Compare
4cd558c to
7f65a80
Compare
aeb762b to
bc4c4d5
Compare
7f65a80 to
569b845
Compare
bc4c4d5 to
043e1d5
Compare
569b845 to
00c2776
Compare
|
Parked as draft until Phase C (see #528). Stage 1 Pass 1 local alternatives belong to the #509 end-to-end work, which comes after finishing #511 (Phase A) and the #572 reorganization (Phase B). It will move into the 🤖 Generated with Claude Code |
00c2776 to
2918b78
Compare
b044f4f to
7b4972b
Compare
2918b78 to
21b014f
Compare
95f1f36 to
e961752
Compare
488c6eb to
14c6b88
Compare
e961752 to
c8594de
Compare
14c6b88 to
c84eb6f
Compare
c8594de to
f21c3a1
Compare
c84eb6f to
7c8ae7d
Compare
| @@ -0,0 +1,39 @@ | |||
| # Local logical alternatives (Pass 1) | |||
There was a problem hiding this comment.
you can delete this doc.
|
|
||
| pub mod maintained_population; | ||
|
|
||
| /// Local candidate generation over the unified IR. No execution timing is |
There was a problem hiding this comment.
Please rename the term "local" to be aligend with what https://github.com/ProjectASAP/ASAPPlanner/blob/docs/planner-layering-problem-definition/docs/design_docs/proposals/planner-layering.md#asapplanner-planning-stages-design use
| @@ -0,0 +1,147 @@ | |||
| //! Pass 1 local alternatives over the unified logical IR. | |||
There was a problem hiding this comment.
you should be clear this is which stage given the layer design doc: https://github.com/ProjectASAP/ASAPPlanner/blob/docs/planner-layering-problem-definition/docs/design_docs/proposals/planner-layering.md#asapplanner-planning-stages-design
…1 candidates (#663) * docs: align #509/#511/#573 docs with the decided vocabulary and Pass 1 candidates - operator-sharing.md: ReadPopulation { readout } -> EvaluatePopulation { evaluation } (matches crates/types/src/ir/asap.rs); "readout" -> "evaluation" where it names reading summary state; add the missing `filter` field to the SummaryAgg sketch. - asap-primitive-schema.md: "readout" -> "evaluation" where it names the operation (intent table header, §6.5 heading and its anchor/table row, top-k evaluation, guarantee of an evaluation). Verb "read out" kept, as in the code comments. Coverage cache text unchanged. - planner-layering.md: define an eligible sub-DAG at its first use; add the exact accumulator state candidate to the Pass 1 table and text; recompute Example 1 (Pass 1: 2 x 2 x 2 x 3 = 24, Pass 2: 24 x 2 x 3 x 3 = 432, Stage 2: 24 x 52 = 1,248). - planner-layering.md: every aggregation is its own Pass 1 target, including nested ones (Q1's per-series rate and per-job sum, Q2's per-series sum_over_time and per-job top-k), as in #561's enumerate_local_logical_candidates; the Algorithm 1 example and diagram show the four sub-DAGs, and Example 1 lists options per target. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW * docs: leave multi-measure targets out of the eligible sub-DAG definition Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW * docs: one exact option per Pass 1 target Each Pass 1 target gets a single exact option: exact accumulator state when the intent has a buildable mergeable exact accumulator, otherwise the plain exact computation. Example 1 returns to 3 / 54 / 156 with four targets. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW * docs: reflow the eligible sub-DAG paragraph Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
f21c3a1 to
5bf690c
Compare
7c8ae7d to
9d5ab8f
Compare
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The PromQL frontend's unified module was promoted to the crate root later in the stack; asap_frontend_promql::unified no longer exists. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r the export removal Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW
Summary candidates are unsized (LocalCandidate::Summary carries only the algorithm); sizing happens after Pass 2 sharing. Every pruned candidate is recorded on its target with a PruneReason (RequiresExact, NullableAvgInput). Each measure of an aggregate with a realization besides exact execution is its own target; input containing ASAP operators is rejected. avg is rewritten as exact sum/count accumulator states. The Example 1 test runs Q1 as exact, and the dev doc places composition in Pass 1. - One exact option per target: the exact accumulator (ExactAccumulator, or AvgAsSumCount for avg) when it can be built, otherwise plain Exact (NullableAvgInput prune, or no accumulator form). The plain form would duplicate "accumulator, not materialized"; Stage 2/3 decide materialization and sharing. - Per-measure filters and HAVING keep every candidate. The target records the measure's filter (applied to the state as SummaryAgg.filter) and a HavingPlacement for the aggregate's having or a Filter directly above it (the SQL frontend's HAVING form): BelowAggregate when it reads only group keys (pushed below as a row predicate), else AboveOutput (a Filter above the finalize/estimate output; approximate candidates carry guarantee = None). Composition (#575) applies them; PruneReason::FilteredAggregate is removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW
…ter Pass 1 input checks LocalLogicalTarget.having is now one HavingEntry (consumer Filter, predicate, placement) per HAVING. A consumer Filter's key-only predicate is pushed below only when every consumer of the aggregate applies it, and a global aggregate's HAVING always stays above the output. Only the adjacent form is recorded; value predicates elsewhere get guarantee None via #575, multi-level push-down is #664. Inputs with assigned materialization are rejected too (AssignedPhysicalAnnotation). Approximate accuracy needs epsilon and delta in (0, 1), and InvalidAccuracy names the root and measure. The avg nullability check runs only for avg. Tests cover SQL HAVING placement, a shared aggregate, a global constant HAVING and #509 Example 1 Q2. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW
The dev doc describes per-consumer HAVING entries, the adjacent-form scope and that TopK Hydra is added in #605. planner-layering says a filter or HAVING does not prevent accumulator or summary candidates, and Example 1 says Sum has no summary family rather than pruned ones. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW
ad0a866 to
6a79e94
Compare
9d5ab8f to
8eccd53
Compare
Why
#509 Stage 1 starts with Pass 1, per-computation candidate generation.
docs/design_docs/proposals/planner-layering.mdsays:The planner today (
MajorPass, #542) builds replacements and ranks them by cost in one search. There is no logical-only step that lists every valid per-computation candidate over the unified IR without a cost model.What
A new module,
asap_aware_mapping::logical_candidates, that enumerates Pass 1 local candidates for a workload ofQueryRoots. It takes no cost model, accuracy model, capabilities, storage policy or materialization assignment, and does not rank, size or build replacement sub-DAGs.LocalCandidate):Exact: plain exact execution of the original sub-DAG.ExactAccumulator { kind, params }: an exact mergeable accumulator state (count,sum,min,max,rate,irate,increase).Summary(SketchAlgorithm): a summary family, unsized. Pass 2 may share a summary and tighten it to the strictest consumer, so sizing happens later.AvgAsSumCount:avgrewritten as exactsumandcountaccumulator states.ExactAccumulator, orAvgAsSumCountforavg) when the intent has one and it can be built, otherwiseExact. Offering both would duplicate "accumulator, not materialized"; Stage 2/3 decide materialization and sharing. Summary families follow in stable catalog order, which carries no preference.PruneReason):RequiresExact(an exact request does not get approximate summaries) andNullableAvgInput(countcounts rows, soavgover a possibly-null input is not rewritten; the target falls back toExact).LocalChoices { alternatives, pruned }keeps both lists.LocalLogicalTarget { target, measure, choices, filter, having }): one per measure of every reachableAggregatewhose intent has a realization besides plain exact execution (even if all of them are pruned). Each measure of a multi-measure aggregate is its own target. Nested aggregates are separate targets. Producers read by scalar roots and scalar expressions are discovered, and a shared producer is one target (pointer identity).filter: the measure's own filter, applied to the state asSummaryAgg.filter.having: oneHavingEntry { filter, predicate, placement }per HAVING: the aggregate's ownhaving(no consumerFilter), then one per consumerFilterdirectly above the aggregate (the form the SQL frontend lowers HAVING to). Only this adjacentFilteris recorded.HavingPlacement::BelowAggregateonly when the predicate reads onlyby(...)group keys and, for a consumerFilter, every consumer of the aggregate applies the same predicate; it is then pushed below as a row predicate. Everything else isAboveOutput: aFilterabove the finalize/estimate output. A global aggregate's HAVING is alwaysAboveOutput, since its one output row exists even with no input rows.guarantee = Nonethrough feat(planner): Stage 1 whole-workload candidates and the stage_pipeline devtool #575; multi-level push-down is Pass 1: push down filters and HAVING across levels to create more candidates (and reuse DataFusion's filter push-down) #664.LogicalCandidateError):Structure(QueryRoot::validate_structurefailed),ContainsAsap(input already has ASAP operators),AssignedPhysicalAnnotation(a node already has an execution timing or a materialization),InvalidAccuracy { root, measure }(an approximate target needs epsilon and delta in (0, 1)).docs/develop_docs/local-logical-candidates.md(new) describes the API.planner-layering.mdnow says a filter or HAVING does not prevent the accumulator or summary candidates, and Example 1's diagram says Sum has no summary family instead of showing pruned summaries.How
enumerate_local_logical_candidates(roots)validates each root, walks every operator node reachable from its operator roots (including those referenced by scalar expressions) once, rejects physical annotations and ASAP operators, and records each node's consumers. For eachAggregateit computes the HAVING entries from the consumers, then callslocal_candidates_for_intent(intent)per measure, using the existingaccuracy_target,accuracy_budgetandsummary_candidatesfromreplacement.rs. The roots are returned unchanged with the targets.Public API:
Before this PR
No API lists Pass 1 candidates over
OperatorNode/QueryRoot. The only candidate generation is the cost-ranked search insideMajorPass.After this PR
Callers can get, for a lowered workload, every local target with its unranked candidates, its pruned candidates and reasons, and how its filters and HAVING are applied. Nothing in
MajorPasschanges; the module is not yet called by the planner.Examples (approximate =
EpsilonDelta { 0.05, 0.01 }):count, approximateExactAccumulator{Count}, CMS, Count Sketch, UnivMonExact, HLL, Theta, KMV, UnivMonExact, HLL, Theta, KMV (UnivMon not declared)Exact, UnivMonExact, KLL, DDSketchExactRequiresExact)Exact, CMS with heap, Count Sketch with heapavgover a non-null inputAvgAsSumCountavgover a nullable inputExactAvgAsSumCount(NullableAvgInput)stddev#509 Example 1 with exact accuracy: Q1
sum by (job) (rate(http_requests_total[1m]))gives two targets,ExactAccumulator{Sum}andExactAccumulator{Rate}; Q2topk by (job) (10, sum_over_time(http_requests_total[1m]))givesExactfor the top-k with both heap summaries prunedRequiresExact, andExactAccumulator{Sum}forsum_over_time.Evidence
Execution examples:
crates/asap-aware-mapping/tests/logical_candidates.rsandcrates/integration-tests/tests/logical_candidates_sql.rs(SQLHAVING src = 'a'→BelowAggregate;HAVING count(*) > 10→AboveOutput; globalHAVING false→AboveOutput). Screenshots and measurements: not applicable.Verification
approximate_count_keeps_one_exact_accumulator_and_universal_choices; intests/logical_candidates.rs: catalogs (cardinality_keeps_exact_specialized_and_universal_alternatives,frequency_statistics_keep_universal_choices,exact_quantile_stays_exact_and_approximate_keeps_both_families,topk_keeps_both_specialized_heap_choices,summary_candidates_are_unsized,avg_rewrites_to_sum_and_count_states), targets (scalar_root_producers_are_discovered_once,multi_measure_aggregate_has_one_target_per_measure,aggregate_without_realization_is_not_a_target), filters and HAVING (filtered_measure_keeps_candidates_and_records_its_filter,key_only_having_is_pushed_below_and_keeps_candidates,value_having_stays_above_output_and_keeps_candidates,having_on_one_consumer_of_a_shared_aggregate_stays_above,global_aggregate_having_stays_above), input checks (assigned_physical_annotation_asap_input_and_invalid_accuracy_are_rejected).example_1_exact_q1_keeps_exact_accumulators_onlyandexample_1_exact_q2_prunes_topk_heapslower docs: propose workload-wide planning, summary sharing, and materialization #509 Example 1 through the PromQL frontend; the three SQL HAVING tests lower through the SQL frontend.cargo fmt --check; workspace all-target Clippy with-D warnings;cargo test --workspace(1,549 passed, 0 failed, 2 ignored); dag-viewertest_render(29 passed);tools/verify_metricsql_external_consumer.shOK.Architectural decisions
Exact).Limitations and follow-up
guarantee = Noneunder value predicates).avg(for example recognizing entropy / L2 forms) and extra alternatives for opaqueExtensionintents are not added.MajorPassdoes not call this module yet.Stack: tracker #528 · main → #542 → #665 → #666 → #543 → #667 → #561.
Human review — do not complete with an agent
🤖 Generated with Claude Code
https://claude.ai/code/session_01W7qG9aFyPij5uWsyAJCxDW