Repository navigation
feat(types): family-capability table and executor tumbling pane merges - #696
Merged
Merged
Conversation
Add a generic family-capability table keyed by the state family: whether the family merges, how the merged inputs' selections must relate (disjoint, or overlap allowed for idempotent families), how a merged state's error relates to its parts', and whether it subtracts. Hydra over Count-Min or Count-Sketch merges; Hydra over KLL fails closed. The IR stays permissive: SummaryMerge accepts any family and consumers consult the table. SummaryCoverage skips the disjointness check for families whose merge allows overlap, and the union of identical selections is that selection. Execution timing validates SummaryMerge: it reads summary state at either phase, and a merge at ingestion time needs every input at ingestion time.
A per-entity SummaryAgg reads its raw rows through one TimeShift, so a tumbling pane builds over its shifted window. A temporal SummaryMerge groups pane states by series and takes the run scope's timestamp, as a per-series SummaryAgg does. Both the query-time and the precompute lowering run a merge only when the family-capability table gives the family a sound merge.
A merged UnivMon keeps the guarantee of readouts from its additive layer-0 counters (L2, point counts), while readouts from its per-layer heaps (distinct count, entropy, top-k) are uncertified after a merge. MergeCapability records the heap readouts' merged error, and FamilyCapability::merged_error answers it per readout. KMV merges with the guarantee of one build over the union: asap_sketchlib's KMV hashes with one shared seed and KMV::merge keeps the k smallest distinct hashes, so overlapping inputs are allowed.
… in time Add MergedError::Approximate: the merge is allowed but the merged readout is evidence only. Count-Min and Count-Sketch with heap now merge, with approximate top-k and point counts that keep their guarantee. At the pinned asap_sketchlib, UnivMon::merge rebuilds each layer's heap from the parts' heap keys and L2 and distinct count read those heaps, so every UnivMon readout is approximate after a merge; a TODO marks where the pin move past upstream #221 restores L2. Rate and Increase merge exactly (IncreaseAccumulator::merge_pair joins time-ordered windows with reset handling) when their inputs are disjoint in time: SelectionRelation::DisjointInTime, checked by coverage as CoverageError::NotDisjointInTime. IRate stays without a merge. The UnimplementedOperator doc no longer lists SummaryMerge.
…pane merges A SummaryMerge with no inputs is an invalid DAG instead of an index panic. Tests cover an exact Increase pane merge against the single build, compacted KLL panes (k = 200, 60 x 1000 values) within the calibrated rank error, and IRate as the precompute family without a merge.
Counter states (Rate, Increase) join consecutive windows pairwise, which is exact only in time order. A merge over a family whose inputs must be disjoint in time now orders its input states by their earliest sample time before folding, so panes merged in any input order give the single-build result.
zzylol
force-pushed
the
stack/g6a-capability-merges
branch
from
October 15, 2026 02:55
82e9b25 to
5b5fc9f
Compare
This was referenced Oct 15, 2026
Closed
Contributor
Author
|
Interface and efficiency review of this PR. These items land in the Pass 2 Interfaces
Efficiency
Minor: this PR body's interface comment says heap readouts cover "cardinality, entropy, top-k". The code ( |
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.
Supersedes #592 and #591, which stay open for now. Part of #509 (Example 3, tumbling panes).
Why
In #509 Example 3, a window is built as tumbling panes: one
SummaryAggper pane, combined by aSummaryMerge. Before the planner can emit that form, three things must hold:Planner rules and the executor need one place that says, for each family:
Design decision: a generic family-capability table, with the IR left permissive.
The executor must run a pane plan.
Execution timing must accept
SummaryMerge.What
types::post_asap::family_capabilityaddsFamilyCapability::of(&FieldDataType), which returns:merge: Option<MergeCapability>:inputs:SelectionRelation::{Disjoint, DisjointInTime, OverlapAllowed}error:MergedError::{Exact, SameAsUnionBuild, Approximate}heap_readouts: the merged error of readouts that read heavy-hitter heaps (distinct count, entropy, top-k), when it differs fromerrorsubtractableFamilyCapability::merged_error(&SketchStatistic)gives the merged error per readout.Approximatemeans the merge is allowed but the merged readout is evidence only, for Stage 3 to judge (docs: propose workload-wide planning, summary sharing, and materialization #509 planner-layering.md,SummaryMerge).asap_sketchlibpin)SummaryMergestays structurally valid for any family; the IR does not reject a merge by family.SummaryMerge.SummaryMergewith no inputs is an invalid DAG, not a panic.How
Selection relations (from types: evaluation-relative coverage time and mergeable summary families #592).
SummaryCoverage::deriveconsults the table:OverlapAllowedskips the disjointness check, and the union of identical selection boxes is that box.DisjointInTimerequires the inputs' time windows not to overlap (CoverageError::NotDisjointInTime). Counter states join consecutive windows in time order (IncreaseAccumulator::merge_pair, with reset handling), so states disjoint only by a label would interleave in time.TimeRangeoverTimeShift.Heaps. A heavy-hitter heap keeps only the heavy items of its own part, so an item that is heavy over the window but in no single pane is lost.
UnivMon at the pin. At the pinned
asap_sketchlib(5f03ccb),UnivMon::mergerebuilds each layer's heap from the parts' heap keys, and L2 and distinct count go through that heap. A review measurement (heap 8, 20 panes) found:A
TODO(univmon-certification)marks the change for when the pin moves past upstream feat: rewrite uniqExact to COUNT(DISTINCT ...) #221: L2 becomes same as one build over the union, distinct count is revisited, and entropy stays approximate.KMV.
asap_sketchlib's KMV (src/sketches/kmv.rsat5f03ccband932ab4a) hashes every item withCANONICAL_HASH_SEED.KMV::mergekeeps the k smallest distinct hashes, which is the state of the union, and it ignores repeated hashes.Timing.
SummaryMergeinputs must be summary state at either phase. A merge at ingestion time needs every input at ingestion time. This follows refactor(planner): replace the summary lifecycle with #509 materialization options #667'sMaterializationassignment, soapply_materialization_timingscovers both cases:Executor.
SummaryAgglooks through oneTimeShiftto itsScan.SummaryMergelowers to union → merge by series → scope timestamp, the same pattern as a per-seriesSummaryAgg.require_sound_mergeis shared by the query-time and precompute lowerings.SummaryMergesorts its input states by their earliest sample time (ExactAccumulator::counter_window_start) before folding them withmerge_pair.Key code interfaces added / modified
crates/types/src/post_asap/family_capability.rs(new),mod.rscrates/types/src/ir/summary_coverage.rscrates/types/src/ir/timing.rs,post_asap/execution_data_state.rscrates/asap-physical-operators/src/physical_planner/mod.rs,precompute.rscrates/asap-physical-operators/src/summary_kernels/exact.rs,operators/summary/mod.rsUsage, end to end (a 5-minute query answered from five 1-minute panes; numbers from a scratch run of
tests/tumbling_pane_merge.rs's harness at3a25450d). The planner's window-composition rule that emits panes comes later, so step 2 rewrites the selected plan into panes by hand, as that test does:Before this PR
apply_materialization_timingsreturnedUnimplementedOperator { "SummaryMerge" }, so no pane plan could be exported.TimeShiftwith "per-entity summary requires a resolved source".PossibleOverlap.After this PR
A pane plan (5 one-minute panes under a
SummaryMerge) exports and executes forsum_over_time(m[5m]),increase(m[5m])andquantile_over_time(0.99, m[5m]). It returns the same per-series rows as the single 5-minute build, timestamped at the evaluation time, in two ways:Verification
Each new test was written first and failed before its change.
crates/types/tests/summary_merge_structure.rs:SummaryMergetiming under the query-time, B1 and ingestion-time assignments.crates/types/tests/summary_coverage.rs: Increase panes merge when disjoint in time, but not when disjoint only by a label.crates/integration-tests/tests/tumbling_pane_merge.rs: exact Sum, exact Increase and quantile pane plans match the single build on both paths.crates/asap-physical-operators/tests/:physical_semantics.rs: 60 compacted KLL panes (k = 200, 1000 values each) merge within the calibrated 99% rank error, 2.296/k^0.9723.precompute_population.rs: a precompute merge of IRate state is rejected, and one of Sum state compiles.summary_projection.rs: aSummaryMergewithout inputs is rejected.physical_semantics.rs: Increase panes A, B, C merged in the order A, C, B, with a counter reset inside B, give the single build's increase.precompute_population.rs).5b5fc9f6, rebased on main80fc72e1:cargo fmt --all -- --check: passed.cargo clippy --workspace --all-targets --all-features --locked -- -D warnings: passed.cargo nextest run --workspace: 1663 passed, 46 skipped.Limitations and follow-ups
FamilyCapabilitylater.asap_sketchlibfeat: rewrite uniqExact to COUNT(DISTINCT ...) #221 (see the TODO).