use of org.apache.druid.math.expr.ExpressionType in project druid by druid-io.
the class Projection method postAggregatorDirectColumnIsOk.
/**
* Returns true if a post-aggregation "expression" can be realized as a direct field access. This is true if it's
* a direct column access that doesn't require an implicit cast.
*
* @param aggregateRowSignature signature of the aggregation
* @param expression post-aggregation expression
* @param rexNode RexNode for the post-aggregation expression
*
* @return yes or no
*/
private static boolean postAggregatorDirectColumnIsOk(final RowSignature aggregateRowSignature, final DruidExpression expression, final RexNode rexNode) {
if (!expression.isDirectColumnAccess()) {
return false;
}
// We don't really have a way to cast complex type. So might as well not do anything and return.
final ColumnType columnValueType = aggregateRowSignature.getColumnType(expression.getDirectColumn()).orElseThrow(() -> new ISE("Encountered null type for column[%s]", expression.getDirectColumn()));
if (columnValueType.is(ValueType.COMPLEX)) {
return true;
}
// Check if a cast is necessary.
final ExpressionType toExprType = ExpressionType.fromColumnTypeStrict(columnValueType);
final ExpressionType fromExprType = ExpressionType.fromColumnTypeStrict(Calcites.getColumnTypeForRelDataType(rexNode.getType()));
return toExprType.equals(fromExprType);
}
use of org.apache.druid.math.expr.ExpressionType in project druid by druid-io.
the class ExpressionVectorSelectorsTest method sanityTestVectorizedExpressionSelectors.
public static void sanityTestVectorizedExpressionSelectors(String expression, @Nullable ExpressionType outputType, QueryableIndex index, Closer closer, int rowsPerSegment) {
final List<Object> results = new ArrayList<>(rowsPerSegment);
final VirtualColumns virtualColumns = VirtualColumns.create(ImmutableList.of(new ExpressionVirtualColumn("v", expression, ExpressionType.toColumnType(outputType), TestExprMacroTable.INSTANCE)));
final QueryableIndexStorageAdapter storageAdapter = new QueryableIndexStorageAdapter(index);
VectorCursor cursor = storageAdapter.makeVectorCursor(null, index.getDataInterval(), virtualColumns, false, 512, null);
ColumnCapabilities capabilities = virtualColumns.getColumnCapabilities(storageAdapter, "v");
int rowCount = 0;
if (capabilities.isDictionaryEncoded().isTrue()) {
SingleValueDimensionVectorSelector selector = cursor.getColumnSelectorFactory().makeSingleValueDimensionSelector(DefaultDimensionSpec.of("v"));
while (!cursor.isDone()) {
int[] row = selector.getRowVector();
for (int i = 0; i < selector.getCurrentVectorSize(); i++, rowCount++) {
results.add(selector.lookupName(row[i]));
}
cursor.advance();
}
} else {
VectorValueSelector selector = null;
VectorObjectSelector objectSelector = null;
if (outputType != null && outputType.isNumeric()) {
selector = cursor.getColumnSelectorFactory().makeValueSelector("v");
} else {
objectSelector = cursor.getColumnSelectorFactory().makeObjectSelector("v");
}
while (!cursor.isDone()) {
boolean[] nulls;
switch(outputType.getType()) {
case LONG:
nulls = selector.getNullVector();
long[] longs = selector.getLongVector();
for (int i = 0; i < selector.getCurrentVectorSize(); i++, rowCount++) {
results.add(nulls != null && nulls[i] ? null : longs[i]);
}
break;
case DOUBLE:
// special case to test floats just to get coverage on getFloatVector
if ("float2".equals(expression)) {
nulls = selector.getNullVector();
float[] floats = selector.getFloatVector();
for (int i = 0; i < selector.getCurrentVectorSize(); i++, rowCount++) {
results.add(nulls != null && nulls[i] ? null : (double) floats[i]);
}
} else {
nulls = selector.getNullVector();
double[] doubles = selector.getDoubleVector();
for (int i = 0; i < selector.getCurrentVectorSize(); i++, rowCount++) {
results.add(nulls != null && nulls[i] ? null : doubles[i]);
}
}
break;
case STRING:
Object[] objects = objectSelector.getObjectVector();
for (int i = 0; i < objectSelector.getCurrentVectorSize(); i++, rowCount++) {
results.add(objects[i]);
}
break;
}
cursor.advance();
}
}
closer.register(cursor);
Sequence<Cursor> cursors = new QueryableIndexStorageAdapter(index).makeCursors(null, index.getDataInterval(), virtualColumns, Granularities.ALL, false, null);
int rowCountCursor = cursors.map(nonVectorized -> {
final ColumnValueSelector nonSelector = nonVectorized.getColumnSelectorFactory().makeColumnValueSelector("v");
int rows = 0;
while (!nonVectorized.isDone()) {
Assert.assertEquals(StringUtils.format("Failed at row %s", rows), nonSelector.getObject(), results.get(rows));
rows++;
nonVectorized.advance();
}
return rows;
}).accumulate(0, (acc, in) -> acc + in);
Assert.assertTrue(rowCountCursor > 0);
Assert.assertEquals(rowCountCursor, rowCount);
}
use of org.apache.druid.math.expr.ExpressionType in project druid by druid-io.
the class ExpressionFilter method makeVectorMatcher.
@Override
public VectorValueMatcher makeVectorMatcher(VectorColumnSelectorFactory factory) {
final Expr theExpr = expr.get();
DruidPredicateFactory predicateFactory = new DruidPredicateFactory() {
@Override
public Predicate<String> makeStringPredicate() {
return Evals::asBoolean;
}
@Override
public DruidLongPredicate makeLongPredicate() {
return Evals::asBoolean;
}
@Override
public DruidFloatPredicate makeFloatPredicate() {
return Evals::asBoolean;
}
@Override
public DruidDoublePredicate makeDoublePredicate() {
return Evals::asBoolean;
}
// The hashcode and equals are to make SubclassesMustOverrideEqualsAndHashCodeTest stop complaining..
// DruidPredicateFactory currently doesn't really need equals or hashcode since 'toString' method that is actually
// called when testing equality of DimensionPredicateFilter, so it's the truly required method, but that seems
// a bit strange. DimensionPredicateFilter should probably be reworked to use equals from DruidPredicateFactory
// instead of using toString.
@Override
public int hashCode() {
return super.hashCode();
}
@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
};
final ExpressionType outputType = theExpr.getOutputType(factory);
// effectively constant
if (outputType == null) {
// false matcher
if (NullHandling.sqlCompatible()) {
return BooleanVectorValueMatcher.of(factory.getReadableVectorInspector(), false);
}
// or not.
return BooleanVectorValueMatcher.of(factory.getReadableVectorInspector(), theExpr.eval(InputBindings.nilBindings()).asBoolean());
}
// if we got here, we really have to evaluate the expressions to match
switch(outputType.getType()) {
case LONG:
return VectorValueMatcherColumnProcessorFactory.instance().makeLongProcessor(ColumnCapabilitiesImpl.createSimpleNumericColumnCapabilities(ColumnType.LONG), ExpressionVectorSelectors.makeVectorValueSelector(factory, theExpr)).makeMatcher(predicateFactory);
case DOUBLE:
return VectorValueMatcherColumnProcessorFactory.instance().makeDoubleProcessor(ColumnCapabilitiesImpl.createSimpleNumericColumnCapabilities(ColumnType.DOUBLE), ExpressionVectorSelectors.makeVectorValueSelector(factory, theExpr)).makeMatcher(predicateFactory);
case STRING:
return VectorValueMatcherColumnProcessorFactory.instance().makeObjectProcessor(ColumnCapabilitiesImpl.createSimpleSingleValueStringColumnCapabilities(), ExpressionVectorSelectors.makeVectorObjectSelector(factory, theExpr)).makeMatcher(predicateFactory);
default:
throw new UOE("Vectorized expression matchers not implemented for type: [%s]", outputType);
}
}
use of org.apache.druid.math.expr.ExpressionType in project druid by druid-io.
the class VectorProcessors method not.
public static <T> ExprVectorProcessor<T> not(Expr.VectorInputBindingInspector inspector, Expr expr) {
final ExpressionType inputType = expr.getOutputType(inspector);
final int maxVectorSize = inspector.getMaxVectorSize();
ExprVectorProcessor<?> processor = null;
if (Types.is(inputType, ExprType.STRING)) {
processor = new LongOutStringInFunctionVectorProcessor(expr.buildVectorized(inspector), maxVectorSize) {
@Override
public void processIndex(String[] strings, long[] longs, boolean[] outputNulls, int i) {
outputNulls[i] = strings[i] == null;
if (!outputNulls[i]) {
longs[i] = Evals.asLong(!Evals.asBoolean(strings[i]));
}
}
};
} else if (Types.is(inputType, ExprType.LONG)) {
processor = new LongOutLongInFunctionVectorValueProcessor(expr.buildVectorized(inspector), maxVectorSize) {
@Override
public long apply(long input) {
return Evals.asLong(!Evals.asBoolean(input));
}
};
} else if (Types.is(inputType, ExprType.DOUBLE)) {
if (!ExpressionProcessing.useStrictBooleans()) {
processor = new DoubleOutDoubleInFunctionVectorValueProcessor(expr.buildVectorized(inspector), maxVectorSize) {
@Override
public double apply(double input) {
return Evals.asDouble(!Evals.asBoolean(input));
}
};
} else {
processor = new LongOutDoubleInFunctionVectorValueProcessor(expr.buildVectorized(inspector), maxVectorSize) {
@Override
public long apply(double input) {
return Evals.asLong(!Evals.asBoolean(input));
}
};
}
}
if (processor == null) {
throw Exprs.cannotVectorize();
}
return (ExprVectorProcessor<T>) processor;
}
use of org.apache.druid.math.expr.ExpressionType in project druid by druid-io.
the class VectorProcessors method isNotNull.
public static <T> ExprVectorProcessor<T> isNotNull(Expr.VectorInputBindingInspector inspector, Expr expr) {
final ExpressionType type = expr.getOutputType(inspector);
if (type == null) {
return constant(0L, inspector.getMaxVectorSize());
}
final long[] outputValues = new long[inspector.getMaxVectorSize()];
ExprVectorProcessor<?> processor = null;
if (Types.is(type, ExprType.STRING)) {
final ExprVectorProcessor<String[]> input = expr.buildVectorized(inspector);
processor = new ExprVectorProcessor<long[]>() {
@Override
public ExprEvalVector<long[]> evalVector(Expr.VectorInputBinding bindings) {
final ExprEvalVector<String[]> inputEval = input.evalVector(bindings);
final int currentSize = bindings.getCurrentVectorSize();
final String[] values = inputEval.values();
for (int i = 0; i < currentSize; i++) {
if (values[i] == null) {
outputValues[i] = 0L;
} else {
outputValues[i] = 1L;
}
}
return new ExprEvalLongVector(outputValues, null);
}
@Override
public ExpressionType getOutputType() {
return ExpressionType.LONG;
}
};
} else if (Types.is(type, ExprType.LONG)) {
final ExprVectorProcessor<long[]> input = expr.buildVectorized(inspector);
processor = new ExprVectorProcessor<long[]>() {
@Override
public ExprEvalVector<long[]> evalVector(Expr.VectorInputBinding bindings) {
final ExprEvalVector<long[]> inputEval = input.evalVector(bindings);
final int currentSize = bindings.getCurrentVectorSize();
final boolean[] nulls = inputEval.getNullVector();
if (nulls == null) {
Arrays.fill(outputValues, 1L);
} else {
for (int i = 0; i < currentSize; i++) {
if (nulls[i]) {
outputValues[i] = 0L;
} else {
outputValues[i] = 1L;
}
}
}
return new ExprEvalLongVector(outputValues, null);
}
@Override
public ExpressionType getOutputType() {
return ExpressionType.LONG;
}
};
} else if (Types.is(type, ExprType.DOUBLE)) {
final ExprVectorProcessor<double[]> input = expr.buildVectorized(inspector);
processor = new ExprVectorProcessor<long[]>() {
@Override
public ExprEvalVector<long[]> evalVector(Expr.VectorInputBinding bindings) {
final ExprEvalVector<double[]> inputEval = input.evalVector(bindings);
final int currentSize = bindings.getCurrentVectorSize();
final boolean[] nulls = inputEval.getNullVector();
if (nulls == null) {
Arrays.fill(outputValues, 1L);
} else {
for (int i = 0; i < currentSize; i++) {
if (nulls[i]) {
outputValues[i] = 0L;
} else {
outputValues[i] = 1L;
}
}
}
return new ExprEvalLongVector(outputValues, null);
}
@Override
public ExpressionType getOutputType() {
return ExpressionType.LONG;
}
};
}
if (processor == null) {
throw Exprs.cannotVectorize();
}
return (ExprVectorProcessor<T>) processor;
}
Aggregations