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 4c1382af994 refactor vectorized nvl implementation into more general
coalesce implementation (#18537)
4c1382af994 is described below
commit 4c1382af994fa1cc606e28a780029d8b784c9ba5
Author: Clint Wylie <[email protected]>
AuthorDate: Tue Sep 16 22:51:50 2025 -0700
refactor vectorized nvl implementation into more general coalesce
implementation (#18537)
---
.../java/org/apache/druid/math/expr/Function.java | 4 +-
.../expr/vector/CoalesceDoubleVectorProcessor.java | 83 ++++++++++++++++++++
...r.java => CoalesceFunctionVectorProcessor.java} | 17 ++---
.../expr/vector/CoalesceLongVectorProcessor.java | 82 ++++++++++++++++++++
.../expr/vector/CoalesceVectorObjectProcessor.java | 72 ++++++++++++++++++
.../math/expr/vector/NvlDoubleVectorProcessor.java | 88 ----------------------
.../math/expr/vector/NvlLongVectorProcessor.java | 88 ----------------------
.../math/expr/vector/NvlVectorObjectProcessor.java | 63 ----------------
.../expr/vector/VectorConditionalProcessors.java | 30 ++++----
.../math/expr/VectorExprResultConsistencyTest.java | 31 +++++++-
10 files changed, 288 insertions(+), 270 deletions(-)
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 8f51a50fd90..16a46cbda9b 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
@@ -2673,13 +2673,13 @@ public interface Function extends NamedFunction
@Override
public boolean canVectorize(Expr.InputBindingInspector inspector,
List<Expr> args)
{
- return args.size() == 2 && inspector.canVectorize(args);
+ return inspector.canVectorize(args) && inspector.areSameTypes(args);
}
@Override
public <T> ExprVectorProcessor<T>
asVectorProcessor(Expr.VectorInputBindingInspector inspector, List<Expr> args)
{
- return VectorConditionalProcessors.nvl(inspector, args.get(0),
args.get(1));
+ return VectorConditionalProcessors.coalesce(inspector, args);
}
}
diff --git
a/processing/src/main/java/org/apache/druid/math/expr/vector/CoalesceDoubleVectorProcessor.java
b/processing/src/main/java/org/apache/druid/math/expr/vector/CoalesceDoubleVectorProcessor.java
new file mode 100644
index 00000000000..b04c0605351
--- /dev/null
+++
b/processing/src/main/java/org/apache/druid/math/expr/vector/CoalesceDoubleVectorProcessor.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.druid.math.expr.vector;
+
+import org.apache.druid.math.expr.Expr;
+import org.apache.druid.math.expr.ExpressionType;
+import org.apache.druid.query.filter.vector.VectorMatch;
+
+public final class CoalesceDoubleVectorProcessor extends
CoalesceFunctionVectorProcessor<double[]>
+{
+ private final double[] output;
+ private final boolean[] outputNulls;
+
+ public CoalesceDoubleVectorProcessor(
+ ExprVectorProcessor<double[]>[] processors
+ )
+ {
+ super(ExpressionType.DOUBLE, processors);
+ this.output = new double[processors[0].maxVectorSize()];
+ this.outputNulls = new boolean[processors[0].maxVectorSize()];
+ }
+
+ @Override
+ public ExprEvalVector<double[]> evalVector(Expr.VectorInputBinding bindings)
+ {
+ inputBindingFilterer.setBindings(bindings);
+
inputBindingFilterer.getVectorMatch().copyFrom(VectorMatch.allTrue(bindings.getCurrentVectorSize()));
+ final int[] selection =
inputBindingFilterer.getVectorMatch().getSelection();
+
+ ExprEvalVector<double[]> currentVector;
+ int currentProcessor = 0;
+ int notNull = 0;
+ while (notNull < bindings.getCurrentVectorSize() && currentProcessor <
processors.length) {
+ currentVector =
processors[currentProcessor].evalVector(inputBindingFilterer);
+ final double[] currentValues = currentVector.getDoubleVector();
+ final boolean[] currentNulls = currentVector.getNullVector();
+ if (currentProcessor == 0 && currentNulls == null) {
+ // this one has no nulls, bail early
+ return currentVector;
+ }
+ currentProcessor++;
+
+ int nulls = 0;
+ for (int i = 0; i < inputBindingFilterer.getCurrentVectorSize(); i++) {
+ final int outIndex = selection[i];
+ if (currentNulls != null && currentNulls[i]) {
+ if (currentProcessor < processors.length) {
+ selection[nulls++] = selection[i];
+ } else {
+ outputNulls[outIndex] = true;
+ output[outIndex] = 0;
+ }
+ } else {
+ notNull++;
+ outputNulls[outIndex] = false;
+ output[outIndex] = currentValues[i];
+ }
+ }
+ if (notNull == bindings.getCurrentVectorSize()) {
+ break;
+ }
+ inputBindingFilterer.getVectorMatch().setSelectionSize(nulls);
+ }
+ return new ExprEvalDoubleVector(output, outputNulls);
+ }
+}
diff --git
a/processing/src/main/java/org/apache/druid/math/expr/vector/NvlFunctionVectorProcessor.java
b/processing/src/main/java/org/apache/druid/math/expr/vector/CoalesceFunctionVectorProcessor.java
similarity index 69%
rename from
processing/src/main/java/org/apache/druid/math/expr/vector/NvlFunctionVectorProcessor.java
rename to
processing/src/main/java/org/apache/druid/math/expr/vector/CoalesceFunctionVectorProcessor.java
index 2053fd5b929..c551c966353 100644
---
a/processing/src/main/java/org/apache/druid/math/expr/vector/NvlFunctionVectorProcessor.java
+++
b/processing/src/main/java/org/apache/druid/math/expr/vector/CoalesceFunctionVectorProcessor.java
@@ -21,23 +21,20 @@ package org.apache.druid.math.expr.vector;
import org.apache.druid.math.expr.ExpressionType;
-public abstract class NvlFunctionVectorProcessor<T> implements
ExprVectorProcessor<T>
+public abstract class CoalesceFunctionVectorProcessor<T> implements
ExprVectorProcessor<T>
{
final ExpressionType outputType;
- final ExprVectorProcessor<T> inputProcessor;
- final ExprVectorProcessor<T> elseProcessor;
+ final ExprVectorProcessor<T>[] processors;
final FilteredVectorInputBinding inputBindingFilterer;
- public NvlFunctionVectorProcessor(
+ public CoalesceFunctionVectorProcessor(
ExpressionType outputType,
- ExprVectorProcessor<T> inputProcessor,
- ExprVectorProcessor<T> elseProcessor
+ ExprVectorProcessor<T>[] processors
)
{
this.outputType = outputType;
- this.inputProcessor = inputProcessor;
- this.elseProcessor = elseProcessor;
- this.inputBindingFilterer = new
FilteredVectorInputBinding(inputProcessor.maxVectorSize());
+ this.processors = processors;
+ this.inputBindingFilterer = new
FilteredVectorInputBinding(processors[0].maxVectorSize());
}
@Override
@@ -49,6 +46,6 @@ public abstract class NvlFunctionVectorProcessor<T>
implements ExprVectorProcess
@Override
public int maxVectorSize()
{
- return inputProcessor.maxVectorSize();
+ return processors[0].maxVectorSize();
}
}
diff --git
a/processing/src/main/java/org/apache/druid/math/expr/vector/CoalesceLongVectorProcessor.java
b/processing/src/main/java/org/apache/druid/math/expr/vector/CoalesceLongVectorProcessor.java
new file mode 100644
index 00000000000..7524e9507aa
--- /dev/null
+++
b/processing/src/main/java/org/apache/druid/math/expr/vector/CoalesceLongVectorProcessor.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.druid.math.expr.vector;
+
+import org.apache.druid.math.expr.Expr;
+import org.apache.druid.math.expr.ExpressionType;
+import org.apache.druid.query.filter.vector.VectorMatch;
+
+public final class CoalesceLongVectorProcessor extends
CoalesceFunctionVectorProcessor<long[]>
+{
+ private final long[] output;
+ private final boolean[] outputNulls;
+
+ public CoalesceLongVectorProcessor(
+ ExprVectorProcessor<long[]>[] processors
+ )
+ {
+ super(ExpressionType.LONG, processors);
+ this.output = new long[processors[0].maxVectorSize()];
+ this.outputNulls = new boolean[processors[0].maxVectorSize()];
+ }
+
+ @Override
+ public ExprEvalVector<long[]> evalVector(Expr.VectorInputBinding bindings)
+ {
+ inputBindingFilterer.setBindings(bindings);
+
inputBindingFilterer.getVectorMatch().copyFrom(VectorMatch.allTrue(bindings.getCurrentVectorSize()));
+ final int[] selection =
inputBindingFilterer.getVectorMatch().getSelection();
+
+ ExprEvalVector<long[]> currentVector;
+ int currentProcessor = 0;
+ int notNull = 0;
+ while (notNull < bindings.getCurrentVectorSize() && currentProcessor <
processors.length) {
+ currentVector =
processors[currentProcessor].evalVector(inputBindingFilterer);
+ final long[] currentValues = currentVector.getLongVector();
+ final boolean[] currentNulls = currentVector.getNullVector();
+ if (currentProcessor == 0 && currentNulls == null) {
+ // this one has no nulls, bail early
+ return currentVector;
+ }
+ currentProcessor++;
+ int nulls = 0;
+ for (int i = 0; i < inputBindingFilterer.getCurrentVectorSize(); i++) {
+ final int outIndex = selection[i];
+ if (currentNulls != null && currentNulls[i]) {
+ if (currentProcessor < processors.length) {
+ selection[nulls++] = selection[i];
+ } else {
+ outputNulls[outIndex] = true;
+ output[outIndex] = 0;
+ }
+ } else {
+ notNull++;
+ outputNulls[outIndex] = false;
+ output[outIndex] = currentValues[i];
+ }
+ }
+ if (notNull == bindings.getCurrentVectorSize()) {
+ break;
+ }
+ inputBindingFilterer.getVectorMatch().setSelectionSize(nulls);
+ }
+ return new ExprEvalLongVector(output, outputNulls);
+ }
+}
diff --git
a/processing/src/main/java/org/apache/druid/math/expr/vector/CoalesceVectorObjectProcessor.java
b/processing/src/main/java/org/apache/druid/math/expr/vector/CoalesceVectorObjectProcessor.java
new file mode 100644
index 00000000000..12cddbcad93
--- /dev/null
+++
b/processing/src/main/java/org/apache/druid/math/expr/vector/CoalesceVectorObjectProcessor.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.druid.math.expr.vector;
+
+import org.apache.druid.math.expr.Expr;
+import org.apache.druid.math.expr.ExpressionType;
+import org.apache.druid.query.filter.vector.VectorMatch;
+
+public final class CoalesceVectorObjectProcessor extends
CoalesceFunctionVectorProcessor<Object[]>
+{
+ private final Object[] output;
+
+ public CoalesceVectorObjectProcessor(
+ ExpressionType outputType,
+ ExprVectorProcessor<Object[]>[] processors
+ )
+ {
+ super(outputType, processors);
+ this.output = new Object[processors[0].maxVectorSize()];
+ }
+
+ @Override
+ public ExprEvalVector<Object[]> evalVector(Expr.VectorInputBinding bindings)
+ {
+ inputBindingFilterer.setBindings(bindings);
+
inputBindingFilterer.getVectorMatch().copyFrom(VectorMatch.allTrue(bindings.getCurrentVectorSize()));
+ final int[] selection =
inputBindingFilterer.getVectorMatch().getSelection();
+
+ int currentProcessor = 0;
+ int notNull = 0;
+ while (notNull < bindings.getCurrentVectorSize() && currentProcessor <
processors.length) {
+ final ExprEvalVector<Object[]> inputVector =
processors[currentProcessor++].evalVector(inputBindingFilterer);
+ final Object[] inputValues = inputVector.getObjectVector();
+ int nulls = 0;
+ for (int i = 0; i < inputBindingFilterer.getCurrentVectorSize(); i++) {
+ final int outIndex = selection[i];
+ if (inputValues[i] == null) {
+ if (currentProcessor < processors.length) {
+ selection[nulls++] = selection[i];
+ } else {
+ output[outIndex] = null;
+ }
+ } else {
+ notNull++;
+ output[outIndex] = inputValues[i];
+ }
+ }
+ if (notNull == bindings.getCurrentVectorSize()) {
+ break;
+ }
+ inputBindingFilterer.getVectorMatch().setSelectionSize(nulls);
+ }
+ return new ExprEvalObjectVector(output, outputType);
+ }
+}
diff --git
a/processing/src/main/java/org/apache/druid/math/expr/vector/NvlDoubleVectorProcessor.java
b/processing/src/main/java/org/apache/druid/math/expr/vector/NvlDoubleVectorProcessor.java
deleted file mode 100644
index 1e2f87987ef..00000000000
---
a/processing/src/main/java/org/apache/druid/math/expr/vector/NvlDoubleVectorProcessor.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.druid.math.expr.vector;
-
-import org.apache.druid.math.expr.Expr;
-import org.apache.druid.math.expr.ExpressionType;
-
-public final class NvlDoubleVectorProcessor extends
NvlFunctionVectorProcessor<double[]>
-{
- private final double[] output;
- private final boolean[] outputNulls;
-
- public NvlDoubleVectorProcessor(
- ExprVectorProcessor<double[]> inputProcessor,
- ExprVectorProcessor<double[]> elseProcessor
- )
- {
- super(ExpressionType.DOUBLE, inputProcessor, elseProcessor);
- this.output = new double[inputProcessor.maxVectorSize()];
- this.outputNulls = new boolean[inputProcessor.maxVectorSize()];
- }
-
- @Override
- public ExprEvalVector<double[]> evalVector(Expr.VectorInputBinding bindings)
- {
- inputBindingFilterer.setBindings(bindings);
- final ExprEvalVector<double[]> inputVector =
inputProcessor.evalVector(bindings);
-
- if (inputVector.getNullVector() == null) {
- // this one has no nulls, just spit it out
- return inputVector;
- }
-
-
- final double[] inputValues = inputVector.getDoubleVector();
- final boolean[] inputNulls = inputVector.getNullVector();
- final int[] selection =
inputBindingFilterer.getVectorMatch().getSelection();
- int nulls = 0;
- for (int i = 0; i < bindings.getCurrentVectorSize(); i++) {
- if (inputNulls[i]) {
- selection[nulls++] = i;
- } else {
- outputNulls[i] = false;
- output[i] = inputValues[i];
- }
- }
- if (nulls == 0) {
- return new ExprEvalDoubleVector(output, outputNulls);
- }
- inputBindingFilterer.getVectorMatch().setSelectionSize(nulls);
-
- if (nulls == bindings.getCurrentVectorSize()) {
- // all nulls, just return the other
- return elseProcessor.evalVector(bindings);
- }
-
- final ExprEvalVector<double[]> elseVector =
elseProcessor.evalVector(inputBindingFilterer);
- final double[] elseValues = elseVector.getDoubleVector();
- final boolean[] elseNulls = elseVector.getNullVector();
- for (int i = 0; i < nulls; i++) {
- final int outIndex = selection[i];
- if (elseNulls != null && elseNulls[i]) {
- outputNulls[outIndex] = true;
- } else {
- output[outIndex] = elseValues[i];
- outputNulls[outIndex] = false;
- }
- }
- return new ExprEvalDoubleVector(output, outputNulls);
- }
-}
diff --git
a/processing/src/main/java/org/apache/druid/math/expr/vector/NvlLongVectorProcessor.java
b/processing/src/main/java/org/apache/druid/math/expr/vector/NvlLongVectorProcessor.java
deleted file mode 100644
index 9f709005f02..00000000000
---
a/processing/src/main/java/org/apache/druid/math/expr/vector/NvlLongVectorProcessor.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.druid.math.expr.vector;
-
-import org.apache.druid.math.expr.Expr;
-import org.apache.druid.math.expr.ExpressionType;
-
-public final class NvlLongVectorProcessor extends
NvlFunctionVectorProcessor<long[]>
-{
- private final long[] output;
- private final boolean[] outputNulls;
-
- public NvlLongVectorProcessor(
- ExprVectorProcessor<long[]> inputProcessor,
- ExprVectorProcessor<long[]> elseProcessor
- )
- {
- super(ExpressionType.LONG, inputProcessor, elseProcessor);
- this.output = new long[inputProcessor.maxVectorSize()];
- this.outputNulls = new boolean[inputProcessor.maxVectorSize()];
- }
-
- @Override
- public ExprEvalVector<long[]> evalVector(Expr.VectorInputBinding bindings)
- {
- inputBindingFilterer.setBindings(bindings);
- final ExprEvalVector<long[]> inputVector =
inputProcessor.evalVector(bindings);
-
- if (inputVector.getNullVector() == null) {
- // this one has no nulls, just spit it out
- return inputVector;
- }
-
-
- final long[] inputValues = inputVector.getLongVector();
- final boolean[] inputNulls = inputVector.getNullVector();
- final int[] selection =
inputBindingFilterer.getVectorMatch().getSelection();
- int nulls = 0;
- for (int i = 0; i < bindings.getCurrentVectorSize(); i++) {
- if (inputNulls[i]) {
- selection[nulls++] = i;
- } else {
- outputNulls[i] = false;
- output[i] = inputValues[i];
- }
- }
- inputBindingFilterer.getVectorMatch().setSelectionSize(nulls);
- if (nulls == 0) {
- return new ExprEvalLongVector(output, outputNulls);
- }
-
- if (nulls == bindings.getCurrentVectorSize()) {
- // all nulls, just return the other
- return elseProcessor.evalVector(bindings);
- }
-
- final ExprEvalVector<long[]> elseVector =
elseProcessor.evalVector(inputBindingFilterer);
- final long[] elseValues = elseVector.getLongVector();
- final boolean[] elseNulls = elseVector.getNullVector();
- for (int i = 0; i < nulls; i++) {
- final int outIndex = selection[i];
- if (elseNulls != null && elseNulls[i]) {
- outputNulls[outIndex] = true;
- } else {
- output[outIndex] = elseValues[i];
- outputNulls[outIndex] = false;
- }
- }
- return new ExprEvalLongVector(output, outputNulls);
- }
-}
diff --git
a/processing/src/main/java/org/apache/druid/math/expr/vector/NvlVectorObjectProcessor.java
b/processing/src/main/java/org/apache/druid/math/expr/vector/NvlVectorObjectProcessor.java
deleted file mode 100644
index 061a66b0827..00000000000
---
a/processing/src/main/java/org/apache/druid/math/expr/vector/NvlVectorObjectProcessor.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.druid.math.expr.vector;
-
-import org.apache.druid.math.expr.Expr;
-import org.apache.druid.math.expr.ExpressionType;
-
-public final class NvlVectorObjectProcessor extends
NvlFunctionVectorProcessor<Object[]>
-{
- private final Object[] output;
-
- public NvlVectorObjectProcessor(
- ExpressionType outputType,
- ExprVectorProcessor<Object[]> inputProcessor,
- ExprVectorProcessor<Object[]> elseProcessor
- )
- {
- super(outputType, inputProcessor, elseProcessor);
- this.output = new Object[inputProcessor.maxVectorSize()];
- }
-
- @Override
- public ExprEvalVector<Object[]> evalVector(Expr.VectorInputBinding bindings)
- {
- inputBindingFilterer.setBindings(bindings);
- final ExprEvalVector<Object[]> inputVector =
inputProcessor.evalVector(bindings);
-
- Object[] inputValues = inputVector.getObjectVector();
- final int[] selection =
inputBindingFilterer.getVectorMatch().getSelection();
- int nulls = 0;
- for (int i = 0; i < bindings.getCurrentVectorSize(); i++) {
- if (inputValues[i] == null) {
- selection[nulls++] = i;
- } else {
- output[i] = inputValues[i];
- }
- }
- inputBindingFilterer.getVectorMatch().setSelectionSize(nulls);
- final ExprEvalVector<Object[]> elseVector =
elseProcessor.evalVector(inputBindingFilterer);
- final Object[] elseValues = elseVector.getObjectVector();
- for (int i = 0; i < nulls; i++) {
- output[selection[i]] = elseValues[i];
- }
- return new ExprEvalObjectVector(output, outputType);
- }
-}
diff --git
a/processing/src/main/java/org/apache/druid/math/expr/vector/VectorConditionalProcessors.java
b/processing/src/main/java/org/apache/druid/math/expr/vector/VectorConditionalProcessors.java
index b093f52da6e..5ab6dcac51c 100644
---
a/processing/src/main/java/org/apache/druid/math/expr/vector/VectorConditionalProcessors.java
+++
b/processing/src/main/java/org/apache/druid/math/expr/vector/VectorConditionalProcessors.java
@@ -29,34 +29,30 @@ import java.util.List;
public class VectorConditionalProcessors
{
- public static <T> ExprVectorProcessor<T>
nvl(Expr.VectorInputBindingInspector inspector, Expr left, Expr right)
+ public static <T> ExprVectorProcessor<T>
coalesce(Expr.VectorInputBindingInspector inspector, List<Expr> args)
{
- final ExpressionType leftType = left.getOutputType(inspector);
- final ExpressionType rightType = right.getOutputType(inspector);
- final ExpressionType outputType =
ExpressionTypeConversion.leastRestrictiveType(leftType, rightType);
+ ExpressionType outputType = null;
+ for (Expr arg : args) {
+ outputType = ExpressionTypeConversion.leastRestrictiveType(outputType,
arg.getOutputType(inspector));
+ }
final ExprVectorProcessor<?> processor;
if (outputType == null) {
// if output type is null, it means all the input types were null
(non-existent), and nvl(null, null) is null
return VectorProcessors.constant((Long) null,
inspector.getMaxVectorSize());
}
+
+ ExprVectorProcessor[] processors = new ExprVectorProcessor[args.size()];
+ for (int i = 0; i < args.size(); i++) {
+ processors[i] =
CastToTypeVectorProcessor.cast(args.get(i).asVectorProcessor(inspector),
outputType);
+ }
if (outputType.is(ExprType.LONG)) {
// long is most restrictive so both processors are definitely long typed
if output is long
- processor = new NvlLongVectorProcessor(
- left.asVectorProcessor(inspector),
- right.asVectorProcessor(inspector)
- );
+ processor = new CoalesceLongVectorProcessor(processors);
} else if (outputType.is(ExprType.DOUBLE)) {
- processor = new NvlDoubleVectorProcessor(
- CastToTypeVectorProcessor.cast(left.asVectorProcessor(inspector),
ExpressionType.DOUBLE),
- CastToTypeVectorProcessor.cast(right.asVectorProcessor(inspector),
ExpressionType.DOUBLE)
- );
+ processor = new CoalesceDoubleVectorProcessor(processors);
} else {
- processor = new NvlVectorObjectProcessor(
- outputType,
- CastToTypeVectorProcessor.cast(left.asVectorProcessor(inspector),
outputType),
- CastToTypeVectorProcessor.cast(right.asVectorProcessor(inspector),
outputType)
- );
+ processor = new CoalesceVectorObjectProcessor(outputType, processors);
}
return (ExprVectorProcessor<T>) processor;
}
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 c54f01472bc..bb199f04ee5 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
@@ -65,7 +65,7 @@ public class VectorExprResultConsistencyTest extends
InitializedNullHandlingTest
{
private static final Logger log = new
Logger(VectorExprResultConsistencyTest.class);
private static final int NUM_ITERATIONS = 10;
- private static final int VECTOR_SIZE = 512;
+ private static final int VECTOR_SIZE = 4;
private static final Map<String, String> LOOKUP = Map.of(
@@ -135,12 +135,16 @@ public class VectorExprResultConsistencyTest extends
InitializedNullHandlingTest
final Map<String, ExpressionType> types = ImmutableMap.<String,
ExpressionType>builder()
.put("l1", ExpressionType.LONG)
.put("l2", ExpressionType.LONG)
+ .put("l3", ExpressionType.LONG)
.put("d1", ExpressionType.DOUBLE)
.put("d2", ExpressionType.DOUBLE)
+ .put("d3", ExpressionType.DOUBLE)
.put("s1", ExpressionType.STRING)
.put("s2", ExpressionType.STRING)
+ .put("s3", ExpressionType.STRING)
.put("boolString1", ExpressionType.STRING)
.put("boolString2", ExpressionType.STRING)
+ .put("boolString3", ExpressionType.STRING)
.build();
@@ -339,7 +343,8 @@ public class VectorExprResultConsistencyTest extends
InitializedNullHandlingTest
public void testSymmetricalBivariateFunctions()
{
final List<String> functions = List.of(
- "nvl"
+ "nvl",
+ "coalesce"
);
final List<String> templates = List.of(
"%s(d1, d2)",
@@ -380,8 +385,11 @@ public class VectorExprResultConsistencyTest extends
InitializedNullHandlingTest
public void testCaseSearchedFunction()
{
testExpression("case_searched(boolString1, s1, boolString2, s2, s1)",
types);
+ testExpression("case_searched(boolString1, s1, boolString2, s2,
boolString3, s3, s1)", types);
testExpression("case_searched(boolString1, l1, boolString2, l2, l2)",
types);
+ testExpression("case_searched(boolString1, l1, boolString2, l2,
boolString3, l3, l2)", types);
testExpression("case_searched(boolString1, d1, boolString2, d2, d1)",
types);
+ testExpression("case_searched(boolString1, d1, boolString2, d2,
boolString3, d3, d1)", types);
testExpression("case_searched(l1 % 2 == 0, -1, l1 % 2 == 1, l2 / (l1 %
2))", types);
Assertions.assertFalse(
Parser.parse("case_searched(boolString1, d1, boolString2, d2, l1)",
MACRO_TABLE)
@@ -407,6 +415,25 @@ public class VectorExprResultConsistencyTest extends
InitializedNullHandlingTest
);
}
+ @Test
+ public void testCoalesceFunction()
+ {
+ final List<String> functions = List.of(
+ "coalesce"
+ );
+ final List<String> templates = List.of(
+ "%s(nonexistent, d1, d2, d3)",
+ "%s(nonexistent, d1, nonexistent2, d2, nonexistent3, d3)",
+ "%s(nonexistent, nonexistent2, l1, l2, nonexistent, l3)",
+ "%s(nonexistent, s1, nonexistent2, s2)"
+ );
+ testFunctions(types, templates, functions);
+ // cannot vectorize mixed arg types
+ Assertions.assertFalse(
+ Parser.parse("coalesce(s1, d1, s1, l1, d1)", MACRO_TABLE)
+ .canVectorize(InputBindings.inspectorFromTypeMap(types))
+ );
+ }
@Test
public void testStringFns()
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]