88package org .elasticsearch .xpack .esql .expression .promql .predicate .operator ;
99
1010import org .elasticsearch .common .io .stream .StreamOutput ;
11- import org .elasticsearch .xpack .esql .EsqlIllegalArgumentException ;
11+ import org .elasticsearch .xpack .esql .core . expression . Attribute ;
1212import org .elasticsearch .xpack .esql .core .expression .Expression ;
13- import org .elasticsearch .xpack .esql .core .expression .FoldContext ;
14- import org .elasticsearch .xpack .esql .core .expression .Nullability ;
13+ import org .elasticsearch .xpack .esql .core .expression .ReferenceAttribute ;
1514import org .elasticsearch .xpack .esql .core .expression .function .Function ;
1615import org .elasticsearch .xpack .esql .core .tree .Source ;
1716import org .elasticsearch .xpack .esql .core .type .DataType ;
18- import org .elasticsearch .xpack .esql .expression .promql .types .PromqlDataTypes ;
17+ import org .elasticsearch .xpack .esql .evaluator .mapper .EvaluatorMapper ;
18+ import org .elasticsearch .xpack .esql .expression .function .scalar .EsqlScalarFunction ;
19+ import org .elasticsearch .xpack .esql .plan .logical .BinaryPlan ;
20+ import org .elasticsearch .xpack .esql .plan .logical .LogicalPlan ;
21+ import org .elasticsearch .xpack .esql .plan .logical .promql .selector .LabelMatcher ;
1922
2023import java .io .IOException ;
24+ import java .util .ArrayList ;
25+ import java .util .HashSet ;
2126import java .util .List ;
2227import java .util .Objects ;
28+ import java .util .Set ;
2329
24- import static java . util . Arrays . asList ;
30+ public abstract class VectorBinaryOperator extends BinaryPlan {
2531
26- public abstract class VectorBinaryOperator extends Expression {
27-
28- private final Expression left , right ;
2932 private final VectorMatch match ;
3033 private final boolean dropMetricName ;
31-
32- private DataType dataType ;
33-
34- private BinaryOp binaryOp ;
34+ private final BinaryOp binaryOp ;
35+ private List <Attribute > output ;
3536
3637 /**
3738 * Underlying binary operation (e.g. +, -, *, /, etc.) being performed
@@ -49,28 +50,18 @@ public interface ScalarFunctionFactory {
4950
5051 protected VectorBinaryOperator (
5152 Source source ,
52- Expression left ,
53- Expression right ,
53+ LogicalPlan left ,
54+ LogicalPlan right ,
5455 VectorMatch match ,
5556 boolean dropMetricName ,
5657 BinaryOp binaryOp
5758 ) {
58- super (source , asList (left , right ));
59- this .left = left ;
60- this .right = right ;
59+ super (source , left , right );
6160 this .match = match ;
6261 this .dropMetricName = dropMetricName ;
6362 this .binaryOp = binaryOp ;
6463 }
6564
66- public Expression left () {
67- return left ;
68- }
69-
70- public Expression right () {
71- return right ;
72- }
73-
7465 public VectorMatch match () {
7566 return match ;
7667 }
@@ -84,55 +75,113 @@ public BinaryOp binaryOp() {
8475 }
8576
8677 @ Override
87- public DataType dataType () {
88- if (dataType == null ) {
89- dataType = PromqlDataTypes .operationType (left .dataType (), right .dataType ());
78+ public List <Attribute > output () {
79+ if (output == null ) {
80+ output = computeOutputAttributes ();
81+ }
82+ return output ;
83+ }
84+
85+ private List <Attribute > computeOutputAttributes () {
86+ // TODO: this isn't tested and should be revised
87+ List <Attribute > leftAttrs = left ().output ();
88+ List <Attribute > rightAttrs = right ().output ();
89+
90+ Set <String > leftLabels = extractLabelNames (leftAttrs );
91+ Set <String > rightLabels = extractLabelNames (rightAttrs );
92+
93+ Set <String > outputLabels ;
94+
95+ if (match != null ) {
96+ if (match .filter () == VectorMatch .Filter .ON ) {
97+ outputLabels = new HashSet <>(match .filterLabels ());
98+ } else if (match .filter () == VectorMatch .Filter .IGNORING ) {
99+ outputLabels = new HashSet <>(leftLabels );
100+ outputLabels .addAll (rightLabels );
101+ outputLabels .removeAll (match .filterLabels ());
102+ } else {
103+ outputLabels = new HashSet <>(leftLabels );
104+ outputLabels .retainAll (rightLabels );
105+ }
106+ } else {
107+ outputLabels = new HashSet <>(leftLabels );
108+ outputLabels .retainAll (rightLabels );
90109 }
91- return dataType ;
92- }
93110
94- @ Override
95- public VectorBinaryOperator replaceChildren (List <Expression > newChildren ) {
96- return replaceChildren (left , right );
111+ if (dropMetricName ) {
112+ outputLabels .remove (LabelMatcher .NAME );
113+ }
114+
115+ List <Attribute > result = new ArrayList <>();
116+ for (String label : outputLabels ) {
117+ Attribute attr = findAttribute (label , leftAttrs , rightAttrs );
118+ if (attr != null ) {
119+ result .add (attr );
120+ }
121+ }
122+
123+ result .add (new ReferenceAttribute (source (), "value" , DataType .DOUBLE ));
124+ return result ;
97125 }
98126
99- protected abstract VectorBinaryOperator replaceChildren (Expression left , Expression right );
127+ private Set <String > extractLabelNames (List <Attribute > attrs ) {
128+ Set <String > labels = new HashSet <>();
129+ for (Attribute attr : attrs ) {
130+ String name = attr .name ();
131+ if (name .equals ("value" ) == false ) {
132+ labels .add (name );
133+ }
134+ }
135+ return labels ;
136+ }
100137
101- @ Override
102- public boolean foldable () {
103- return left .foldable () && right .foldable ();
138+ private Attribute findAttribute (String name , List <Attribute > left , List <Attribute > right ) {
139+ for (Attribute attr : left ) {
140+ if (attr .name ().equals (name )) {
141+ return attr ;
142+ }
143+ }
144+ for (Attribute attr : right ) {
145+ if (attr .name ().equals (name )) {
146+ return attr ;
147+ }
148+ }
149+ return null ;
104150 }
105151
106152 @ Override
107- public Object fold (FoldContext ctx ) {
108- return binaryOp .asFunction ().create (source (), left (), right ()).fold (ctx );
109- }
153+ public abstract VectorBinaryOperator replaceChildren (LogicalPlan newLeft , LogicalPlan newRight );
110154
111155 @ Override
112- public Nullability nullable () {
113- return Nullability . TRUE ;
156+ public boolean expressionsResolved () {
157+ return true ;
114158 }
115159
116160 @ Override
117161 public boolean equals (Object o ) {
162+ if (this == o ) return true ;
163+ if (o == null || getClass () != o .getClass ()) return false ;
118164 if (super .equals (o )) {
119165 VectorBinaryOperator that = (VectorBinaryOperator ) o ;
120- return dropMetricName == that .dropMetricName && Objects .equals (match , that .match ) && Objects .equals (binaryOp , that .binaryOp );
166+ return dropMetricName == that .dropMetricName
167+ && Objects .equals (match , that .match )
168+ && Objects .equals (binaryOp , that .binaryOp );
121169 }
122170 return false ;
123171 }
124172
125173 @ Override
126174 public int hashCode () {
127- return Objects .hash (left , right , match , dropMetricName , binaryOp );
175+ return Objects .hash (super . hashCode () , match , dropMetricName , binaryOp );
128176 }
129177
178+ @ Override
130179 public String getWriteableName () {
131- throw new EsqlIllegalArgumentException ( " should not be serialized" );
180+ throw new UnsupportedOperationException ( "PromQL plans should not be serialized" );
132181 }
133182
134183 @ Override
135184 public void writeTo (StreamOutput out ) throws IOException {
136- throw new EsqlIllegalArgumentException ( " should not be serialized" );
185+ throw new UnsupportedOperationException ( "PromQL plans should not be serialized" );
137186 }
138187}
0 commit comments