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 09fd96ec24f Expr: Collect BindingAnalysis in bulk rather than one at a 
time. (#17613)
09fd96ec24f is described below

commit 09fd96ec24f9cb9e2d37a794ec5b2725db7c75fb
Author: Gian Merlino <[email protected]>
AuthorDate: Thu Jan 30 08:56:46 2025 -0800

    Expr: Collect BindingAnalysis in bulk rather than one at a time. (#17613)
    
    Speeds up analysis of functions with large numbers of arguments, such
    as CASE statements with many branches. The prior code would call "with"
    for each argument on the accumulated analysis so far, which needlessly
    re-created the sets of variables over and over.
---
 .../druid/math/expr/BinaryEvalOpExprBase.java      |  4 +-
 .../main/java/org/apache/druid/math/expr/Expr.java | 68 +++++++++++++++-------
 .../java/org/apache/druid/math/expr/Exprs.java     |  6 +-
 .../org/apache/druid/math/expr/FunctionalExpr.java | 28 ++++-----
 4 files changed, 60 insertions(+), 46 deletions(-)

diff --git 
a/processing/src/main/java/org/apache/druid/math/expr/BinaryEvalOpExprBase.java 
b/processing/src/main/java/org/apache/druid/math/expr/BinaryEvalOpExprBase.java
index ebd90a88bfd..1ec567f97b0 100644
--- 
a/processing/src/main/java/org/apache/druid/math/expr/BinaryEvalOpExprBase.java
+++ 
b/processing/src/main/java/org/apache/druid/math/expr/BinaryEvalOpExprBase.java
@@ -24,6 +24,7 @@ import org.apache.druid.java.util.common.IAE;
 import org.apache.druid.java.util.common.StringUtils;
 
 import javax.annotation.Nullable;
+import java.util.Arrays;
 import java.util.Objects;
 
 /**
@@ -77,7 +78,8 @@ abstract class BinaryOpExprBase implements Expr
   public BindingAnalysis analyzeInputs()
   {
     // currently all binary operators operate on scalar inputs
-    return 
left.analyzeInputs().with(right).withScalarArguments(ImmutableSet.of(left, 
right));
+    return BindingAnalysis.collectExprs(Arrays.asList(left, right))
+                          .withScalarArguments(ImmutableSet.of(left, right));
   }
 
   @Nullable
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 9355447340a..b287d8f1289 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
@@ -39,10 +39,12 @@ import org.apache.druid.segment.virtual.ExpressionSelectors;
 import javax.annotation.Nullable;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * Base interface of Druid expression language abstract syntax tree nodes. All 
{@link Expr} implementations are
@@ -576,6 +578,50 @@ public interface Expr extends Cacheable
       this.isOutputArray = isOutputArray;
     }
 
+    /**
+     * Create an instance by combining a collection of other instances.
+     */
+    public static BindingAnalysis collect(final Collection<BindingAnalysis> 
others)
+    {
+      if (others.isEmpty()) {
+        return EMTPY;
+      } else if (others.size() == 1) {
+        return Iterables.getOnlyElement(others);
+      } else {
+        final ImmutableSet.Builder<IdentifierExpr> freeVariables = 
ImmutableSet.builder();
+        final ImmutableSet.Builder<IdentifierExpr> scalarVariables = 
ImmutableSet.builder();
+        final ImmutableSet.Builder<IdentifierExpr> arrayVariables = 
ImmutableSet.builder();
+
+        boolean hasInputArrays = false;
+        boolean isOutputArray = false;
+
+        for (final BindingAnalysis other : others) {
+          hasInputArrays = hasInputArrays || other.hasInputArrays;
+          isOutputArray = isOutputArray || other.isOutputArray;
+
+          freeVariables.addAll(other.freeVariables);
+          scalarVariables.addAll(other.scalarVariables);
+          arrayVariables.addAll(other.arrayVariables);
+        }
+
+        return new BindingAnalysis(
+            freeVariables.build(),
+            scalarVariables.build(),
+            arrayVariables.build(),
+            hasInputArrays,
+            isOutputArray
+        );
+      }
+    }
+
+    /**
+     * Create an instance by combining a collection of analyses from {@link 
Expr#analyzeInputs()}.
+     */
+    public static BindingAnalysis collectExprs(final Collection<Expr> exprs)
+    {
+      return 
collect(exprs.stream().map(Expr::analyzeInputs).collect(Collectors.toList()));
+    }
+
     /**
      * Get the list of required column inputs to evaluate an expression 
({@link IdentifierExpr#binding})
      */
@@ -658,28 +704,6 @@ public interface Expr extends Cacheable
       return isOutputArray;
     }
 
-    /**
-     * Combine with {@link BindingAnalysis} from {@link Expr#analyzeInputs()}
-     */
-    public BindingAnalysis with(Expr other)
-    {
-      return with(other.analyzeInputs());
-    }
-
-    /**
-     * Combine (union) another {@link BindingAnalysis}
-     */
-    public BindingAnalysis with(BindingAnalysis other)
-    {
-      return new BindingAnalysis(
-          ImmutableSet.copyOf(Sets.union(freeVariables, other.freeVariables)),
-          ImmutableSet.copyOf(Sets.union(scalarVariables, 
other.scalarVariables)),
-          ImmutableSet.copyOf(Sets.union(arrayVariables, 
other.arrayVariables)),
-          hasInputArrays || other.hasInputArrays,
-          isOutputArray || other.isOutputArray
-      );
-    }
-
     /**
      * Add set of arguments as {@link BindingAnalysis#scalarVariables} that 
are *directly* {@link IdentifierExpr},
      * else they are ignored.
diff --git a/processing/src/main/java/org/apache/druid/math/expr/Exprs.java 
b/processing/src/main/java/org/apache/druid/math/expr/Exprs.java
index e3d2844ba03..c012cc83327 100644
--- a/processing/src/main/java/org/apache/druid/math/expr/Exprs.java
+++ b/processing/src/main/java/org/apache/druid/math/expr/Exprs.java
@@ -58,11 +58,7 @@ public class Exprs
    */
   public static Expr.BindingAnalysis analyzeBindings(final List<Expr> args)
   {
-    Expr.BindingAnalysis accumulator = new Expr.BindingAnalysis();
-    for (final Expr arg : args) {
-      accumulator = accumulator.with(arg);
-    }
-    return accumulator;
+    return Expr.BindingAnalysis.collectExprs(args);
   }
 
   /**
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 e95140011a7..5eadbf96ba1 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
@@ -128,15 +128,11 @@ class FunctionExpr implements Expr
   @Override
   public BindingAnalysis analyzeInputs()
   {
-    BindingAnalysis accumulator = new BindingAnalysis();
-
-    for (Expr arg : args) {
-      accumulator = accumulator.with(arg);
-    }
-    return accumulator.withScalarArguments(function.getScalarInputs(args))
-                      .withArrayArguments(function.getArrayInputs(args))
-                      .withArrayInputs(function.hasArrayInputs())
-                      .withArrayOutput(function.hasArrayOutput());
+    return BindingAnalysis.collectExprs(args)
+                          .withScalarArguments(function.getScalarInputs(args))
+                          .withArrayArguments(function.getArrayInputs(args))
+                          .withArrayInputs(function.hasArrayInputs())
+                          .withArrayOutput(function.hasArrayOutput());
   }
 
   @Override
@@ -194,20 +190,16 @@ class ApplyFunctionExpr implements Expr
     // apply function expressions are examined during expression selector 
creation, so precompute and cache the
     // binding details of children
     ImmutableList.Builder<BindingAnalysis> argBindingDetailsBuilder = 
ImmutableList.builder();
-    BindingAnalysis accumulator = new BindingAnalysis();
     for (Expr arg : argsExpr) {
-      BindingAnalysis argDetails = arg.analyzeInputs();
-      argBindingDetailsBuilder.add(argDetails);
-      accumulator = accumulator.with(argDetails);
+      argBindingDetailsBuilder.add(arg.analyzeInputs());
     }
 
     lambdaBindingAnalysis = lambdaExpr.analyzeInputs();
-
-    bindingAnalysis = accumulator.with(lambdaBindingAnalysis)
-                                 
.withArrayArguments(function.getArrayInputs(argsExpr))
-                                 .withArrayInputs(true)
-                                 
.withArrayOutput(function.hasArrayOutput(lambdaExpr));
     argsBindingAnalyses = argBindingDetailsBuilder.build();
+    bindingAnalysis = 
BindingAnalysis.collect(argBindingDetailsBuilder.add(lambdaBindingAnalysis).build())
+                                     
.withArrayArguments(function.getArrayInputs(argsExpr))
+                                     .withArrayInputs(true)
+                                     
.withArrayOutput(function.hasArrayOutput(lambdaExpr));
   }
 
   @Override


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

Reply via email to