3838import org .elasticsearch .xpack .esql .plan .logical .Eval ;
3939import org .elasticsearch .xpack .esql .plan .logical .Filter ;
4040import org .elasticsearch .xpack .esql .plan .logical .LogicalPlan ;
41+ import org .elasticsearch .xpack .esql .plan .logical .Project ;
4142import org .elasticsearch .xpack .esql .plan .logical .TimeSeriesAggregate ;
4243import org .elasticsearch .xpack .esql .plan .logical .promql .AcrossSeriesAggregate ;
4344import org .elasticsearch .xpack .esql .plan .logical .promql .PlaceholderRelation ;
@@ -185,7 +186,26 @@ private static MapResult mapFunction(PromqlCommand promqlCommand, PromqlFunction
185186
186187 LogicalPlan p = childResult .plan ;
187188 p = new Eval (stepBucket .source (), p , List .of (stepBucket ));
188- p = new TimeSeriesAggregate (acrossAggregate .source (), p , groupings , aggs , null );
189+ TimeSeriesAggregate tsAggregate = new TimeSeriesAggregate (acrossAggregate .source (), p , groupings , aggs , null );
190+ p = tsAggregate ;
191+ // ToDouble conversion of the metric using an eval to ensure a consistent output type
192+ Alias convertedValue = new Alias (
193+ acrossAggregate .source (),
194+ acrossAggregate .sourceText (),
195+ new ToDouble (acrossAggregate .source (), p .output ().getFirst ().toAttribute ()),
196+ acrossAggregate .valueId ()
197+ );
198+ p = new Eval (acrossAggregate .source (), p , List .of (convertedValue ));
199+ // Project to maintain the correct output order, as declared in AcrossSeriesAggregate#output:
200+ // [value, step, ...groupings]
201+ List <NamedExpression > projections = new ArrayList <>();
202+ projections .add (convertedValue .toAttribute ());
203+ List <Attribute > output = tsAggregate .output ();
204+ for (int i = 1 ; i < output .size (); i ++) {
205+ projections .add (output .get (i ));
206+ }
207+ p = new Project (acrossAggregate .source (), p , projections );
208+
189209 result = new MapResult (p , extras );
190210 } else {
191211 throw new QlIllegalArgumentException ("Unsupported PromQL function call: {}" , functionCall );
@@ -205,13 +225,11 @@ private static void initAggregatesAndGroupings(
205225 Function esqlFunction = PromqlFunctionRegistry .INSTANCE .buildEsqlFunction (
206226 acrossAggregate .functionName (),
207227 acrossAggregate .source (),
208- // to double conversion of the metric to ensure a consistent output type
209- // TODO it's probably more efficient to wrap the function in the ToDouble
210- // but for some reason this doesn't work if you have an inner and outer aggregation
211- List .of (new ToDouble (target .source (), target ))
228+ List .of (target )
212229 );
213230
214- aggs .add (new Alias (acrossAggregate .source (), acrossAggregate .sourceText (), esqlFunction , acrossAggregate .valueId ()));
231+ Alias value = new Alias (acrossAggregate .source (), acrossAggregate .sourceText (), esqlFunction );
232+ aggs .add (value );
215233
216234 // timestamp/step
217235 aggs .add (stepBucket );
0 commit comments