You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Replaces the hardcoded decisions in planner/sketch.rs, planner/window.rs, and planner/promql.rs:is_supported() with an optimization-based approach that jointly selects sketch type, parameters, window config, and query method for a given RQE workload.
Query support — boolean AST-pattern match with no cost/accuracy tradeoff (planner/promql.rs:163-169)
There is also no mechanism for one streaming config to serve multiple queries (amortizing ingestion cost), and no connection between sketch-bench measurements and planner decisions.
Formulation
The problem is modeled as an uncapacitated facility-location MIP:
Inputs: List of RQEs r = (QE_r, T_r). Each QE decomposes into AQEs (atomic query expressions, deduplicated across RQEs). Each AQE has a profiled cardinality/skew θ_a, query frequency f_a = Σ 1/T_r, lookback range range_a, and accuracy tolerance ε_a.
Decision variables:
y_g ∈ {0,1} — whether streaming config g is deployed
x_{a,g} ∈ {0,1} — whether AQE a is served by config g
Each config g = (sketch_type, params, ingest_type, W, S, retention_windows, metric, label_set, spatial_filter). Every AQE also has a dedicated EXACT_a config (no sketch, queries raw data directly, IngestCost=0, Error=0) ensuring the problem is always feasible.
Both terms are cost-per-second. IngestCost covers ingestion CPU + memory (steady-state). QueryCost covers per-query CPU + memory (transient).
Constraints:
Σ_{g: Feasible(a,g)} x_{a,g} = 1 for all a (each AQE assigned to exactly one config)
x_{a,g} ≤ y_g for all a,g (can't use an undeployed config)
x_{a,g}, y_g ∈ {0,1}
Three boolean sketch properties determine cost structure: mergeable, subtractable, subpopulation_aware. Let N(s,g) = 1 if subpopulation_aware(s), else N_g (distinct label-group count from θ_a). Let n = ⌈range_a/W⌉.
The query method is determined (not a free variable) by ingest type + sketch algebra:
Ingest type
Condition
Query method
Tumbling
W = range_a
Neither (direct read)
Tumbling
W < range_a, subtractable
Subtract
Tumbling
W < range_a, mergeable
Merge
Tumbling
W < range_a, neither
Infeasible
Sliding
W = range_a (forced)
Neither
Sliding
W < range_a
Infeasible
Window constraints: W ≤ range_a (no over-coverage), W ≤ T_r (freshness).
Ingestion memory = Mem_active + Mem_retain:
Tumbling: N(s,g)·mem(s,p) active + n·N(s,g)·mem(s,p) retained
Sliding: ⌈W/S⌉·N(s,g)·mem(s,p) active + N(s,g)·mem(s,p) retained (n=1 forced)
Ingestion CPU:ρ_g · insert_cpu(s,p) (tumbling) or ρ_g · ⌈W/S⌉ · insert_cpu(s,p) (sliding). Does not scale with N(s,g).
Atomic costs (mem, insert_cpu, merge_cpu, query_cpu) come from sketch-bench.
Implementation plan
Phase 1 — Scaffolding (all-EXACT end-to-end)
Define OptimizerSolution type: deployed configs + AQE→config assignments + query method per assignment + cost estimates. This is a permanent first-class output type; a thin translator converts it to StreamingConfig + InferenceConfig.
Wire full pipeline with every AQE assigned to its EXACT_a config. Validates plumbing before real optimization logic is added.
Phase 2 — Per-AQE sketch selection (greedy, no sharing)
Candidate generation (G enumeration): per AQE, combine compatible_agg_types × parameter grid × window-size grid (W ≤ range_a, W ≤ T_r) × slide interval × retention depth. Reactive: only propose label granularities existing AQEs need.
Sketch algebraic property catalogue: define mergeable, subtractable, subpopulation_aware for each AggregationType. Encode as a lookup.
Analytical cost model: implement IngestCost(g) and QueryCost(a,g) formulas. Use stub/hardcoded atomic costs initially; real sketch-bench values come later.
Label superset matching: extend labels_compatible in asap_types::capability_matching (currently exact-match only, TODO at line 86) to support finer-grained configs serving coarser AQEs via merge.
sketch-bench cardinality sweep: add cardinality as a swept axis in BENCH_SWEEP.md; add CountMinSketchWithHeap wrapper (currently missing). Needed for real Error(a,g,θ_a) lookups and atomic cost values.
Accuracy constraint + θ_a profiling: implement Error(a,g,θ_a) ≤ ε_a using analytic bounds (CMS ε-δ) and sketch-bench empirical lookup. Add profiling step to estimate cardinality/skew per AQE before optimizer runs.
Overview
Replaces the hardcoded decisions in
planner/sketch.rs,planner/window.rs, andplanner/promql.rs:is_supported()with an optimization-based approach that jointly selects sketch type, parameters, window config, and query method for a given RQE workload.Design doc:
.design_docs/sketch-config-optimization-formulation.mdProblem statement
The planner currently hardcodes:
Statistic → AggregationTypemap inplanner/sketch.rsplanner/sketch.rs:6-14planner/window.rs)planner/promql.rs:163-169)There is also no mechanism for one streaming config to serve multiple queries (amortizing ingestion cost), and no connection between
sketch-benchmeasurements and planner decisions.Formulation
The problem is modeled as an uncapacitated facility-location MIP:
Inputs: List of RQEs
r = (QE_r, T_r). Each QE decomposes into AQEs (atomic query expressions, deduplicated across RQEs). Each AQE has a profiled cardinality/skewθ_a, query frequencyf_a = Σ 1/T_r, lookback rangerange_a, and accuracy toleranceε_a.Decision variables:
y_g ∈ {0,1}— whether streaming configgis deployedx_{a,g} ∈ {0,1}— whether AQEais served by configgEach config
g = (sketch_type, params, ingest_type, W, S, retention_windows, metric, label_set, spatial_filter). Every AQE also has a dedicatedEXACT_aconfig (no sketch, queries raw data directly,IngestCost=0,Error=0) ensuring the problem is always feasible.Objective:
Both terms are cost-per-second.
IngestCostcovers ingestion CPU + memory (steady-state).QueryCostcovers per-query CPU + memory (transient).Constraints:
Feasible(a,g)encodes: capability matching (label/metric/window/statistic), retention coverage (retention × W ≥ range_a), valid (ingest type, query method) combination, accuracy (Error(a,g,θ_a) ≤ ε_a), and optional latency SLA.Analytical cost model
Three boolean sketch properties determine cost structure:
mergeable,subtractable,subpopulation_aware. LetN(s,g) = 1ifsubpopulation_aware(s), elseN_g(distinct label-group count fromθ_a). Letn = ⌈range_a/W⌉.The query method is determined (not a free variable) by ingest type + sketch algebra:
W = range_aW < range_a, subtractableW < range_a, mergeableW < range_a, neitherW = range_a(forced)W < range_aWindow constraints:
W ≤ range_a(no over-coverage),W ≤ T_r(freshness).Ingestion memory =
Mem_active + Mem_retain:N(s,g)·mem(s,p)active +n·N(s,g)·mem(s,p)retained⌈W/S⌉·N(s,g)·mem(s,p)active +N(s,g)·mem(s,p)retained (n=1 forced)Ingestion CPU:
ρ_g · insert_cpu(s,p)(tumbling) orρ_g · ⌈W/S⌉ · insert_cpu(s,p)(sliding). Does not scale withN(s,g).Query CPU:
N(s,g) · query_cpu(s,p)N(s,g) · ((n-1) · merge_cpu(s,p) + query_cpu(s,p))N(s,g) · (subtract_cpu(s,p) + query_cpu(s,p))Query memory (transient):
N(s,g) · mem(s,p)n · N(s,g) · mem(s,p)2 · N(s,g) · mem(s,p)Atomic costs (
mem,insert_cpu,merge_cpu,query_cpu) come from sketch-bench.Implementation plan
Phase 1 — Scaffolding (all-EXACT end-to-end)
OptimizerSolutiontype: deployed configs + AQE→config assignments + query method per assignment + cost estimates. This is a permanent first-class output type; a thin translator converts it toStreamingConfig + InferenceConfig.QueryRequirements, decompose QEs into AQEs, deduplicate, computef_a.EXACT_aconfig. Validates plumbing before real optimization logic is added.Phase 2 — Per-AQE sketch selection (greedy, no sharing)
Genumeration): per AQE, combinecompatible_agg_types× parameter grid × window-size grid (W ≤ range_a,W ≤ T_r) × slide interval × retention depth. Reactive: only propose label granularities existing AQEs need.mergeable,subtractable,subpopulation_awarefor eachAggregationType. Encode as a lookup.IngestCost(g)andQueryCost(a,g)formulas. Use stub/hardcoded atomic costs initially; real sketch-bench values come later.Feasible(a,g)predicate: reusewindow_compatible,spatial_filter_compatible,topk_weighting_compatiblefromasap_types::capability_matching(PR 258 add capability based matching to asap query engine instead of matching incoming queries against pre configured queries in inference config #259). Label matching stays exact for now. Accuracy check stubbed to always pass.IngestCost(g) + f_a · QueryCost(a,g).Phase 3 — Full MIP with sharing and accuracy
good_lp + coin_cbcfacility-location MIP. Enables cross-AQE config sharing.labels_compatibleinasap_types::capability_matching(currently exact-match only, TODO at line 86) to support finer-grained configs serving coarser AQEs via merge.BENCH_SWEEP.md; addCountMinSketchWithHeapwrapper (currently missing). Needed for realError(a,g,θ_a)lookups and atomic cost values.θ_aprofiling: implementError(a,g,θ_a) ≤ ε_ausing analytic bounds (CMS ε-δ) and sketch-bench empirical lookup. Add profiling step to estimate cardinality/skew per AQE before optimizer runs.Out of scope for v1
OneTemporalOneSpatialpipeline decomposition into two sharing stagesw₁..w₄only)