Class PromqlAttributesTranslationContext
java.lang.Object
org.elasticsearch.xpack.esql.optimizer.rules.logical.promql.PromqlAttributesTranslationContext
The label-grouping fragment of the PromQL -> ESQL syntax-directed translation.
A PromQL query such as sum by(cluster) (avg without(region) (cpu_util)) is a chain of aggregates over a single
leaf selector. PromQL grouping is dynamic: the concrete set of label names lives on disk and is unknown at
plan time, so we cannot list it efficiently. Instead, the translation carries the aggregation shape symbolically
and resolves it against real columns only at the very end.
Abstract domain: label sets
A label set is a plainList<Attribute> plus two "top" sentinels: UNIVERSE for the full label universe
T ("every runtime label") - the one set we can never enumerate at plan time - and SCALAR for a
subtree that exposes no series identity at all (a literal/scalar or a bare NONE). T is realised
physically by the opaque _timeseries grouping key (see TranslateTimeSeriesWithout), which is why it
contributes no concrete columns when resolved. The static union/intersect/minus helpers
implement set algebra over these values (labels are compared by field name). T minus a finite set stays
T: the removed labels are never listed, and - because every BY forces a finite scope down its
subtree - that complement is never observed, so a single UNIVERSE sentinel is enough.
The two attributes
The translation is an L-attributed syntax-directed definition. Two attributes flow through the aggregate tree, modelled here as distinct immutable value types:PromqlAttributesTranslationContext.InheritedAttributes- the inherited attribute, threaded down the chain. It answers "what must the subtree below preserve?". Each aggregate narrows it (PromqlAttributesTranslationContext.InheritedAttributes.including(java.util.List<org.elasticsearch.xpack.esql.core.expression.Attribute>)/PromqlAttributesTranslationContext.InheritedAttributes.excluding(java.util.List<org.elasticsearch.xpack.esql.core.expression.Attribute>)); the leaf selector turns it into the shape it exposes (PromqlAttributesTranslationContext.InheritedAttributes.reflect()).PromqlAttributesTranslationContext.SynthesizedAttributes- the synthesized attribute, folded up the chain. It answers "what does the subtree expose?". Each aggregate folds its grouping over its child's shape (PromqlAttributesTranslationContext.SynthesizedAttributes.foldIncluding(java.util.List<org.elasticsearch.xpack.esql.core.expression.Attribute>, org.elasticsearch.xpack.esql.optimizer.rules.logical.promql.PromqlAttributesTranslationContext.SynthesizedAttributes)/PromqlAttributesTranslationContext.SynthesizedAttributes.foldExcluding(java.util.List<org.elasticsearch.xpack.esql.core.expression.Attribute>, org.elasticsearch.xpack.esql.optimizer.rules.logical.promql.PromqlAttributesTranslationContext.SynthesizedAttributes)).
The translation: from attribute to target representation
APromqlAttributesTranslationContext.SynthesizedAttributes is symbolic; it cannot be handed to a plan node directly. PromqlAttributesTranslationContext.SynthesizedAttributes.translate(java.util.List<org.elasticsearch.xpack.esql.core.expression.Attribute>)/
PromqlAttributesTranslationContext.SynthesizedAttributes.translateLeaf(java.util.List<org.elasticsearch.xpack.esql.core.expression.Attribute>) are the code-generation semantic action that concretizes it against the
target schema - collapsing the T/symbolic sets, binding labels by name to the real Attribute
instances, and reporting unresolved BY labels for null-filling. Their output, PromqlAttributesTranslationContext.ResolvedAttributes,
is the target representation the plan builder consumes; unlike the attributes, it does not propagate up the
tree.
Exclusions: inherited vs synthesized
WITHOUT dimensions are tracked twice, on purpose, because two distinct consumers need two distinct facts:
PromqlAttributesTranslationContext.InheritedAttributes.accumulatedExclusionsaccumulates every dimension dropped on the way down. The innermost aggregate (which owns the physical_timeseriesgrouping) needs this full set to build itsTimeSeriesWithout; the translator hands it toPromqlAttributesTranslationContext.SynthesizedAttributes.translateLeaf(java.util.List<org.elasticsearch.xpack.esql.core.expression.Attribute>)viaPromqlAttributesTranslationContext.InheritedAttributes.pathExclusions().PromqlAttributesTranslationContext.SynthesizedAttributes.hasExclusions()reports whether this subtree contains aWITHOUT. An outer aggregate reads only that boolean to decide whether the child's_timeserieshides dimensions that must be packed and unpacked around grouping.
Worked examples
Each aggregate's synthesized[grouping, output, subtreeWithouts] is shown on its closing line; the leaf's
translateLeaf additionally receives the demand's accumulated exclusions.
sum without(pod) (
avg without(region) (
cpu_util
) [G=T\{region}, O={}, X={region}] // translateLeaf path-exclusions = {pod,region}
) [G=T\{region,pod}, O={}, X={region,pod}]
sum by(cluster,region) (
avg without(region) (
cpu_util
) [G=T\{region}, O={}, X={region}] // translateLeaf path-exclusions = {region}
) [G={cluster}, O={cluster,region}, X={}] // region is null-filled
sum without(pod) (
avg by(cluster,pod) (
cpu_util
) [G={cluster,pod}, O={cluster,pod}, X={}] // translateLeaf path-exclusions = {pod}
) [G={cluster}, O={}, X={pod}]
The descent starts from PromqlAttributesTranslationContext.InheritedAttributes.unconstrained() above the outermost aggregate: every label is in scope
(T) and nothing is excluded. Both attribute types are immutable; every transition returns a new value.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final classThe inherited attribute: the scope a subtree must preserve, threaded down the aggregate chain.static final recordThe target representation produced byPromqlAttributesTranslationContext.SynthesizedAttributes.translateLeaf(java.util.List<org.elasticsearch.xpack.esql.core.expression.Attribute>)/PromqlAttributesTranslationContext.SynthesizedAttributes.translate(java.util.List<org.elasticsearch.xpack.esql.core.expression.Attribute>).static final classThe synthesized attribute: the labels a subtree exposes, folded up the aggregate chain. -
Method Summary