فهرست منبع

ESQL: Move some mappers into their expressions (#128342)

This moves half of the remaining centralized expression mapper logic
into the individual expressions. This is how all but 3 of the remaining
expressions work. Let's try and be fully consistent.
Nik Everett 4 ماه پیش
والد
کامیت
33fc85fdff

+ 1 - 1
x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/evaluator/predicate/operator/logical/NotEvaluator.java → x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/predicate/logical/NotEvaluator.java

@@ -2,7 +2,7 @@
 // or more contributor license agreements. Licensed under the Elastic License
 // 2.0; you may not use this file except in compliance with the Elastic License
 // 2.0.
-package org.elasticsearch.xpack.esql.evaluator.predicate.operator.logical;
+package org.elasticsearch.xpack.esql.expression.predicate.logical;
 
 import java.lang.IllegalArgumentException;
 import java.lang.Override;

+ 1 - 117
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/evaluator/EvalMapper.java

@@ -17,7 +17,6 @@ import org.elasticsearch.compute.data.ElementType;
 import org.elasticsearch.compute.data.Page;
 import org.elasticsearch.compute.data.Vector;
 import org.elasticsearch.compute.operator.DriverContext;
-import org.elasticsearch.compute.operator.EvalOperator;
 import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator;
 import org.elasticsearch.core.Releasables;
 import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException;
@@ -28,9 +27,6 @@ import org.elasticsearch.xpack.esql.core.expression.Literal;
 import org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper;
 import org.elasticsearch.xpack.esql.evaluator.mapper.ExpressionMapper;
 import org.elasticsearch.xpack.esql.expression.predicate.logical.BinaryLogic;
-import org.elasticsearch.xpack.esql.expression.predicate.logical.Not;
-import org.elasticsearch.xpack.esql.expression.predicate.nulls.IsNotNull;
-import org.elasticsearch.xpack.esql.expression.predicate.nulls.IsNull;
 import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.InsensitiveEqualsMapper;
 import org.elasticsearch.xpack.esql.planner.EsPhysicalOperationProviders.ShardContext;
 import org.elasticsearch.xpack.esql.planner.Layout;
@@ -42,11 +38,8 @@ public final class EvalMapper {
     private static final List<ExpressionMapper<?>> MAPPERS = List.of(
         new InsensitiveEqualsMapper(),
         new BooleanLogic(),
-        new Nots(),
         new Attributes(),
-        new Literals(),
-        new IsNotNulls(),
-        new IsNulls()
+        new Literals()
     );
 
     private EvalMapper() {}
@@ -174,18 +167,6 @@ public final class EvalMapper {
         }
     }
 
-    static class Nots extends ExpressionMapper<Not> {
-        @Override
-        public ExpressionEvaluator.Factory map(FoldContext foldCtx, Not not, Layout layout, List<ShardContext> shardContexts) {
-            var expEval = toEvaluator(foldCtx, not.field(), layout, shardContexts);
-            return dvrCtx -> new org.elasticsearch.xpack.esql.evaluator.predicate.operator.logical.NotEvaluator(
-                not.source(),
-                expEval.get(dvrCtx),
-                dvrCtx
-            );
-        }
-    }
-
     static class Attributes extends ExpressionMapper<Attribute> {
         @Override
         public ExpressionEvaluator.Factory map(FoldContext foldCtx, Attribute attr, Layout layout, List<ShardContext> shardContexts) {
@@ -276,101 +257,4 @@ public final class EvalMapper {
             return BlockUtils.constantBlock(blockFactory, value, positions);
         }
     }
-
-    static class IsNulls extends ExpressionMapper<IsNull> {
-
-        @Override
-        public ExpressionEvaluator.Factory map(FoldContext foldCtx, IsNull isNull, Layout layout, List<ShardContext> shardContexts) {
-            var field = toEvaluator(foldCtx, isNull.field(), layout, shardContexts);
-            return new IsNullEvaluatorFactory(field);
-        }
-
-        record IsNullEvaluatorFactory(EvalOperator.ExpressionEvaluator.Factory field) implements ExpressionEvaluator.Factory {
-            @Override
-            public ExpressionEvaluator get(DriverContext context) {
-                return new IsNullEvaluator(context, field.get(context));
-            }
-
-            @Override
-            public String toString() {
-                return "IsNullEvaluator[field=" + field + ']';
-            }
-        }
-
-        record IsNullEvaluator(DriverContext driverContext, EvalOperator.ExpressionEvaluator field) implements ExpressionEvaluator {
-            @Override
-            public Block eval(Page page) {
-                try (Block fieldBlock = field.eval(page)) {
-                    if (fieldBlock.asVector() != null) {
-                        return driverContext.blockFactory().newConstantBooleanBlockWith(false, page.getPositionCount());
-                    }
-                    try (var builder = driverContext.blockFactory().newBooleanVectorFixedBuilder(page.getPositionCount())) {
-                        for (int p = 0; p < page.getPositionCount(); p++) {
-                            builder.appendBoolean(p, fieldBlock.isNull(p));
-                        }
-                        return builder.build().asBlock();
-                    }
-                }
-            }
-
-            @Override
-            public void close() {
-                Releasables.closeExpectNoException(field);
-            }
-
-            @Override
-            public String toString() {
-                return "IsNullEvaluator[field=" + field + ']';
-            }
-        }
-    }
-
-    static class IsNotNulls extends ExpressionMapper<IsNotNull> {
-
-        @Override
-        public ExpressionEvaluator.Factory map(FoldContext foldCtx, IsNotNull isNotNull, Layout layout, List<ShardContext> shardContexts) {
-            return new IsNotNullEvaluatorFactory(toEvaluator(foldCtx, isNotNull.field(), layout, shardContexts));
-        }
-
-        record IsNotNullEvaluatorFactory(EvalOperator.ExpressionEvaluator.Factory field) implements ExpressionEvaluator.Factory {
-            @Override
-            public ExpressionEvaluator get(DriverContext context) {
-                return new IsNotNullEvaluator(context, field.get(context));
-            }
-
-            @Override
-            public String toString() {
-                return "IsNotNullEvaluator[field=" + field + ']';
-            }
-        }
-
-        record IsNotNullEvaluator(DriverContext driverContext, EvalOperator.ExpressionEvaluator field)
-            implements
-                EvalOperator.ExpressionEvaluator {
-            @Override
-            public Block eval(Page page) {
-                try (Block fieldBlock = field.eval(page)) {
-                    if (fieldBlock.asVector() != null) {
-                        return driverContext.blockFactory().newConstantBooleanBlockWith(true, page.getPositionCount());
-                    }
-                    try (var builder = driverContext.blockFactory().newBooleanVectorFixedBuilder(page.getPositionCount())) {
-                        for (int p = 0; p < page.getPositionCount(); p++) {
-                            builder.appendBoolean(p, fieldBlock.isNull(p) == false);
-                        }
-                        return builder.build().asBlock();
-                    }
-                }
-            }
-
-            @Override
-            public void close() {
-                Releasables.closeExpectNoException(field);
-            }
-
-            @Override
-            public String toString() {
-                return "IsNotNullEvaluator[field=" + field + ']';
-            }
-        }
-    }
 }

+ 0 - 17
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/evaluator/predicate/operator/logical/Not.java

@@ -1,17 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License
- * 2.0; you may not use this file except in compliance with the Elastic License
- * 2.0.
- */
-
-package org.elasticsearch.xpack.esql.evaluator.predicate.operator.logical;
-
-import org.elasticsearch.compute.ann.Evaluator;
-
-public class Not {
-    @Evaluator
-    static boolean process(boolean v) {
-        return false == v;
-    }
-}

+ 29 - 1
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/logical/Not.java

@@ -8,6 +8,9 @@ package org.elasticsearch.xpack.esql.expression.predicate.logical;
 
 import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
 import org.elasticsearch.common.io.stream.StreamInput;
+import org.elasticsearch.compute.ann.Evaluator;
+import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.compute.operator.EvalOperator;
 import org.elasticsearch.xpack.esql.capabilities.TranslationAware;
 import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException;
 import org.elasticsearch.xpack.esql.core.expression.Expression;
@@ -18,6 +21,7 @@ import org.elasticsearch.xpack.esql.core.querydsl.query.Query;
 import org.elasticsearch.xpack.esql.core.tree.NodeInfo;
 import org.elasticsearch.xpack.esql.core.tree.Source;
 import org.elasticsearch.xpack.esql.core.type.DataType;
+import org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper;
 import org.elasticsearch.xpack.esql.optimizer.rules.physical.local.LucenePushdownPredicates;
 import org.elasticsearch.xpack.esql.planner.TranslatorHandler;
 
@@ -26,7 +30,7 @@ import java.io.IOException;
 import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT;
 import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isBoolean;
 
-public class Not extends UnaryScalarFunction implements Negatable<Expression>, TranslationAware {
+public class Not extends UnaryScalarFunction implements EvaluatorMapper, Negatable<Expression>, TranslationAware {
     public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(Expression.class, "Not", Not::new);
 
     public Not(Source source, Expression child) {
@@ -77,6 +81,16 @@ public class Not extends UnaryScalarFunction implements Negatable<Expression>, T
         return ((Boolean) input).booleanValue() ? Boolean.FALSE : Boolean.TRUE;
     }
 
+    @Override
+    public EvalOperator.ExpressionEvaluator.Factory toEvaluator(ToEvaluator toEvaluator) {
+        return new NotEvaluatorFactory(source(), toEvaluator.apply(field()));
+    }
+
+    @Evaluator
+    static boolean process(boolean v) {
+        return false == v;
+    }
+
     @Override
     protected Expression canonicalize() {
         if (field() instanceof Negatable) {
@@ -108,4 +122,18 @@ public class Not extends UnaryScalarFunction implements Negatable<Expression>, T
     public Query asQuery(LucenePushdownPredicates pushdownPredicates, TranslatorHandler handler) {
         return handler.asQuery(pushdownPredicates, field()).negate(source());
     }
+
+    record NotEvaluatorFactory(Source source, EvalOperator.ExpressionEvaluator.Factory field)
+        implements
+            EvalOperator.ExpressionEvaluator.Factory {
+        @Override
+        public EvalOperator.ExpressionEvaluator get(DriverContext context) {
+            return new NotEvaluator(source, field.get(context), context);
+        }
+
+        @Override
+        public String toString() {
+            return "NotEvaluator[field=" + field + ']';
+        }
+    }
 }

+ 54 - 1
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/nulls/IsNotNull.java

@@ -8,6 +8,11 @@ package org.elasticsearch.xpack.esql.expression.predicate.nulls;
 
 import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
 import org.elasticsearch.common.io.stream.StreamInput;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.compute.operator.EvalOperator;
+import org.elasticsearch.core.Releasables;
 import org.elasticsearch.xpack.esql.capabilities.TranslationAware;
 import org.elasticsearch.xpack.esql.core.expression.Expression;
 import org.elasticsearch.xpack.esql.core.expression.FoldContext;
@@ -19,12 +24,13 @@ import org.elasticsearch.xpack.esql.core.querydsl.query.Query;
 import org.elasticsearch.xpack.esql.core.tree.NodeInfo;
 import org.elasticsearch.xpack.esql.core.tree.Source;
 import org.elasticsearch.xpack.esql.core.type.DataType;
+import org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper;
 import org.elasticsearch.xpack.esql.optimizer.rules.physical.local.LucenePushdownPredicates;
 import org.elasticsearch.xpack.esql.planner.TranslatorHandler;
 
 import java.io.IOException;
 
-public class IsNotNull extends UnaryScalarFunction implements Negatable<UnaryScalarFunction>, TranslationAware {
+public class IsNotNull extends UnaryScalarFunction implements EvaluatorMapper, Negatable<UnaryScalarFunction>, TranslationAware {
     public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(
         Expression.class,
         "IsNotNull",
@@ -59,6 +65,12 @@ public class IsNotNull extends UnaryScalarFunction implements Negatable<UnarySca
         return DataType.isNull(field().dataType()) == false && field().fold(ctx) != null;
     }
 
+    @Override
+    public EvalOperator.ExpressionEvaluator.Factory toEvaluator(ToEvaluator toEvaluator) {
+        return new IsNotNullEvaluatorFactory(toEvaluator.apply(field()));
+
+    }
+
     @Override
     public Nullability nullable() {
         return Nullability.FALSE;
@@ -83,4 +95,45 @@ public class IsNotNull extends UnaryScalarFunction implements Negatable<UnarySca
     public Query asQuery(LucenePushdownPredicates pushdownPredicates, TranslatorHandler handler) {
         return new ExistsQuery(source(), handler.nameOf(field()));
     }
+
+    record IsNotNullEvaluatorFactory(EvalOperator.ExpressionEvaluator.Factory field) implements EvalOperator.ExpressionEvaluator.Factory {
+        @Override
+        public EvalOperator.ExpressionEvaluator get(DriverContext context) {
+            return new IsNotNullEvaluator(context, field.get(context));
+        }
+
+        @Override
+        public String toString() {
+            return "IsNotNullEvaluator[field=" + field + ']';
+        }
+    }
+
+    record IsNotNullEvaluator(DriverContext driverContext, EvalOperator.ExpressionEvaluator field)
+        implements
+            EvalOperator.ExpressionEvaluator {
+        @Override
+        public Block eval(Page page) {
+            try (Block fieldBlock = field.eval(page)) {
+                if (fieldBlock.asVector() != null) {
+                    return driverContext.blockFactory().newConstantBooleanBlockWith(true, page.getPositionCount());
+                }
+                try (var builder = driverContext.blockFactory().newBooleanVectorFixedBuilder(page.getPositionCount())) {
+                    for (int p = 0; p < page.getPositionCount(); p++) {
+                        builder.appendBoolean(p, fieldBlock.isNull(p) == false);
+                    }
+                    return builder.build().asBlock();
+                }
+            }
+        }
+
+        @Override
+        public void close() {
+            Releasables.closeExpectNoException(field);
+        }
+
+        @Override
+        public String toString() {
+            return "IsNotNullEvaluator[field=" + field + ']';
+        }
+    }
 }

+ 53 - 1
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/predicate/nulls/IsNull.java

@@ -8,6 +8,11 @@ package org.elasticsearch.xpack.esql.expression.predicate.nulls;
 
 import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
 import org.elasticsearch.common.io.stream.StreamInput;
+import org.elasticsearch.compute.data.Block;
+import org.elasticsearch.compute.data.Page;
+import org.elasticsearch.compute.operator.DriverContext;
+import org.elasticsearch.compute.operator.EvalOperator;
+import org.elasticsearch.core.Releasables;
 import org.elasticsearch.xpack.esql.capabilities.TranslationAware;
 import org.elasticsearch.xpack.esql.core.expression.Expression;
 import org.elasticsearch.xpack.esql.core.expression.FoldContext;
@@ -20,12 +25,13 @@ import org.elasticsearch.xpack.esql.core.querydsl.query.Query;
 import org.elasticsearch.xpack.esql.core.tree.NodeInfo;
 import org.elasticsearch.xpack.esql.core.tree.Source;
 import org.elasticsearch.xpack.esql.core.type.DataType;
+import org.elasticsearch.xpack.esql.evaluator.mapper.EvaluatorMapper;
 import org.elasticsearch.xpack.esql.optimizer.rules.physical.local.LucenePushdownPredicates;
 import org.elasticsearch.xpack.esql.planner.TranslatorHandler;
 
 import java.io.IOException;
 
-public class IsNull extends UnaryScalarFunction implements Negatable<UnaryScalarFunction>, TranslationAware {
+public class IsNull extends UnaryScalarFunction implements EvaluatorMapper, Negatable<UnaryScalarFunction>, TranslationAware {
     public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(Expression.class, "IsNull", IsNull::new);
 
     public IsNull(Source source, Expression field) {
@@ -56,6 +62,11 @@ public class IsNull extends UnaryScalarFunction implements Negatable<UnaryScalar
         return DataType.isNull(field().dataType()) || field().fold(ctx) == null;
     }
 
+    @Override
+    public EvalOperator.ExpressionEvaluator.Factory toEvaluator(ToEvaluator toEvaluator) {
+        return new IsNullEvaluatorFactory(toEvaluator.apply(field()));
+    }
+
     @Override
     public Nullability nullable() {
         return Nullability.FALSE;
@@ -86,4 +97,45 @@ public class IsNull extends UnaryScalarFunction implements Negatable<UnaryScalar
     public Query asQuery(LucenePushdownPredicates pushdownPredicates, TranslatorHandler handler) {
         return new NotQuery(source(), new ExistsQuery(source(), handler.nameOf(field())));
     }
+
+    record IsNullEvaluatorFactory(EvalOperator.ExpressionEvaluator.Factory field) implements EvalOperator.ExpressionEvaluator.Factory {
+        @Override
+        public EvalOperator.ExpressionEvaluator get(DriverContext context) {
+            return new IsNullEvaluator(context, field.get(context));
+        }
+
+        @Override
+        public String toString() {
+            return "IsNullEvaluator[field=" + field + ']';
+        }
+    }
+
+    record IsNullEvaluator(DriverContext driverContext, EvalOperator.ExpressionEvaluator field)
+        implements
+            EvalOperator.ExpressionEvaluator {
+        @Override
+        public Block eval(Page page) {
+            try (Block fieldBlock = field.eval(page)) {
+                if (fieldBlock.asVector() != null) {
+                    return driverContext.blockFactory().newConstantBooleanBlockWith(false, page.getPositionCount());
+                }
+                try (var builder = driverContext.blockFactory().newBooleanVectorFixedBuilder(page.getPositionCount())) {
+                    for (int p = 0; p < page.getPositionCount(); p++) {
+                        builder.appendBoolean(p, fieldBlock.isNull(p));
+                    }
+                    return builder.build().asBlock();
+                }
+            }
+        }
+
+        @Override
+        public void close() {
+            Releasables.closeExpectNoException(field);
+        }
+
+        @Override
+        public String toString() {
+            return "IsNullEvaluator[field=" + field + ']';
+        }
+    }
 }