Skip to content

Producer–consumer edges (u, c, i): make the edge set explicit after Pass 2 and Stage 2, with α^log and α^phys, as the domain of y_{u,c,i} #1201

Open

Description

@zzylol

Example

Query A: quantile_over_time(0.95, latency[1m]), rank error 0.01. Query B: quantile_over_time(0.99, latency[1m]) / quantile_over_time(0.50, latency[1m]), relative error 0.01. A reads the KLL quantile state over latency[1m]. B's two operands read a DDSketch quantile state over the same input: KLL bounds rank error, which does not bound the relative error of a ratio (metric rule, concepts doc Section 4).

  • The KLL state group's candidates take $\theta$ (k) from the predefined list, and the DDSketch state group's candidates take alpha (Logical memo candidate as (one operator over groups, logical properties θ) with a requirement per input; no private nodes #1203). Accuracy is checked per query at its root (constraint (K), Stage 3 MILP: implement the formulation variables x, y, z, t and rows (A)–(I) as named code over explicit edges #1204), not per edge. A meets its target at k=200 or k=345; B needs a DDSketch alpha small enough for both operands.
  • The DDSketch state group has, among others, a query-time candidate SummaryAgg(DDSketch alpha=a) with lifetime OneEvaluation(Memory).
  • In the formulation, each of B's two operand inputs has an edge $(u, c, i)$ to that producer, with $\alpha^{\log} = \alpha^{\mathrm{phys}} = 1$. A KLL candidate has an edge to each operand input too, but with $\alpha^{\log} = 0$ (metric rule). If Stage 3 sets both $y_{u,c,i} = 1$ for the DDSketch candidate, B's two operands share one build.
  • In code today, no edge exists as a value. Stage 2 stores, per input, an interned set of producer candidates filtered by timing only. Stage 3 has no $y$ variable: an edge is implied when the consumer and the producer are both chosen in one execution context.

This issue makes the producer–consumer edges explicit in the code: after Pass 2, at the logical level; after Stage 2, at the physical level, as the domain of $y_{u,c,i}$.

Representation, rules, enumeration

  • (a) Representation. Edges are stored as values:
    • LogicalEdge after Pass 2 and PhysicalEdge after Stage 2, each $(u, c, i)$ with $\alpha^{\log}$ and $\alpha^{\mathrm{phys}}$;
    • a rejected edge keeps its reason;
    • today there are only per-input producer sets, filtered by timing.
  • (b) Rules. No change. Rules stay group-level and never write edges. The edges are built once, after the last rule, and Stage 2 expands them.
  • (c) Enumeration. The admissible edges are the domain of $y_{u,c,i}$. A DAG is the set of edges with $y = 1$: exactly one per used (consumer, input).

Formulation

The physical compatibility $\alpha^{\mathrm{phys}}$, from #1200:

Consumer $c$ Producer $u$ it may read
ingestion time ingestion time
query time query time with any lifetime, or ingestion time with lifetime AcrossEvaluations

A materialized producer must also deliver on the consumer's schedule (PhysicalCandidate::delivers_on, #1200). Reusing an earlier evaluation's work is the producer's lifetime, not a requirement, so there is no "later evaluation" row.

Data structures and interfaces per stage

Stage 1, Pass 2's output (crates/types/src/stages/logical_memo_candidates.rs). Pass 2's rules stay group-level: a rule adds a candidate to a group, and every consumer of the group sees it. After the last rule, Pass 2 builds the logical edge set once:

/// (u, c, i) over logical candidates: u ∈ G_{c,i}, with α^log.
pub struct LogicalEdge {
    pub producer_candidate_id: CandidateForMemoGroupId,
    pub consumer_candidate_id: CandidateForMemoGroupId,
    pub input_index_of_consumer: usize,
    pub satisfies_logical_requirement: bool,     // α^log
}

pub struct LogicalASAPMemoCandidates {
    pub memo: Memo,
    /// Every (u, c, i) with u ∈ G_{c,i}, grouped by (c, i).
    pub edges: Vec<LogicalEdge>,
}

Stage 2 (crates/types/src/stages/physical). Each logical edge becomes the physical edges between those candidates' physical candidates. After #1203 there are no private nodes: every input of every candidate reads a group through ordinary edges.

pub struct PhysicalEdgeId(pub usize);

/// (u, c, i) over physical candidates, with both indicators.
pub struct PhysicalEdge {
    pub producer_candidate_id: PhysicalCandidateId,
    pub consumer_candidate_id: PhysicalCandidateId,
    pub input_index_of_consumer: usize,
    pub satisfies_logical_requirement: bool,     // α^log
    pub satisfies_physical_requirement: bool,    // α^phys
}

impl PhysicalASAPMemoCandidates {
    /// ℰ: every edge, in (consumer, input) order.
    pub fn edges(&self) -> impl Iterator<Item = (PhysicalEdgeId, PhysicalEdge)>;
    /// The admissible edges into input `input_index_of_consumer` of `consumer` (α^log = α^phys = 1).
    pub fn admissible_edges_into(&self, consumer: PhysicalCandidateId, input_index_of_consumer: usize) -> &[PhysicalEdgeId];
    /// The admissible edges out of `producer`: everyone who may share it.
    pub fn admissible_edges_out_of(&self, producer: PhysicalCandidateId) -> &[PhysicalEdgeId];
}

Stage 3 (crates/plan-selection): reads the edges as the domain of $y$ (#1204).

Realizer / DagOfSelectedCandidates: no change. SelectedEdge { producer, consumer, input_index_of_consumer } is already one selected $(u, c, i)$ per run.

Current vs proposed

Notation Today Proposed
$G_{c,i}$ CandidateForMemoGroup::input_groups[i] input $i$ of the candidate's expression operator (input_groups is deleted, #1207 PR 0)
logical $(u,c,i)$ after Pass 2 not represented; implied by "$u$ is a candidate of input_groups[i]" LogicalASAPMemoCandidates::edges
$P_{c,i}$ PhysicalCandidate::producer_candidates_per_input[i] (memo_candidates.rs:76): an interned ProducerCandidates set edges into $(c, i)$, all of them, before filtering
$\alpha^{\mathrm{phys}}$ compatible_timing (configurations.rs:394): same timing, or query-time consumer of MatAtIngestion; non-admissible producers are dropped, not recorded PhysicalEdge::satisfies_physical_requirement, from producer_satisfies_physical_requirements (timing, lifetime and schedule, #1200)
$\alpha^{\log}$ not computed: sizes are fixed by each consumer's private chain PhysicalEdge::satisfies_logical_requirement (#1203, #1160)
$\mathcal E$ the union of the per-input sets; no edge id edges() with PhysicalEdgeId
$y_{u,c,i}$ no variable: implied by p[ctx,c] ∧ p[ctx,u] (constraints 2–3 of #1144), plus e binaries when an input's producers span several result slots a variable per admissible edge (#1204)
who shares $u$ not queryable before Stage 3 admissible_edges_out_of(u)
one selected edge SelectedEdge per run same

Scope and acceptance

In scope:

  • LogicalEdge and the edge set built at the end of Pass 2;
  • PhysicalEdge, edges(), admissible_edges_into, admissible_edges_out_of;
  • moving producer_candidates_per_input's users onto them.

Out of scope:

Acceptance:

Related

Activity

  1. added
    documentationImprovements or additions to documentation
    optimizerWorkload optimization and plan selection
    and removed
    documentationImprovements or additions to documentation
    on Nov 3, 2026
  2. changed the title [-]Memo: represent sharing (CSE) as equal groups, required properties and producer groups; derive edges in Stage 2 and choose sharing in Stage 3[/-] [+]Formulation: a consumer input connects to a physical producer (e, p) with p = (configuration, timing, lifetime); when that producer is shared[/+] on Nov 3, 2026
  3. changed the title [-]Formulation: a consumer input connects to a physical producer (e, p) with p = (configuration, timing, lifetime); when that producer is shared[/-] [+]Producer–consumer edges (u, c, i): make the edge set explicit after Pass 2 and Stage 2, with α^log and α^phys, as the domain of y_{u,c,i}[/+] on Nov 4, 2026
  4. self-assigned this
    on Nov 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

CSEoptimizerWorkload optimization and plan selection

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions