This is an automated email from the ASF dual-hosted git repository.

gian pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git


The following commit(s) were added to refs/heads/master by this push:
     new 3fe79b56b84 Give control of fallback vectorization to each function. 
(#18522)
3fe79b56b84 is described below

commit 3fe79b56b84cb6464bd03245d1faadf6fec63235
Author: Gian Merlino <[email protected]>
AuthorDate: Mon Sep 15 16:26:54 2025 -0700

    Give control of fallback vectorization to each function. (#18522)
    
    * Give control of fallback vectorization to each function.
    
    If a function overrides canVectorize, let it decide when it does and
    doesn't vectorize, rather than always attempting to fall back. In situations
    like conditionals (#18507, #18512), we are currently refraining from
    vectorizing when output types are not all aligned.
    
    * Additional coverage.
---
 .../org/apache/druid/math/expr/ApplyFunction.java  | 14 +++++++-----
 .../main/java/org/apache/druid/math/expr/Expr.java |  7 ------
 .../org/apache/druid/math/expr/ExprMacroTable.java |  8 +++++--
 .../java/org/apache/druid/math/expr/Function.java  | 14 +++++++-----
 .../org/apache/druid/math/expr/FunctionalExpr.java | 25 ++++------------------
 .../math/expr/vector/FallbackVectorProcessor.java  | 16 ++++++++++++++
 .../math/expr/VectorExprResultConsistencyTest.java | 25 ++++++++++++++++++++++
 7 files changed, 69 insertions(+), 40 deletions(-)

diff --git 
a/processing/src/main/java/org/apache/druid/math/expr/ApplyFunction.java 
b/processing/src/main/java/org/apache/druid/math/expr/ApplyFunction.java
index 8302e1c901b..bd39110c76a 100644
--- a/processing/src/main/java/org/apache/druid/math/expr/ApplyFunction.java
+++ b/processing/src/main/java/org/apache/druid/math/expr/ApplyFunction.java
@@ -23,8 +23,8 @@ import com.google.common.collect.ImmutableSet;
 import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
 import it.unimi.dsi.fastutil.objects.Object2IntMap;
 import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
-import org.apache.druid.java.util.common.UOE;
 import org.apache.druid.math.expr.vector.ExprVectorProcessor;
+import org.apache.druid.math.expr.vector.FallbackVectorProcessor;
 
 import javax.annotation.Nullable;
 import java.util.ArrayList;
@@ -50,9 +50,9 @@ public interface ApplyFunction extends NamedFunction
    * @see Expr#canVectorize(Expr.InputBindingInspector)
    * @see Function#canVectorize(Expr.InputBindingInspector, List)
    */
-  default boolean canVectorize(Expr.InputBindingInspector inspector, Expr 
lambda, List<Expr> args)
+  default boolean canVectorize(Expr.InputBindingInspector inspector, 
LambdaExpr lambda, List<Expr> args)
   {
-    return false;
+    return 
FallbackVectorProcessor.canFallbackVectorize(getOutputType(inspector, lambda, 
args), inspector, args);
   }
 
   /**
@@ -64,11 +64,15 @@ public interface ApplyFunction extends NamedFunction
    */
   default <T> ExprVectorProcessor<T> asVectorProcessor(
       Expr.VectorInputBindingInspector inspector,
-      Expr lambda,
+      LambdaExpr lambda,
       List<Expr> args
   )
   {
-    throw new UOE("%s is not vectorized", name());
+    if (ExpressionProcessing.allowVectorizeFallback()) {
+      return FallbackVectorProcessor.create(this, lambda, args, inspector);
+    } else {
+      throw Exprs.cannotVectorize(name());
+    }
   }
 
   /**
diff --git a/processing/src/main/java/org/apache/druid/math/expr/Expr.java 
b/processing/src/main/java/org/apache/druid/math/expr/Expr.java
index 4347ac7af07..08e05c06579 100644
--- a/processing/src/main/java/org/apache/druid/math/expr/Expr.java
+++ b/processing/src/main/java/org/apache/druid/math/expr/Expr.java
@@ -189,13 +189,6 @@ public interface Expr extends Cacheable
     return false;
   }
 
-
-  default boolean canFallbackVectorize(InputBindingInspector inspector, 
List<Expr> args)
-  {
-    return ExpressionProcessing.allowVectorizeFallback() &&
-           getOutputType(inspector) != null &&
-           inspector.canVectorize(args);
-  }
   /**
    * Possibly convert the {@link Expr} into an optimized, possibly not 
thread-safe {@link Expr}. Does not convert
    * child {@link Expr}. Most callers should use {@link 
Expr#singleThreaded(Expr, InputBindingInspector)} to convert
diff --git 
a/processing/src/main/java/org/apache/druid/math/expr/ExprMacroTable.java 
b/processing/src/main/java/org/apache/druid/math/expr/ExprMacroTable.java
index 40d8ba1112c..5c885892efd 100644
--- a/processing/src/main/java/org/apache/druid/math/expr/ExprMacroTable.java
+++ b/processing/src/main/java/org/apache/druid/math/expr/ExprMacroTable.java
@@ -178,13 +178,17 @@ public class ExprMacroTable
     @Override
     public boolean canVectorize(InputBindingInspector inspector)
     {
-      return canFallbackVectorize(inspector, args);
+      return 
FallbackVectorProcessor.canFallbackVectorize(getOutputType(inspector), 
inspector, args);
     }
 
     @Override
     public <T> ExprVectorProcessor<T> 
asVectorProcessor(VectorInputBindingInspector inspector)
     {
-      return FallbackVectorProcessor.create(macro, args, inspector);
+      if (ExpressionProcessing.allowVectorizeFallback()) {
+        return FallbackVectorProcessor.create(macro, args, inspector);
+      } else {
+        throw Exprs.cannotVectorize(this);
+      }
     }
 
     /**
diff --git a/processing/src/main/java/org/apache/druid/math/expr/Function.java 
b/processing/src/main/java/org/apache/druid/math/expr/Function.java
index 568d44171b5..8f51a50fd90 100644
--- a/processing/src/main/java/org/apache/druid/math/expr/Function.java
+++ b/processing/src/main/java/org/apache/druid/math/expr/Function.java
@@ -29,9 +29,9 @@ import org.apache.druid.error.DruidException;
 import org.apache.druid.java.util.common.DateTimes;
 import org.apache.druid.java.util.common.HumanReadableBytes;
 import org.apache.druid.java.util.common.StringUtils;
-import org.apache.druid.java.util.common.UOE;
 import org.apache.druid.math.expr.vector.CastToTypeVectorProcessor;
 import org.apache.druid.math.expr.vector.ExprVectorProcessor;
+import org.apache.druid.math.expr.vector.FallbackVectorProcessor;
 import org.apache.druid.math.expr.vector.VectorConditionalProcessors;
 import org.apache.druid.math.expr.vector.VectorMathProcessors;
 import org.apache.druid.math.expr.vector.VectorProcessors;
@@ -142,11 +142,11 @@ public interface Function extends NamedFunction
    * batches to use with vectorized query engines.
    *
    * @see Expr#canVectorize(Expr.InputBindingInspector)
-   * @see ApplyFunction#canVectorize(Expr.InputBindingInspector, Expr, List)
+   * @see ApplyFunction#canVectorize(Expr.InputBindingInspector, LambdaExpr, 
List)
    */
   default boolean canVectorize(Expr.InputBindingInspector inspector, 
List<Expr> args)
   {
-    return false;
+    return 
FallbackVectorProcessor.canFallbackVectorize(getOutputType(inspector, args), 
inspector, args);
   }
 
   /**
@@ -154,11 +154,15 @@ public interface Function extends NamedFunction
    * using {@link Expr#asVectorProcessor}, for use in vectorized query engines.
    *
    * @see Expr#asVectorProcessor(Expr.VectorInputBindingInspector)
-   * @see ApplyFunction#asVectorProcessor(Expr.VectorInputBindingInspector, 
Expr, List)
+   * @see ApplyFunction#asVectorProcessor(Expr.VectorInputBindingInspector, 
LambdaExpr, List)
    */
   default <T> ExprVectorProcessor<T> 
asVectorProcessor(Expr.VectorInputBindingInspector inspector, List<Expr> args)
   {
-    throw new UOE("Function[%s] is not vectorized", name());
+    if (ExpressionProcessing.allowVectorizeFallback()) {
+      return FallbackVectorProcessor.create(this, args, inspector);
+    } else {
+      throw Exprs.cannotVectorize(this);
+    }
   }
 
   /**
diff --git 
a/processing/src/main/java/org/apache/druid/math/expr/FunctionalExpr.java 
b/processing/src/main/java/org/apache/druid/math/expr/FunctionalExpr.java
index 02457e992a3..2159cc40008 100644
--- a/processing/src/main/java/org/apache/druid/math/expr/FunctionalExpr.java
+++ b/processing/src/main/java/org/apache/druid/math/expr/FunctionalExpr.java
@@ -23,7 +23,6 @@ import com.google.common.collect.ImmutableList;
 import org.apache.druid.error.DruidException;
 import org.apache.druid.java.util.common.StringUtils;
 import org.apache.druid.math.expr.vector.ExprVectorProcessor;
-import org.apache.druid.math.expr.vector.FallbackVectorProcessor;
 import org.apache.druid.query.filter.ColumnIndexSelector;
 import org.apache.druid.segment.column.ColumnIndexSupplier;
 import org.apache.druid.segment.column.ColumnType;
@@ -104,17 +103,13 @@ class FunctionExpr implements Expr
   @Override
   public boolean canVectorize(InputBindingInspector inspector)
   {
-    return function.canVectorize(inspector, args) || 
canFallbackVectorize(inspector, args);
+    return function.canVectorize(inspector, args);
   }
 
   @Override
   public ExprVectorProcessor<?> asVectorProcessor(VectorInputBindingInspector 
inspector)
   {
-    if (function.canVectorize(inspector, args)) {
-      return function.asVectorProcessor(inspector, args);
-    } else {
-      return FallbackVectorProcessor.create(function, args, inspector);
-    }
+    return function.asVectorProcessor(inspector, args);
   }
 
   @Nullable
@@ -248,25 +243,13 @@ class ApplyFunctionExpr implements Expr
   @Override
   public boolean canVectorize(InputBindingInspector inspector)
   {
-    return canVectorizeNative(inspector) ||
-           (canFallbackVectorize(inspector, argsExpr) && 
lambdaExpr.canVectorize(inspector));
+    return function.canVectorize(inspector, lambdaExpr, argsExpr);
   }
 
   @Override
   public <T> ExprVectorProcessor<T> 
asVectorProcessor(VectorInputBindingInspector inspector)
   {
-    if (canVectorizeNative(inspector)) {
-      return function.asVectorProcessor(inspector, lambdaExpr, argsExpr);
-    } else {
-      return FallbackVectorProcessor.create(function, lambdaExpr, argsExpr, 
inspector);
-    }
-  }
-
-  private boolean canVectorizeNative(InputBindingInspector inspector)
-  {
-    return function.canVectorize(inspector, lambdaExpr, argsExpr) &&
-           lambdaExpr.canVectorize(inspector) &&
-           argsExpr.stream().allMatch(expr -> expr.canVectorize(inspector));
+    return function.asVectorProcessor(inspector, lambdaExpr, argsExpr);
   }
 
   @Override
diff --git 
a/processing/src/main/java/org/apache/druid/math/expr/vector/FallbackVectorProcessor.java
 
b/processing/src/main/java/org/apache/druid/math/expr/vector/FallbackVectorProcessor.java
index 115c9eed397..e8cf412463d 100644
--- 
a/processing/src/main/java/org/apache/druid/math/expr/vector/FallbackVectorProcessor.java
+++ 
b/processing/src/main/java/org/apache/druid/math/expr/vector/FallbackVectorProcessor.java
@@ -25,6 +25,7 @@ import org.apache.druid.math.expr.Expr;
 import org.apache.druid.math.expr.ExprEval;
 import org.apache.druid.math.expr.ExprMacroTable;
 import org.apache.druid.math.expr.ExprType;
+import org.apache.druid.math.expr.ExpressionProcessing;
 import org.apache.druid.math.expr.ExpressionType;
 import org.apache.druid.math.expr.Function;
 import org.apache.druid.math.expr.LambdaExpr;
@@ -113,6 +114,21 @@ public abstract class FallbackVectorProcessor<T> 
implements ExprVectorProcessor<
     );
   }
 
+  /**
+   * Returns whether {@link #create(Function, List, 
Expr.VectorInputBindingInspector)} can be used to make
+   * a fallback vectorized processor.
+   */
+  public static boolean canFallbackVectorize(
+      @Nullable final ExpressionType outputType,
+      final Expr.InputBindingInspector inspector,
+      final List<Expr> args
+  )
+  {
+    return ExpressionProcessing.allowVectorizeFallback() &&
+           outputType != null &&
+           inspector.canVectorize(args);
+  }
+
   /**
    * Helper for the two {@link #create} methods. Makes {@link AdaptedExpr} 
that can replace the original args to
    * the {@link Expr} that requires fallback.
diff --git 
a/processing/src/test/java/org/apache/druid/math/expr/VectorExprResultConsistencyTest.java
 
b/processing/src/test/java/org/apache/druid/math/expr/VectorExprResultConsistencyTest.java
index aa878cb47cf..c54f01472bc 100644
--- 
a/processing/src/test/java/org/apache/druid/math/expr/VectorExprResultConsistencyTest.java
+++ 
b/processing/src/test/java/org/apache/druid/math/expr/VectorExprResultConsistencyTest.java
@@ -441,6 +441,31 @@ public class VectorExprResultConsistencyTest extends 
InitializedNullHandlingTest
       testExpression("array(d1, d2)", types);
       testExpression("array(l1, d2)", types);
       testExpression("array(s1, l2)", types);
+
+      testExpression("map((x) -> x + 1, array(l1, l2))", types);
+      testExpression("map((x) -> x * 2.0, array(d1, d2))", types);
+      testExpression("map((x) -> concat(x, '_mapped'), array(s1, s2))", types);
+
+      testExpression("cartesian_map((x, y) -> x + y, array(l1, l2), array(d1, 
d2))", types);
+      testExpression("cartesian_map((x, y) -> concat(x, cast(y, 'STRING')), 
array(s1, s2), array(l1, l2))", types);
+
+      testExpression("fold((x, acc) -> x + acc, array(l1, l2), 0)", types);
+      testExpression("fold((x, acc) -> x + acc, array(d1, d2), 0.0)", types);
+      testExpression("fold((x, acc) -> concat(acc, x), array(s1, s2), '')", 
types);
+
+      testExpression("cartesian_fold((x, y, acc) -> acc + x + y, array(l1, 
l2), array(d1, d2), 0)", types);
+
+      testExpression("filter((x) -> x > 0, array(l1, l2))", types);
+      testExpression("filter((x) -> x > 0.0, array(d1, d2))", types);
+      testExpression("filter((x) -> strlen(x) > 0, array(s1, s2))", types);
+
+      testExpression("any((x) -> x > 0, array(l1, l2))", types);
+      testExpression("any((x) -> x > 0.0, array(d1, d2))", types);
+      testExpression("any((x) -> strlen(x) > 0, array(s1, s2))", types);
+
+      testExpression("all((x) -> x != null, array(l1, l2))", types);
+      testExpression("all((x) -> x != null, array(d1, d2))", types);
+      testExpression("all((x) -> x != null, array(s1, s2))", types);
     }
     finally {
       ExpressionProcessing.initializeForTests();


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to