fix json_value sql planning with decimal type, fix vectorized expression math null value handling in default mode (#13214)

* fix json_value sql planning with decimal type, fix vectorized expression math null value handling in default mode
changes:
* json_value 'returning' decimal will now plan to native double typed query instead of ending up with default string typing, allowing decimal vector math expressions to work with this type
* vector math expressions now zero out 'null' values even in 'default' mode (druid.generic.useDefaultValueForNull=false) to prevent downstream things that do not check the null vector from producing incorrect results

* more better

* test and why not vectorize

* more test, more fix
This commit is contained in:
Clint Wylie 2022-10-12 16:28:41 -07:00 committed by GitHub
parent 3e13584e0e
commit 6eff6c9ae4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 355 additions and 147 deletions

View File

@ -112,7 +112,7 @@ final class BinMinusExpr extends BinaryEvalOpExprBase
@Override @Override
public boolean canVectorize(InputBindingInspector inspector) public boolean canVectorize(InputBindingInspector inspector)
{ {
return inspector.areNumeric(left, right) && inspector.canVectorize(left, right); return inspector.areScalar(left, right) && inspector.canVectorize(left, right);
} }
@Override @Override
@ -151,7 +151,7 @@ final class BinMulExpr extends BinaryEvalOpExprBase
@Override @Override
public boolean canVectorize(InputBindingInspector inspector) public boolean canVectorize(InputBindingInspector inspector)
{ {
return inspector.areNumeric(left, right) && inspector.canVectorize(left, right); return inspector.areScalar(left, right) && inspector.canVectorize(left, right);
} }
@Override @Override
@ -190,7 +190,7 @@ final class BinDivExpr extends BinaryEvalOpExprBase
@Override @Override
public boolean canVectorize(InputBindingInspector inspector) public boolean canVectorize(InputBindingInspector inspector)
{ {
return inspector.areNumeric(left, right) && inspector.canVectorize(left, right); return inspector.areScalar(left, right) && inspector.canVectorize(left, right);
} }
@Override @Override
@ -229,7 +229,7 @@ class BinPowExpr extends BinaryEvalOpExprBase
@Override @Override
public boolean canVectorize(InputBindingInspector inspector) public boolean canVectorize(InputBindingInspector inspector)
{ {
return inspector.areNumeric(left, right) && inspector.canVectorize(left, right); return inspector.areScalar(left, right) && inspector.canVectorize(left, right);
} }
@Override @Override
@ -268,7 +268,7 @@ class BinModuloExpr extends BinaryEvalOpExprBase
@Override @Override
public boolean canVectorize(InputBindingInspector inspector) public boolean canVectorize(InputBindingInspector inspector)
{ {
return inspector.areNumeric(left, right) && inspector.canVectorize(left, right); return inspector.areScalar(left, right) && inspector.canVectorize(left, right);
} }
@Override @Override

View File

@ -0,0 +1,94 @@
/*
* 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;
/**
* common machinery for processing two input operators and functions, which should always treat null inputs as null
* output, and are backed by a primitive values instead of an object values (and need to use the null vectors instead of
* checking the vector themselves for nulls)
*
* this one is specialized for producing double[], see {@link BivariateLongFunctionVectorValueProcessor} for
* long[] primitives.
*/
public abstract class BivariateDoubleFunctionVectorValueProcessor<TLeftInput, TRightInput>
implements ExprVectorProcessor<double[]>
{
final ExprVectorProcessor<TLeftInput> left;
final ExprVectorProcessor<TRightInput> right;
final int maxVectorSize;
final boolean[] outNulls;
final double[] outValues;
protected BivariateDoubleFunctionVectorValueProcessor(
ExprVectorProcessor<TLeftInput> left,
ExprVectorProcessor<TRightInput> right,
int maxVectorSize
)
{
this.left = left;
this.right = right;
this.maxVectorSize = maxVectorSize;
this.outValues = new double[maxVectorSize];
this.outNulls = new boolean[maxVectorSize];
}
@Override
public final ExprEvalVector<double[]> evalVector(Expr.VectorInputBinding bindings)
{
final ExprEvalVector<TLeftInput> lhs = left.evalVector(bindings);
final ExprEvalVector<TRightInput> rhs = right.evalVector(bindings);
final int currentSize = bindings.getCurrentVectorSize();
final boolean[] leftNulls = lhs.getNullVector();
final boolean[] rightNulls = rhs.getNullVector();
final boolean hasLeftNulls = leftNulls != null;
final boolean hasRightNulls = rightNulls != null;
final boolean hasNulls = hasLeftNulls || hasRightNulls;
final TLeftInput leftInput = lhs.values();
final TRightInput rightInput = rhs.values();
if (hasNulls) {
for (int i = 0; i < currentSize; i++) {
outNulls[i] = (hasLeftNulls && leftNulls[i]) || (hasRightNulls && rightNulls[i]);
if (!outNulls[i]) {
processIndex(leftInput, rightInput, i);
} else {
outValues[i] = 0.0;
}
}
} else {
for (int i = 0; i < currentSize; i++) {
processIndex(leftInput, rightInput, i);
outNulls[i] = false;
}
}
return asEval();
}
abstract void processIndex(TLeftInput leftInput, TRightInput rightInput, int i);
final ExprEvalVector<double[]> asEval()
{
return new ExprEvalDoubleVector(outValues, outNulls);
}
}

View File

@ -26,8 +26,9 @@ import javax.annotation.Nullable;
/** /**
* Basic vector processor that processes 2 inputs and works for both primitive value vectors and object vectors. * Basic vector processor that processes 2 inputs and works for both primitive value vectors and object vectors.
* Different from {@link BivariateFunctionVectorValueProcessor} and {@link BivariateFunctionVectorObjectProcessor} in * Different from {@link BivariateLongFunctionVectorValueProcessor}, {@link BivariateDoubleFunctionVectorValueProcessor}
* that subclasses of this class must check for and directly decide how to handle null values. * and {@link BivariateFunctionVectorObjectProcessor} in that subclasses of this class must check for and directly
* decide how to handle null values.
*/ */
public abstract class BivariateFunctionVectorProcessor<TLeftInput, TRightInput, TOutput> public abstract class BivariateFunctionVectorProcessor<TLeftInput, TRightInput, TOutput>
implements ExprVectorProcessor<TOutput> implements ExprVectorProcessor<TOutput>

View File

@ -25,32 +25,34 @@ import org.apache.druid.math.expr.Expr;
* common machinery for processing two input operators and functions, which should always treat null inputs as null * common machinery for processing two input operators and functions, which should always treat null inputs as null
* output, and are backed by a primitive values instead of an object values (and need to use the null vectors instead of * output, and are backed by a primitive values instead of an object values (and need to use the null vectors instead of
* checking the vector themselves for nulls) * checking the vector themselves for nulls)
*
* this one is specialized for producing long[], see {@link BivariateDoubleFunctionVectorValueProcessor} for
* double[] primitives.
*/ */
public abstract class BivariateFunctionVectorValueProcessor<TLeftInput, TRightInput, TOutput> public abstract class BivariateLongFunctionVectorValueProcessor<TLeftInput, TRightInput>
implements ExprVectorProcessor<TOutput> implements ExprVectorProcessor<long[]>
{ {
final ExprVectorProcessor<TLeftInput> left; final ExprVectorProcessor<TLeftInput> left;
final ExprVectorProcessor<TRightInput> right; final ExprVectorProcessor<TRightInput> right;
final int maxVectorSize; final int maxVectorSize;
final boolean[] outNulls; final boolean[] outNulls;
final TOutput outValues; final long[] outValues;
protected BivariateFunctionVectorValueProcessor( protected BivariateLongFunctionVectorValueProcessor(
ExprVectorProcessor<TLeftInput> left, ExprVectorProcessor<TLeftInput> left,
ExprVectorProcessor<TRightInput> right, ExprVectorProcessor<TRightInput> right,
int maxVectorSize, int maxVectorSize
TOutput outValues
) )
{ {
this.left = left; this.left = left;
this.right = right; this.right = right;
this.maxVectorSize = maxVectorSize; this.maxVectorSize = maxVectorSize;
this.outValues = new long[maxVectorSize];
this.outNulls = new boolean[maxVectorSize]; this.outNulls = new boolean[maxVectorSize];
this.outValues = outValues;
} }
@Override @Override
public final ExprEvalVector<TOutput> evalVector(Expr.VectorInputBinding bindings) public final ExprEvalVector<long[]> evalVector(Expr.VectorInputBinding bindings)
{ {
final ExprEvalVector<TLeftInput> lhs = left.evalVector(bindings); final ExprEvalVector<TLeftInput> lhs = left.evalVector(bindings);
final ExprEvalVector<TRightInput> rhs = right.evalVector(bindings); final ExprEvalVector<TRightInput> rhs = right.evalVector(bindings);
@ -70,6 +72,8 @@ public abstract class BivariateFunctionVectorValueProcessor<TLeftInput, TRightIn
outNulls[i] = (hasLeftNulls && leftNulls[i]) || (hasRightNulls && rightNulls[i]); outNulls[i] = (hasLeftNulls && leftNulls[i]) || (hasRightNulls && rightNulls[i]);
if (!outNulls[i]) { if (!outNulls[i]) {
processIndex(leftInput, rightInput, i); processIndex(leftInput, rightInput, i);
} else {
outValues[i] = 0L;
} }
} }
} else { } else {
@ -83,5 +87,8 @@ public abstract class BivariateFunctionVectorValueProcessor<TLeftInput, TRightIn
abstract void processIndex(TLeftInput leftInput, TRightInput rightInput, int i); abstract void processIndex(TLeftInput leftInput, TRightInput rightInput, int i);
abstract ExprEvalVector<TOutput> asEval(); final ExprEvalVector<long[]> asEval()
{
return new ExprEvalLongVector(outValues, outNulls);
}
} }

View File

@ -22,14 +22,14 @@ package org.apache.druid.math.expr.vector;
import org.apache.druid.math.expr.ExpressionType; import org.apache.druid.math.expr.ExpressionType;
/** /**
* specialized {@link UnivariateFunctionVectorValueProcessor} for processing (double[]) -> double[] * specialized {@link UnivariateDoubleFunctionVectorValueProcessor} for processing (double[]) -> double[]
*/ */
public abstract class DoubleOutDoubleInFunctionVectorValueProcessor public abstract class DoubleOutDoubleInFunctionVectorValueProcessor
extends UnivariateFunctionVectorValueProcessor<double[], double[]> extends UnivariateDoubleFunctionVectorValueProcessor<double[]>
{ {
public DoubleOutDoubleInFunctionVectorValueProcessor(ExprVectorProcessor<double[]> processor, int maxVectorSize) public DoubleOutDoubleInFunctionVectorValueProcessor(ExprVectorProcessor<double[]> processor, int maxVectorSize)
{ {
super(CastToTypeVectorProcessor.cast(processor, ExpressionType.DOUBLE), maxVectorSize, new double[maxVectorSize]); super(CastToTypeVectorProcessor.cast(processor, ExpressionType.DOUBLE), maxVectorSize);
} }
public abstract double apply(double input); public abstract double apply(double input);
@ -45,10 +45,4 @@ public abstract class DoubleOutDoubleInFunctionVectorValueProcessor
{ {
outValues[i] = apply(input[i]); outValues[i] = apply(input[i]);
} }
@Override
final ExprEvalVector<double[]> asEval()
{
return new ExprEvalDoubleVector(outValues, outNulls);
}
} }

View File

@ -22,10 +22,10 @@ package org.apache.druid.math.expr.vector;
import org.apache.druid.math.expr.ExpressionType; import org.apache.druid.math.expr.ExpressionType;
/** /**
* specialized {@link BivariateFunctionVectorValueProcessor} for processing (double[], long[]) -> double[] * specialized {@link BivariateDoubleFunctionVectorValueProcessor} for processing (double[], long[]) -> double[]
*/ */
public abstract class DoubleOutDoubleLongInFunctionVectorValueProcessor public abstract class DoubleOutDoubleLongInFunctionVectorValueProcessor
extends BivariateFunctionVectorValueProcessor<double[], long[], double[]> extends BivariateDoubleFunctionVectorValueProcessor<double[], long[]>
{ {
public DoubleOutDoubleLongInFunctionVectorValueProcessor( public DoubleOutDoubleLongInFunctionVectorValueProcessor(
ExprVectorProcessor<double[]> left, ExprVectorProcessor<double[]> left,
@ -36,8 +36,7 @@ public abstract class DoubleOutDoubleLongInFunctionVectorValueProcessor
super( super(
CastToTypeVectorProcessor.cast(left, ExpressionType.DOUBLE), CastToTypeVectorProcessor.cast(left, ExpressionType.DOUBLE),
CastToTypeVectorProcessor.cast(right, ExpressionType.LONG), CastToTypeVectorProcessor.cast(right, ExpressionType.LONG),
maxVectorSize, maxVectorSize
new double[maxVectorSize]
); );
} }
@ -54,10 +53,4 @@ public abstract class DoubleOutDoubleLongInFunctionVectorValueProcessor
{ {
outValues[i] = apply(leftInput[i], rightInput[i]); outValues[i] = apply(leftInput[i], rightInput[i]);
} }
@Override
final ExprEvalVector<double[]> asEval()
{
return new ExprEvalDoubleVector(outValues, outNulls);
}
} }

View File

@ -22,10 +22,10 @@ package org.apache.druid.math.expr.vector;
import org.apache.druid.math.expr.ExpressionType; import org.apache.druid.math.expr.ExpressionType;
/** /**
* specialized {@link BivariateFunctionVectorValueProcessor} for processing (double[], double[]) -> double[] * specialized {@link BivariateDoubleFunctionVectorValueProcessor} for processing (double[], double[]) -> double[]
*/ */
public abstract class DoubleOutDoublesInFunctionVectorValueProcessor public abstract class DoubleOutDoublesInFunctionVectorValueProcessor
extends BivariateFunctionVectorValueProcessor<double[], double[], double[]> extends BivariateDoubleFunctionVectorValueProcessor<double[], double[]>
{ {
public DoubleOutDoublesInFunctionVectorValueProcessor( public DoubleOutDoublesInFunctionVectorValueProcessor(
ExprVectorProcessor<double[]> left, ExprVectorProcessor<double[]> left,
@ -36,8 +36,7 @@ public abstract class DoubleOutDoublesInFunctionVectorValueProcessor
super( super(
CastToTypeVectorProcessor.cast(left, ExpressionType.DOUBLE), CastToTypeVectorProcessor.cast(left, ExpressionType.DOUBLE),
CastToTypeVectorProcessor.cast(right, ExpressionType.DOUBLE), CastToTypeVectorProcessor.cast(right, ExpressionType.DOUBLE),
maxVectorSize, maxVectorSize
new double[maxVectorSize]
); );
} }
@ -54,10 +53,4 @@ public abstract class DoubleOutDoublesInFunctionVectorValueProcessor
{ {
outValues[i] = apply(leftInput[i], rightInput[i]); outValues[i] = apply(leftInput[i], rightInput[i]);
} }
@Override
final ExprEvalVector<double[]> asEval()
{
return new ExprEvalDoubleVector(outValues, outNulls);
}
} }

View File

@ -22,10 +22,10 @@ package org.apache.druid.math.expr.vector;
import org.apache.druid.math.expr.ExpressionType; import org.apache.druid.math.expr.ExpressionType;
/** /**
* specialized {@link BivariateFunctionVectorValueProcessor} for processing (long[], double[]) -> double[] * specialized {@link BivariateDoubleFunctionVectorValueProcessor} for processing (long[], double[]) -> double[]
*/ */
public abstract class DoubleOutLongDoubleInFunctionVectorValueProcessor public abstract class DoubleOutLongDoubleInFunctionVectorValueProcessor
extends BivariateFunctionVectorValueProcessor<long[], double[], double[]> extends BivariateDoubleFunctionVectorValueProcessor<long[], double[]>
{ {
public DoubleOutLongDoubleInFunctionVectorValueProcessor( public DoubleOutLongDoubleInFunctionVectorValueProcessor(
ExprVectorProcessor<long[]> left, ExprVectorProcessor<long[]> left,
@ -36,8 +36,7 @@ public abstract class DoubleOutLongDoubleInFunctionVectorValueProcessor
super( super(
CastToTypeVectorProcessor.cast(left, ExpressionType.LONG), CastToTypeVectorProcessor.cast(left, ExpressionType.LONG),
CastToTypeVectorProcessor.cast(right, ExpressionType.DOUBLE), CastToTypeVectorProcessor.cast(right, ExpressionType.DOUBLE),
maxVectorSize, maxVectorSize
new double[maxVectorSize]
); );
} }
@ -54,10 +53,4 @@ public abstract class DoubleOutLongDoubleInFunctionVectorValueProcessor
{ {
outValues[i] = apply(leftInput[i], rightInput[i]); outValues[i] = apply(leftInput[i], rightInput[i]);
} }
@Override
final ExprEvalVector<double[]> asEval()
{
return new ExprEvalDoubleVector(outValues, outNulls);
}
} }

View File

@ -22,14 +22,14 @@ package org.apache.druid.math.expr.vector;
import org.apache.druid.math.expr.ExpressionType; import org.apache.druid.math.expr.ExpressionType;
/** /**
* specialized {@link UnivariateFunctionVectorValueProcessor} for processing (long[]) -> double[] * specialized {@link UnivariateDoubleFunctionVectorValueProcessor} for processing (long[]) -> double[]
*/ */
public abstract class DoubleOutLongInFunctionVectorValueProcessor public abstract class DoubleOutLongInFunctionVectorValueProcessor
extends UnivariateFunctionVectorValueProcessor<long[], double[]> extends UnivariateDoubleFunctionVectorValueProcessor<long[]>
{ {
public DoubleOutLongInFunctionVectorValueProcessor(ExprVectorProcessor<long[]> processor, int maxVectorSize) public DoubleOutLongInFunctionVectorValueProcessor(ExprVectorProcessor<long[]> processor, int maxVectorSize)
{ {
super(CastToTypeVectorProcessor.cast(processor, ExpressionType.LONG), maxVectorSize, new double[maxVectorSize]); super(CastToTypeVectorProcessor.cast(processor, ExpressionType.LONG), maxVectorSize);
} }
public abstract double apply(long input); public abstract double apply(long input);
@ -45,10 +45,4 @@ public abstract class DoubleOutLongInFunctionVectorValueProcessor
{ {
outValues[i] = apply(input[i]); outValues[i] = apply(input[i]);
} }
@Override
final ExprEvalVector<double[]> asEval()
{
return new ExprEvalDoubleVector(outValues, outNulls);
}
} }

View File

@ -22,10 +22,10 @@ package org.apache.druid.math.expr.vector;
import org.apache.druid.math.expr.ExpressionType; import org.apache.druid.math.expr.ExpressionType;
/** /**
* specialized {@link BivariateFunctionVectorValueProcessor} for processing (long[], long[]) -> double[] * specialized {@link BivariateDoubleFunctionVectorValueProcessor} for processing (long[], long[]) -> double[]
*/ */
public abstract class DoubleOutLongsInFunctionVectorValueProcessor public abstract class DoubleOutLongsInFunctionVectorValueProcessor
extends BivariateFunctionVectorValueProcessor<long[], long[], double[]> extends BivariateDoubleFunctionVectorValueProcessor<long[], long[]>
{ {
public DoubleOutLongsInFunctionVectorValueProcessor( public DoubleOutLongsInFunctionVectorValueProcessor(
ExprVectorProcessor<long[]> left, ExprVectorProcessor<long[]> left,
@ -36,8 +36,7 @@ public abstract class DoubleOutLongsInFunctionVectorValueProcessor
super( super(
CastToTypeVectorProcessor.cast(left, ExpressionType.LONG), CastToTypeVectorProcessor.cast(left, ExpressionType.LONG),
CastToTypeVectorProcessor.cast(right, ExpressionType.LONG), CastToTypeVectorProcessor.cast(right, ExpressionType.LONG),
maxVectorSize, maxVectorSize
new double[maxVectorSize]
); );
} }
@ -54,10 +53,4 @@ public abstract class DoubleOutLongsInFunctionVectorValueProcessor
{ {
outValues[i] = apply(leftInput[i], rightInput[i]); outValues[i] = apply(leftInput[i], rightInput[i]);
} }
@Override
final ExprEvalVector<double[]> asEval()
{
return new ExprEvalDoubleVector(outValues, outNulls);
}
} }

View File

@ -22,13 +22,14 @@ package org.apache.druid.math.expr.vector;
import org.apache.druid.math.expr.ExpressionType; import org.apache.druid.math.expr.ExpressionType;
/** /**
* specialized {@link UnivariateFunctionVectorValueProcessor} for processing (long[]) -> long[] * specialized {@link UnivariateLongFunctionVectorValueProcessor} for processing (long[]) -> long[]
*/ */
public abstract class LongOutDoubleInFunctionVectorValueProcessor extends UnivariateFunctionVectorValueProcessor<double[], long[]> public abstract class LongOutDoubleInFunctionVectorValueProcessor
extends UnivariateLongFunctionVectorValueProcessor<double[]>
{ {
public LongOutDoubleInFunctionVectorValueProcessor(ExprVectorProcessor<double[]> processor, int maxVectorSize) public LongOutDoubleInFunctionVectorValueProcessor(ExprVectorProcessor<double[]> processor, int maxVectorSize)
{ {
super(CastToTypeVectorProcessor.cast(processor, ExpressionType.DOUBLE), maxVectorSize, new long[maxVectorSize]); super(CastToTypeVectorProcessor.cast(processor, ExpressionType.DOUBLE), maxVectorSize);
} }
public abstract long apply(double input); public abstract long apply(double input);
@ -44,10 +45,4 @@ public abstract class LongOutDoubleInFunctionVectorValueProcessor extends Univar
{ {
outValues[i] = apply(input[i]); outValues[i] = apply(input[i]);
} }
@Override
final ExprEvalVector<long[]> asEval()
{
return new ExprEvalLongVector(outValues, outNulls);
}
} }

View File

@ -22,10 +22,10 @@ package org.apache.druid.math.expr.vector;
import org.apache.druid.math.expr.ExpressionType; import org.apache.druid.math.expr.ExpressionType;
/** /**
* specialized {@link BivariateFunctionVectorValueProcessor} for processing (double[], long[]) -> long[] * specialized {@link BivariateLongFunctionVectorValueProcessor} for processing (double[], long[]) -> long[]
*/ */
public abstract class LongOutDoubleLongInFunctionVectorValueProcessor public abstract class LongOutDoubleLongInFunctionVectorValueProcessor
extends BivariateFunctionVectorValueProcessor<double[], long[], long[]> extends BivariateLongFunctionVectorValueProcessor<double[], long[]>
{ {
public LongOutDoubleLongInFunctionVectorValueProcessor( public LongOutDoubleLongInFunctionVectorValueProcessor(
ExprVectorProcessor<double[]> left, ExprVectorProcessor<double[]> left,
@ -36,8 +36,7 @@ public abstract class LongOutDoubleLongInFunctionVectorValueProcessor
super( super(
CastToTypeVectorProcessor.cast(left, ExpressionType.DOUBLE), CastToTypeVectorProcessor.cast(left, ExpressionType.DOUBLE),
CastToTypeVectorProcessor.cast(right, ExpressionType.LONG), CastToTypeVectorProcessor.cast(right, ExpressionType.LONG),
maxVectorSize, maxVectorSize
new long[maxVectorSize]
); );
} }
@ -54,10 +53,4 @@ public abstract class LongOutDoubleLongInFunctionVectorValueProcessor
{ {
outValues[i] = apply(leftInput[i], rightInput[i]); outValues[i] = apply(leftInput[i], rightInput[i]);
} }
@Override
final ExprEvalVector<long[]> asEval()
{
return new ExprEvalLongVector(outValues, outNulls);
}
} }

View File

@ -22,10 +22,10 @@ package org.apache.druid.math.expr.vector;
import org.apache.druid.math.expr.ExpressionType; import org.apache.druid.math.expr.ExpressionType;
/** /**
* specialized {@link BivariateFunctionVectorValueProcessor} for processing (double[], double[]) -> long[] * specialized {@link BivariateLongFunctionVectorValueProcessor} for processing (double[], double[]) -> long[]
*/ */
public abstract class LongOutDoublesInFunctionVectorValueProcessor public abstract class LongOutDoublesInFunctionVectorValueProcessor
extends BivariateFunctionVectorValueProcessor<double[], double[], long[]> extends BivariateLongFunctionVectorValueProcessor<double[], double[]>
{ {
public LongOutDoublesInFunctionVectorValueProcessor( public LongOutDoublesInFunctionVectorValueProcessor(
ExprVectorProcessor<double[]> left, ExprVectorProcessor<double[]> left,
@ -36,8 +36,7 @@ public abstract class LongOutDoublesInFunctionVectorValueProcessor
super( super(
CastToTypeVectorProcessor.cast(left, ExpressionType.DOUBLE), CastToTypeVectorProcessor.cast(left, ExpressionType.DOUBLE),
CastToTypeVectorProcessor.cast(right, ExpressionType.DOUBLE), CastToTypeVectorProcessor.cast(right, ExpressionType.DOUBLE),
maxVectorSize, maxVectorSize
new long[maxVectorSize]
); );
} }
@ -54,10 +53,4 @@ public abstract class LongOutDoublesInFunctionVectorValueProcessor
{ {
outValues[i] = apply(leftInput[i], rightInput[i]); outValues[i] = apply(leftInput[i], rightInput[i]);
} }
@Override
final ExprEvalVector<long[]> asEval()
{
return new ExprEvalLongVector(outValues, outNulls);
}
} }

View File

@ -22,10 +22,10 @@ package org.apache.druid.math.expr.vector;
import org.apache.druid.math.expr.ExpressionType; import org.apache.druid.math.expr.ExpressionType;
/** /**
* specialized {@link BivariateFunctionVectorValueProcessor} for processing (long[], double[]) -> long[] * specialized {@link BivariateLongFunctionVectorValueProcessor} for processing (long[], double[]) -> long[]
*/ */
public abstract class LongOutLongDoubleInFunctionVectorValueProcessor public abstract class LongOutLongDoubleInFunctionVectorValueProcessor
extends BivariateFunctionVectorValueProcessor<long[], double[], long[]> extends BivariateLongFunctionVectorValueProcessor<long[], double[]>
{ {
public LongOutLongDoubleInFunctionVectorValueProcessor( public LongOutLongDoubleInFunctionVectorValueProcessor(
ExprVectorProcessor<long[]> left, ExprVectorProcessor<long[]> left,
@ -36,8 +36,7 @@ public abstract class LongOutLongDoubleInFunctionVectorValueProcessor
super( super(
CastToTypeVectorProcessor.cast(left, ExpressionType.LONG), CastToTypeVectorProcessor.cast(left, ExpressionType.LONG),
CastToTypeVectorProcessor.cast(right, ExpressionType.DOUBLE), CastToTypeVectorProcessor.cast(right, ExpressionType.DOUBLE),
maxVectorSize, maxVectorSize
new long[maxVectorSize]
); );
} }
@ -54,10 +53,4 @@ public abstract class LongOutLongDoubleInFunctionVectorValueProcessor
{ {
outValues[i] = apply(leftInput[i], rightInput[i]); outValues[i] = apply(leftInput[i], rightInput[i]);
} }
@Override
final ExprEvalVector<long[]> asEval()
{
return new ExprEvalLongVector(outValues, outNulls);
}
} }

View File

@ -22,13 +22,14 @@ package org.apache.druid.math.expr.vector;
import org.apache.druid.math.expr.ExpressionType; import org.apache.druid.math.expr.ExpressionType;
/** /**
* specialized {@link UnivariateFunctionVectorValueProcessor} for processing (long[]) -> long[] * specialized {@link UnivariateLongFunctionVectorValueProcessor} for processing (long[]) -> long[]
*/ */
public abstract class LongOutLongInFunctionVectorValueProcessor extends UnivariateFunctionVectorValueProcessor<long[], long[]> public abstract class LongOutLongInFunctionVectorValueProcessor
extends UnivariateLongFunctionVectorValueProcessor<long[]>
{ {
public LongOutLongInFunctionVectorValueProcessor(ExprVectorProcessor<long[]> processor, int maxVectorSize) public LongOutLongInFunctionVectorValueProcessor(ExprVectorProcessor<long[]> processor, int maxVectorSize)
{ {
super(CastToTypeVectorProcessor.cast(processor, ExpressionType.LONG), maxVectorSize, new long[maxVectorSize]); super(CastToTypeVectorProcessor.cast(processor, ExpressionType.LONG), maxVectorSize);
} }
public abstract long apply(long input); public abstract long apply(long input);
@ -44,10 +45,4 @@ public abstract class LongOutLongInFunctionVectorValueProcessor extends Univaria
{ {
outValues[i] = apply(input[i]); outValues[i] = apply(input[i]);
} }
@Override
final ExprEvalVector<long[]> asEval()
{
return new ExprEvalLongVector(outValues, outNulls);
}
} }

View File

@ -22,10 +22,10 @@ package org.apache.druid.math.expr.vector;
import org.apache.druid.math.expr.ExpressionType; import org.apache.druid.math.expr.ExpressionType;
/** /**
* specialized {@link BivariateFunctionVectorValueProcessor} for processing (long[], long[]) -> long[] * specialized {@link BivariateLongFunctionVectorValueProcessor} for processing (long[], long[]) -> long[]
*/ */
public abstract class LongOutLongsInFunctionVectorValueProcessor public abstract class LongOutLongsInFunctionVectorValueProcessor
extends BivariateFunctionVectorValueProcessor<long[], long[], long[]> extends BivariateLongFunctionVectorValueProcessor<long[], long[]>
{ {
public LongOutLongsInFunctionVectorValueProcessor( public LongOutLongsInFunctionVectorValueProcessor(
ExprVectorProcessor<long[]> left, ExprVectorProcessor<long[]> left,
@ -36,8 +36,7 @@ public abstract class LongOutLongsInFunctionVectorValueProcessor
super( super(
CastToTypeVectorProcessor.cast(left, ExpressionType.LONG), CastToTypeVectorProcessor.cast(left, ExpressionType.LONG),
CastToTypeVectorProcessor.cast(right, ExpressionType.LONG), CastToTypeVectorProcessor.cast(right, ExpressionType.LONG),
maxVectorSize, maxVectorSize
new long[maxVectorSize]
); );
} }
@ -54,10 +53,4 @@ public abstract class LongOutLongsInFunctionVectorValueProcessor
{ {
outValues[i] = apply(leftInput[i], rightInput[i]); outValues[i] = apply(leftInput[i], rightInput[i]);
} }
@Override
final ExprEvalVector<long[]> asEval()
{
return new ExprEvalLongVector(outValues, outNulls);
}
} }

View File

@ -0,0 +1,85 @@
/*
* 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;
/**
* common machinery for processing single input operators and functions, which should always treat null input as null
* output, and are backed by a primitive value instead of an object value (and need to use the null vector instead of
* checking the vector itself for nulls)
*
* this one is specialized for producing double[], see {@link UnivariateLongFunctionVectorValueProcessor} for
* long[] primitives.
*/
public abstract class UnivariateDoubleFunctionVectorValueProcessor<TInput> implements ExprVectorProcessor<double[]>
{
final ExprVectorProcessor<TInput> processor;
final int maxVectorSize;
final boolean[] outNulls;
final double[] outValues;
public UnivariateDoubleFunctionVectorValueProcessor(
ExprVectorProcessor<TInput> processor,
int maxVectorSize
)
{
this.processor = processor;
this.maxVectorSize = maxVectorSize;
this.outNulls = new boolean[maxVectorSize];
this.outValues = new double[maxVectorSize];
}
@Override
public final ExprEvalVector<double[]> evalVector(Expr.VectorInputBinding bindings)
{
final ExprEvalVector<TInput> lhs = processor.evalVector(bindings);
final int currentSize = bindings.getCurrentVectorSize();
final boolean[] inputNulls = lhs.getNullVector();
final boolean hasNulls = inputNulls != null;
final TInput input = lhs.values();
if (hasNulls) {
for (int i = 0; i < currentSize; i++) {
outNulls[i] = inputNulls[i];
if (!outNulls[i]) {
processIndex(input, i);
} else {
outValues[i] = 0.0;
}
}
} else {
for (int i = 0; i < currentSize; i++) {
outNulls[i] = false;
processIndex(input, i);
}
}
return asEval();
}
abstract void processIndex(TInput input, int i);
final ExprEvalVector<double[]> asEval()
{
return new ExprEvalDoubleVector(outValues, outNulls);
}
}

View File

@ -25,28 +25,30 @@ import org.apache.druid.math.expr.Expr;
* common machinery for processing single input operators and functions, which should always treat null input as null * common machinery for processing single input operators and functions, which should always treat null input as null
* output, and are backed by a primitive value instead of an object value (and need to use the null vector instead of * output, and are backed by a primitive value instead of an object value (and need to use the null vector instead of
* checking the vector itself for nulls) * checking the vector itself for nulls)
*
* this one is specialized for producing long[], see {@link UnivariateDoubleFunctionVectorValueProcessor} for
* double[] primitives.
*/ */
public abstract class UnivariateFunctionVectorValueProcessor<TInput, TOutput> implements ExprVectorProcessor<TOutput> public abstract class UnivariateLongFunctionVectorValueProcessor<TInput> implements ExprVectorProcessor<long[]>
{ {
final ExprVectorProcessor<TInput> processor; final ExprVectorProcessor<TInput> processor;
final int maxVectorSize; final int maxVectorSize;
final boolean[] outNulls; final boolean[] outNulls;
final TOutput outValues; final long[] outValues;
public UnivariateFunctionVectorValueProcessor( public UnivariateLongFunctionVectorValueProcessor(
ExprVectorProcessor<TInput> processor, ExprVectorProcessor<TInput> processor,
int maxVectorSize, int maxVectorSize
TOutput outValues
) )
{ {
this.processor = processor; this.processor = processor;
this.maxVectorSize = maxVectorSize; this.maxVectorSize = maxVectorSize;
this.outNulls = new boolean[maxVectorSize]; this.outNulls = new boolean[maxVectorSize];
this.outValues = outValues; this.outValues = new long[maxVectorSize];
} }
@Override @Override
public final ExprEvalVector<TOutput> evalVector(Expr.VectorInputBinding bindings) public final ExprEvalVector<long[]> evalVector(Expr.VectorInputBinding bindings)
{ {
final ExprEvalVector<TInput> lhs = processor.evalVector(bindings); final ExprEvalVector<TInput> lhs = processor.evalVector(bindings);
@ -61,6 +63,8 @@ public abstract class UnivariateFunctionVectorValueProcessor<TInput, TOutput> im
outNulls[i] = inputNulls[i]; outNulls[i] = inputNulls[i];
if (!outNulls[i]) { if (!outNulls[i]) {
processIndex(input, i); processIndex(input, i);
} else {
outValues[i] = 0L;
} }
} }
} else { } else {
@ -74,5 +78,8 @@ public abstract class UnivariateFunctionVectorValueProcessor<TInput, TOutput> im
abstract void processIndex(TInput input, int i); abstract void processIndex(TInput input, int i);
abstract ExprEvalVector<TOutput> asEval(); final ExprEvalVector<long[]> asEval()
{
return new ExprEvalLongVector(outValues, outNulls);
}
} }

View File

@ -158,9 +158,9 @@ public class VectorMathProcessors
} }
} else if (leftType.is(ExprType.STRING)) { } else if (leftType.is(ExprType.STRING)) {
if (Types.is(rightType, ExprType.LONG)) { if (Types.is(rightType, ExprType.LONG)) {
processor = longOutLongsInProcessor.get(); processor = doubleOutDoubleLongInProcessor.get();
} else if (Types.is(rightType, ExprType.DOUBLE)) { } else if (Types.is(rightType, ExprType.DOUBLE)) {
processor = doubleOutLongDoubleInProcessor.get(); processor = doubleOutDoublesInProcessor.get();
} }
} }
if (processor == null) { if (processor == null) {
@ -696,7 +696,7 @@ public class VectorMathProcessors
{ {
final ExpressionType leftType = left.getOutputType(inspector); final ExpressionType leftType = left.getOutputType(inspector);
final ExpressionType rightType = right.getOutputType(inspector); final ExpressionType rightType = right.getOutputType(inspector);
BivariateFunctionVectorValueProcessor<?, ?, ?> processor = null; ExprVectorProcessor<?> processor = null;
if ((Types.is(leftType, ExprType.LONG) && Types.isNullOr(rightType, ExprType.LONG)) || if ((Types.is(leftType, ExprType.LONG) && Types.isNullOr(rightType, ExprType.LONG)) ||
(leftType == null && Types.is(rightType, ExprType.LONG))) { (leftType == null && Types.is(rightType, ExprType.LONG))) {
processor = new DoubleOutLongsInFunctionVectorValueProcessor( processor = new DoubleOutLongsInFunctionVectorValueProcessor(

View File

@ -88,7 +88,7 @@ public class VectorExprSanityTest extends InitializedNullHandlingTest
@Test @Test
public void testBinaryMathOperators() public void testBinaryMathOperators()
{ {
final String[] columns = new String[]{"d1", "d2", "l1", "l2", "1", "1.0", "nonexistent", "null"}; final String[] columns = new String[]{"d1", "d2", "l1", "l2", "1", "1.0", "nonexistent", "null", "s1"};
final String[] columns2 = new String[]{"d1", "d2", "l1", "l2", "1", "1.0"}; final String[] columns2 = new String[]{"d1", "d2", "l1", "l2", "1", "1.0"};
final String[][] templateInputs = makeTemplateArgs(columns, columns2); final String[][] templateInputs = makeTemplateArgs(columns, columns2);
final String[] templates = final String[] templates =
@ -305,7 +305,7 @@ public class VectorExprSanityTest extends InitializedNullHandlingTest
ExprEvalVector<?> vectorEval = parsed.buildVectorized(bindings.rhs).evalVector(bindings.rhs); ExprEvalVector<?> vectorEval = parsed.buildVectorized(bindings.rhs).evalVector(bindings.rhs);
// 'null' expressions can have an output type of null, but still evaluate in default mode, so skip type checks // 'null' expressions can have an output type of null, but still evaluate in default mode, so skip type checks
if (outputType != null) { if (outputType != null) {
Assert.assertEquals(outputType, vectorEval.getType()); Assert.assertEquals(expr, outputType, vectorEval.getType());
} }
for (int i = 0; i < VECTOR_SIZE; i++) { for (int i = 0; i < VECTOR_SIZE; i++) {
ExprEval<?> eval = parsed.eval(bindings.lhs[i]); ExprEval<?> eval = parsed.eval(bindings.lhs[i]);

View File

@ -247,7 +247,8 @@ public class VirtualColumns implements Cacheable
public boolean canVectorize(ColumnInspector columnInspector) public boolean canVectorize(ColumnInspector columnInspector)
{ {
return virtualColumns.stream().allMatch(virtualColumn -> virtualColumn.canVectorize(columnInspector)); final ColumnInspector inspector = wrapInspector(columnInspector);
return virtualColumns.stream().allMatch(virtualColumn -> virtualColumn.canVectorize(inspector));
} }
/** /**

View File

@ -51,6 +51,7 @@ import org.apache.druid.segment.column.ColumnType;
import org.apache.druid.segment.column.ValueType; import org.apache.druid.segment.column.ValueType;
import org.apache.druid.segment.data.IndexedInts; import org.apache.druid.segment.data.IndexedInts;
import org.apache.druid.segment.data.ZeroIndexedInts; import org.apache.druid.segment.data.ZeroIndexedInts;
import org.apache.druid.segment.nested.NestedDataComplexTypeSerde;
import org.apache.druid.testing.InitializedNullHandlingTest; import org.apache.druid.testing.InitializedNullHandlingTest;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Rule; import org.junit.Rule;
@ -471,6 +472,37 @@ public class VirtualColumnsTest extends InitializedNullHandlingTest
Assert.assertTrue(virtualColumns.exists("v2")); Assert.assertTrue(virtualColumns.exists("v2"));
} }
@Test
public void testCompositeVirtualColumnsCapabilitiesHasAccessToOtherVirtualColumns()
{
final ColumnInspector baseInspector = new ColumnInspector()
{
@Nullable
@Override
public ColumnCapabilities getColumnCapabilities(String column)
{
if ("x".equals(column)) {
return ColumnCapabilitiesImpl.createSimpleNumericColumnCapabilities(ColumnType.LONG);
}
if ("n".equals(column)) {
return ColumnCapabilitiesImpl.createDefault().setType(NestedDataComplexTypeSerde.TYPE);
}
return null;
}
};
final NestedFieldVirtualColumn v0 = new NestedFieldVirtualColumn("n", "$.x", "v0", ColumnType.STRING);
final NestedFieldVirtualColumn v1 = new NestedFieldVirtualColumn("n", "$.y", "v1", ColumnType.LONG);
final ExpressionVirtualColumn expr1 = new ExpressionVirtualColumn("v2", "v0 * v1", null, TestExprMacroTable.INSTANCE);
final ExpressionVirtualColumn expr2 = new ExpressionVirtualColumn("v3", "v0 * x", null, TestExprMacroTable.INSTANCE);
final VirtualColumns virtualColumns = VirtualColumns.create(ImmutableList.of(v0, v1, expr1, expr2));
Assert.assertEquals(ColumnType.STRING, virtualColumns.getColumnCapabilities(baseInspector, "v0").toColumnType());
Assert.assertEquals(ColumnType.LONG, virtualColumns.getColumnCapabilities(baseInspector, "v1").toColumnType());
Assert.assertEquals(ColumnType.DOUBLE, virtualColumns.getColumnCapabilities(baseInspector, "v2").toColumnType());
Assert.assertEquals(ColumnType.DOUBLE, virtualColumns.getColumnCapabilities(baseInspector, "v3").toColumnType());
Assert.assertTrue(virtualColumns.canVectorize(baseInspector));
}
private VirtualColumns makeVirtualColumns() private VirtualColumns makeVirtualColumns()
{ {
final ExpressionVirtualColumn expr = new ExpressionVirtualColumn( final ExpressionVirtualColumn expr = new ExpressionVirtualColumn(

View File

@ -276,7 +276,8 @@ public class NestedDataOperatorConversions
call.operand(0), call.operand(0),
call.operand(1) call.operand(1)
); );
} else if (SqlTypeName.APPROX_TYPES.contains(sqlType.getSqlTypeName())) { } else if (SqlTypeName.DECIMAL.equals(sqlType.getSqlTypeName()) ||
SqlTypeName.APPROX_TYPES.contains(sqlType.getSqlTypeName())) {
rewrite = JsonValueDoubleOperatorConversion.FUNCTION.createCall( rewrite = JsonValueDoubleOperatorConversion.FUNCTION.createCall(
SqlParserPos.ZERO, SqlParserPos.ZERO,
call.operand(0), call.operand(0),

View File

@ -1951,6 +1951,35 @@ public class CalciteNestedDataQueryTest extends BaseCalciteQueryTest
); );
} }
@Test
public void testReturningAndSumPathWithMaths()
{
testQuery(
"SELECT "
+ "SUM(JSON_VALUE(nest, '$.x' RETURNING BIGINT) / 100) "
+ "FROM druid.nested",
ImmutableList.of(
Druids.newTimeseriesQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.granularity(Granularities.ALL)
.virtualColumns(
expressionVirtualColumn("v0", "(\"v1\" / 100)", ColumnType.LONG),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.LONG)
)
.aggregators(aggregators(new LongSumAggregatorFactory("a0", "v0")))
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{4L}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.LONG)
.build()
);
}
@Test @Test
public void testReturningAndSumPathDouble() public void testReturningAndSumPathDouble()
{ {
@ -2003,6 +2032,35 @@ public class CalciteNestedDataQueryTest extends BaseCalciteQueryTest
); );
} }
@Test
public void testReturningAndSumPathDecimalWithMaths()
{
testQuery(
"SELECT "
+ "SUM(JSON_VALUE(nest, '$.x' RETURNING DECIMAL) / 100.0) "
+ "FROM druid.nested",
ImmutableList.of(
Druids.newTimeseriesQueryBuilder()
.dataSource(DATA_SOURCE)
.intervals(querySegmentSpec(Filtration.eternity()))
.granularity(Granularities.ALL)
.virtualColumns(
expressionVirtualColumn("v0", "(\"v1\" / 100.0)", ColumnType.DOUBLE),
new NestedFieldVirtualColumn("nest", "$.x", "v1", ColumnType.DOUBLE)
)
.aggregators(aggregators(new DoubleSumAggregatorFactory("a0", "v0")))
.context(QUERY_CONTEXT_DEFAULT)
.build()
),
ImmutableList.of(
new Object[]{4.0}
),
RowSignature.builder()
.add("EXPR$0", ColumnType.DOUBLE)
.build()
);
}
@Test @Test
public void testReturningAndSumPathStrings() public void testReturningAndSumPathStrings()
{ {