This is an automated email from the ASF dual-hosted git repository.
cwylie 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 18937ffee2 split out null value index (#12627)
18937ffee2 is described below
commit 18937ffee210fb230737aac20e48ede9601b8096
Author: Clint Wylie <[email protected]>
AuthorDate: Fri Jun 17 15:29:23 2022 -0700
split out null value index (#12627)
* split out null value index
* gg spotbugs
* fix stuff
---
.../benchmark/query/SqlExpressionBenchmark.java | 11 +-
.../PredicateFilteredDimensionSelector.java | 7 +-
.../apache/druid/segment/column/ColumnBuilder.java | 29 +++++
.../segment/column/LexicographicalRangeIndex.java | 11 +-
.../druid/segment/column/NullValueIndex.java | 28 +++++
.../segment/column/SimpleBitmapColumnIndex.java | 34 +++++
.../segment/column/SimpleImmutableBitmapIndex.java | 48 +++++++
.../column/SimpleImmutableBitmapIterableIndex.java | 44 +++++++
.../apache/druid/segment/filter/BoundFilter.java | 44 ++++++-
.../druid/segment/filter/SelectorFilter.java | 22 +++-
.../DictionaryEncodedStringIndexSupplier.java | 138 +++++++--------------
.../serde/DoubleNumericColumnPartSerdeV2.java | 3 +-
.../serde/FloatNumericColumnPartSerdeV2.java | 3 +-
.../serde/LongNumericColumnPartSerdeV2.java | 3 +-
.../segment/serde/NullValueIndexSupplier.java | 63 ++++++++++
.../segment/virtual/ListFilteredVirtualColumn.java | 108 +++++++++-------
.../druid/segment/filter/BoundFilterTest.java | 21 ++++
.../druid/segment/filter/LikeFilterTest.java | 17 +++
.../druid/segment/filter/SelectorFilterTest.java | 15 ++-
.../ListFilteredVirtualColumnSelectorTest.java | 14 ++-
20 files changed, 504 insertions(+), 159 deletions(-)
diff --git
a/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlExpressionBenchmark.java
b/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlExpressionBenchmark.java
index 395336ff2e..b991b8922a 100644
---
a/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlExpressionBenchmark.java
+++
b/benchmarks/src/test/java/org/apache/druid/benchmark/query/SqlExpressionBenchmark.java
@@ -208,7 +208,10 @@ public class SqlExpressionBenchmark
// 40: LATEST aggregator double
"SELECT LATEST(float3) FROM foo",
// 41: LATEST aggregator double
- "SELECT LATEST(float3), LATEST(long1), LATEST(double4) FROM foo"
+ "SELECT LATEST(float3), LATEST(long1), LATEST(double4) FROM foo",
+ // 42,43: filter numeric nulls
+ "SELECT SUM(long5) FROM foo WHERE long5 IS NOT NULL",
+ "SELECT string2, SUM(long5) FROM foo WHERE long5 IS NOT NULL GROUP BY 1"
);
@Param({"5000000"})
@@ -229,7 +232,7 @@ public class SqlExpressionBenchmark
"4",
"5",
"6",
- // expressions
+ // expressions, etc
"7",
"8",
"9",
@@ -264,7 +267,9 @@ public class SqlExpressionBenchmark
"38",
"39",
"40",
- "41"
+ "41",
+ "42",
+ "43"
})
private String query;
diff --git
a/processing/src/main/java/org/apache/druid/query/dimension/PredicateFilteredDimensionSelector.java
b/processing/src/main/java/org/apache/druid/query/dimension/PredicateFilteredDimensionSelector.java
index 3aaf66d248..cf4e88bbe8 100644
---
a/processing/src/main/java/org/apache/druid/query/dimension/PredicateFilteredDimensionSelector.java
+++
b/processing/src/main/java/org/apache/druid/query/dimension/PredicateFilteredDimensionSelector.java
@@ -64,7 +64,6 @@ final class PredicateFilteredDimensionSelector extends
AbstractDimensionSelector
@Override
public ValueMatcher makeValueMatcher(final String value)
{
- final boolean matchNull = predicate.apply(null);
return new ValueMatcher()
{
@Override
@@ -82,8 +81,8 @@ final class PredicateFilteredDimensionSelector extends
AbstractDimensionSelector
nullRow = false;
}
}
- // null should match empty rows in multi-value columns if predicate
matches null
- return nullRow && value == null && matchNull;
+ // null should match empty rows in multi-value columns
+ return nullRow && value == null;
}
@Override
@@ -98,7 +97,7 @@ final class PredicateFilteredDimensionSelector extends
AbstractDimensionSelector
@Override
public ValueMatcher makeValueMatcher(final Predicate<String>
matcherPredicate)
{
- final boolean matchNull = predicate.apply(null) &&
matcherPredicate.apply(null);
+ final boolean matchNull = matcherPredicate.apply(null);
return new ValueMatcher()
{
@Override
diff --git
a/processing/src/main/java/org/apache/druid/segment/column/ColumnBuilder.java
b/processing/src/main/java/org/apache/druid/segment/column/ColumnBuilder.java
index ff4355d2e7..70f67bc13e 100644
---
a/processing/src/main/java/org/apache/druid/segment/column/ColumnBuilder.java
+++
b/processing/src/main/java/org/apache/druid/segment/column/ColumnBuilder.java
@@ -21,8 +21,11 @@ package org.apache.druid.segment.column;
import com.google.common.base.Preconditions;
import com.google.common.base.Supplier;
+import org.apache.druid.collections.bitmap.ImmutableBitmap;
+import org.apache.druid.java.util.common.ISE;
import org.apache.druid.java.util.common.io.smoosh.SmooshedFileMapper;
import org.apache.druid.segment.serde.NoIndexesColumnIndexSupplier;
+import org.apache.druid.segment.serde.NullValueIndexSupplier;
import javax.annotation.Nullable;
@@ -71,6 +74,7 @@ public class ColumnBuilder
public ColumnBuilder setDictionaryEncodedColumnSupplier(Supplier<? extends
DictionaryEncodedColumn<?>> columnSupplier)
{
+ checkColumnSupplierNotSet();
this.columnSupplier = columnSupplier;
this.capabilitiesBuilder.setDictionaryEncoded(true);
this.capabilitiesBuilder.setDictionaryValuesSorted(true);
@@ -87,12 +91,14 @@ public class ColumnBuilder
public ColumnBuilder setComplexColumnSupplier(Supplier<? extends
ComplexColumn> columnSupplier)
{
+ checkColumnSupplierNotSet();
this.columnSupplier = columnSupplier;
return this;
}
public ColumnBuilder setNumericColumnSupplier(Supplier<? extends
NumericColumn> columnSupplier)
{
+ checkColumnSupplierNotSet();
this.columnSupplier = columnSupplier;
return this;
}
@@ -103,12 +109,20 @@ public class ColumnBuilder
boolean hasSpatial
)
{
+ checkIndexSupplierNotSet();
this.indexSupplier = indexSupplier;
capabilitiesBuilder.setHasBitmapIndexes(hasBitmapIndex);
capabilitiesBuilder.setHasSpatialIndexes(hasSpatial);
return this;
}
+ public ColumnBuilder setNullValueIndexSupplier(ImmutableBitmap
nullValueIndex)
+ {
+ checkIndexSupplierNotSet();
+ this.indexSupplier = new NullValueIndexSupplier(nullValueIndex);
+ return this;
+ }
+
public ColumnBuilder setHasNulls(boolean nullable)
{
this.capabilitiesBuilder.setHasNulls(nullable);
@@ -126,4 +140,19 @@ public class ColumnBuilder
return new SimpleColumnHolder(capabilitiesBuilder, columnSupplier,
indexSupplier);
}
+
+ private void checkColumnSupplierNotSet()
+ {
+ if (columnSupplier != null) {
+ throw new ISE("Column supplier already set!");
+ }
+ }
+
+ private void checkIndexSupplierNotSet()
+ {
+ //noinspection ObjectEquality
+ if (indexSupplier != NoIndexesColumnIndexSupplier.getInstance()) {
+ throw new ISE("Index supplier already set!");
+ }
+ }
}
diff --git
a/processing/src/main/java/org/apache/druid/segment/column/LexicographicalRangeIndex.java
b/processing/src/main/java/org/apache/druid/segment/column/LexicographicalRangeIndex.java
index 9568f671a4..872eadf40d 100644
---
a/processing/src/main/java/org/apache/druid/segment/column/LexicographicalRangeIndex.java
+++
b/processing/src/main/java/org/apache/druid/segment/column/LexicographicalRangeIndex.java
@@ -25,12 +25,15 @@ import javax.annotation.Nullable;
/**
* An optimized column value {@link BitmapColumnIndex} provider for columns
which are stored in 'lexicographical' order,
- * allowing short-circuit processing of string value ranges.
+ * allowing short-circuit processing of string value ranges. This index does
not match null values, union the results
+ * of this index with {@link NullValueIndex} if null values should be
considered part of the value range.
*/
public interface LexicographicalRangeIndex
{
/**
- * Get a {@link BitmapColumnIndex} corresponding to the values supplied in
the specified range.
+ * Get a {@link BitmapColumnIndex} corresponding to the values supplied in
the specified range. If supplied starting
+ * value is null, the range will begin at the first non-null value in the
underlying value dictionary. If the end
+ * value is null, the range will extend to the last value in the underlying
value dictionary.
*/
BitmapColumnIndex forRange(
@Nullable String startValue,
@@ -41,7 +44,9 @@ public interface LexicographicalRangeIndex
/**
* Get a {@link BitmapColumnIndex} corresponding to the values supplied in
the specified range whose dictionary ids
- * also match some predicate, such as to match a prefix.
+ * also match some predicate, such as to match a prefix. If supplied
starting value is null, the range will begin at
+ * the first non-null value in the underlying value dictionary that matches
the predicate. If the end value is null,
+ * the range will extend to the last value in the underlying value
dictionary that matches the predicate.
*
* If the provided {@code} matcher is always true, it's better to use the
other
* {@link #forRange(String, boolean, String, boolean)} method.
diff --git
a/processing/src/main/java/org/apache/druid/segment/column/NullValueIndex.java
b/processing/src/main/java/org/apache/druid/segment/column/NullValueIndex.java
new file mode 100644
index 0000000000..65ab439b56
--- /dev/null
+++
b/processing/src/main/java/org/apache/druid/segment/column/NullValueIndex.java
@@ -0,0 +1,28 @@
+/*
+ * 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.segment.column;
+
+/**
+ * Provides index for all null rows in a column, to use with IS/IS NOT NULL
filters
+ */
+public interface NullValueIndex
+{
+ BitmapColumnIndex forNull();
+}
diff --git
a/processing/src/main/java/org/apache/druid/segment/column/SimpleBitmapColumnIndex.java
b/processing/src/main/java/org/apache/druid/segment/column/SimpleBitmapColumnIndex.java
new file mode 100644
index 0000000000..9f494d0cd2
--- /dev/null
+++
b/processing/src/main/java/org/apache/druid/segment/column/SimpleBitmapColumnIndex.java
@@ -0,0 +1,34 @@
+/*
+ * 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.segment.column;
+
+/**
+ * {@link BitmapColumnIndex} with Druids "default" {@link
ColumnIndexCapabilities}.
+ */
+public abstract class SimpleBitmapColumnIndex implements BitmapColumnIndex
+{
+ public static final ColumnIndexCapabilities CAPABILITIES = new
SimpleColumnIndexCapabilities(true, true);
+
+ @Override
+ public ColumnIndexCapabilities getIndexCapabilities()
+ {
+ return CAPABILITIES;
+ }
+}
diff --git
a/processing/src/main/java/org/apache/druid/segment/column/SimpleImmutableBitmapIndex.java
b/processing/src/main/java/org/apache/druid/segment/column/SimpleImmutableBitmapIndex.java
new file mode 100644
index 0000000000..411e79e576
--- /dev/null
+++
b/processing/src/main/java/org/apache/druid/segment/column/SimpleImmutableBitmapIndex.java
@@ -0,0 +1,48 @@
+/*
+ * 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.segment.column;
+
+import org.apache.druid.collections.bitmap.ImmutableBitmap;
+import org.apache.druid.query.BitmapResultFactory;
+
+/**
+ * {@link SimpleBitmapColumnIndex} which wraps a single {@link ImmutableBitmap}
+ */
+public final class SimpleImmutableBitmapIndex extends SimpleBitmapColumnIndex
+{
+ private final ImmutableBitmap bitmap;
+
+ public SimpleImmutableBitmapIndex(ImmutableBitmap bitmap)
+ {
+ this.bitmap = bitmap;
+ }
+
+ @Override
+ public double estimateSelectivity(int totalRows)
+ {
+ return Math.min(1, (double) bitmap.size() / totalRows);
+ }
+
+ @Override
+ public <T> T computeBitmapResult(BitmapResultFactory<T> bitmapResultFactory)
+ {
+ return bitmapResultFactory.wrapDimensionValue(bitmap);
+ }
+}
diff --git
a/processing/src/main/java/org/apache/druid/segment/column/SimpleImmutableBitmapIterableIndex.java
b/processing/src/main/java/org/apache/druid/segment/column/SimpleImmutableBitmapIterableIndex.java
new file mode 100644
index 0000000000..67587725f7
--- /dev/null
+++
b/processing/src/main/java/org/apache/druid/segment/column/SimpleImmutableBitmapIterableIndex.java
@@ -0,0 +1,44 @@
+/*
+ * 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.segment.column;
+
+import org.apache.druid.collections.bitmap.ImmutableBitmap;
+import org.apache.druid.query.BitmapResultFactory;
+import org.apache.druid.segment.filter.Filters;
+
+/**
+ * {@link SimpleBitmapColumnIndex} for anything which can compute an {@link
Iterable<ImmutableBitmap>} in some manner
+ */
+public abstract class SimpleImmutableBitmapIterableIndex extends
SimpleBitmapColumnIndex
+{
+ @Override
+ public double estimateSelectivity(int totalRows)
+ {
+ return Filters.estimateSelectivity(getBitmapIterable().iterator(),
totalRows);
+ }
+
+ @Override
+ public <T> T computeBitmapResult(BitmapResultFactory<T> bitmapResultFactory)
+ {
+ return bitmapResultFactory.unionDimensionValueBitmaps(getBitmapIterable());
+ }
+
+ protected abstract Iterable<ImmutableBitmap> getBitmapIterable();
+}
diff --git
a/processing/src/main/java/org/apache/druid/segment/filter/BoundFilter.java
b/processing/src/main/java/org/apache/druid/segment/filter/BoundFilter.java
index d5bc31d522..0c00d31086 100644
--- a/processing/src/main/java/org/apache/druid/segment/filter/BoundFilter.java
+++ b/processing/src/main/java/org/apache/druid/segment/filter/BoundFilter.java
@@ -22,8 +22,10 @@ package org.apache.druid.segment.filter;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
import org.apache.druid.common.config.NullHandling;
import org.apache.druid.java.util.common.IAE;
+import org.apache.druid.query.BitmapResultFactory;
import org.apache.druid.query.extraction.ExtractionFn;
import org.apache.druid.query.filter.BoundDimFilter;
import org.apache.druid.query.filter.ColumnIndexSelector;
@@ -42,8 +44,10 @@ import org.apache.druid.segment.ColumnProcessors;
import org.apache.druid.segment.ColumnSelector;
import org.apache.druid.segment.ColumnSelectorFactory;
import org.apache.druid.segment.column.BitmapColumnIndex;
+import org.apache.druid.segment.column.ColumnIndexCapabilities;
import org.apache.druid.segment.column.ColumnIndexSupplier;
import org.apache.druid.segment.column.LexicographicalRangeIndex;
+import org.apache.druid.segment.column.NullValueIndex;
import org.apache.druid.segment.vector.VectorColumnSelectorFactory;
import javax.annotation.Nullable;
@@ -81,12 +85,50 @@ public class BoundFilter implements Filter
// column
return null;
}
- return rangeIndex.forRange(
+ final BitmapColumnIndex rangeBitmaps = rangeIndex.forRange(
boundDimFilter.getLower(),
boundDimFilter.isLowerStrict(),
boundDimFilter.getUpper(),
boundDimFilter.isUpperStrict()
);
+ // preserve sad backwards compatible behavior where bound filter matches
'null' if the lower bound is not set
+ if (boundDimFilter.hasLowerBound() &&
!NullHandling.isNullOrEquivalent(boundDimFilter.getLower())) {
+ return rangeBitmaps;
+ } else {
+ final NullValueIndex nulls = indexSupplier.as(NullValueIndex.class);
+ if (nulls == null) {
+ return null;
+ }
+ final BitmapColumnIndex nullBitmap = nulls.forNull();
+ return new BitmapColumnIndex()
+ {
+ @Override
+ public ColumnIndexCapabilities getIndexCapabilities()
+ {
+ return
rangeBitmaps.getIndexCapabilities().merge(nullBitmap.getIndexCapabilities());
+ }
+
+ @Override
+ public double estimateSelectivity(int totalRows)
+ {
+ return Math.min(
+ 1.0,
+ rangeBitmaps.estimateSelectivity(totalRows) +
nullBitmap.estimateSelectivity(totalRows)
+ );
+ }
+
+ @Override
+ public <T> T computeBitmapResult(BitmapResultFactory<T>
bitmapResultFactory)
+ {
+ return bitmapResultFactory.union(
+ ImmutableList.of(
+ rangeBitmaps.computeBitmapResult(bitmapResultFactory),
+ nullBitmap.computeBitmapResult(bitmapResultFactory)
+ )
+ );
+ }
+ };
+ }
} else {
return Filters.makePredicateIndex(boundDimFilter.getDimension(),
selector, getPredicateFactory());
}
diff --git
a/processing/src/main/java/org/apache/druid/segment/filter/SelectorFilter.java
b/processing/src/main/java/org/apache/druid/segment/filter/SelectorFilter.java
index 03c16309a9..036059d95c 100644
---
a/processing/src/main/java/org/apache/druid/segment/filter/SelectorFilter.java
+++
b/processing/src/main/java/org/apache/druid/segment/filter/SelectorFilter.java
@@ -35,6 +35,7 @@ import org.apache.druid.segment.ColumnSelector;
import org.apache.druid.segment.ColumnSelectorFactory;
import org.apache.druid.segment.column.BitmapColumnIndex;
import org.apache.druid.segment.column.ColumnIndexSupplier;
+import org.apache.druid.segment.column.NullValueIndex;
import org.apache.druid.segment.column.StringValueSetIndex;
import org.apache.druid.segment.vector.VectorColumnSelectorFactory;
@@ -83,16 +84,25 @@ public class SelectorFilter implements Filter
if (!Filters.checkFilterTuningUseIndex(dimension, selector, filterTuning))
{
return null;
}
+ final boolean isNull = NullHandling.isNullOrEquivalent(value);
final ColumnIndexSupplier indexSupplier =
selector.getIndexSupplier(dimension);
if (indexSupplier == null) {
- return Filters.makeNullIndex(NullHandling.isNullOrEquivalent(value),
selector);
+ return Filters.makeNullIndex(isNull, selector);
}
- final StringValueSetIndex valueSetIndex =
indexSupplier.as(StringValueSetIndex.class);
- if (valueSetIndex == null) {
- // column exists, but has no index
- return null;
+ if (isNull) {
+ final NullValueIndex nullValueIndex =
indexSupplier.as(NullValueIndex.class);
+ if (nullValueIndex == null) {
+ return null;
+ }
+ return nullValueIndex.forNull();
+ } else {
+ final StringValueSetIndex valueSetIndex =
indexSupplier.as(StringValueSetIndex.class);
+ if (valueSetIndex == null) {
+ // column exists, but has no index
+ return null;
+ }
+ return valueSetIndex.forValue(value);
}
- return valueSetIndex.forValue(value);
}
@Override
diff --git
a/processing/src/main/java/org/apache/druid/segment/serde/DictionaryEncodedStringIndexSupplier.java
b/processing/src/main/java/org/apache/druid/segment/serde/DictionaryEncodedStringIndexSupplier.java
index 0a1ee09d51..30b31784b1 100644
---
a/processing/src/main/java/org/apache/druid/segment/serde/DictionaryEncodedStringIndexSupplier.java
+++
b/processing/src/main/java/org/apache/druid/segment/serde/DictionaryEncodedStringIndexSupplier.java
@@ -33,18 +33,19 @@ import org.apache.druid.query.BitmapResultFactory;
import org.apache.druid.query.filter.DruidPredicateFactory;
import org.apache.druid.segment.IntListUtils;
import org.apache.druid.segment.column.BitmapColumnIndex;
-import org.apache.druid.segment.column.ColumnIndexCapabilities;
import org.apache.druid.segment.column.ColumnIndexSupplier;
import org.apache.druid.segment.column.DictionaryEncodedStringValueIndex;
import org.apache.druid.segment.column.DruidPredicateIndex;
import org.apache.druid.segment.column.LexicographicalRangeIndex;
-import org.apache.druid.segment.column.SimpleColumnIndexCapabilities;
+import org.apache.druid.segment.column.NullValueIndex;
+import org.apache.druid.segment.column.SimpleBitmapColumnIndex;
+import org.apache.druid.segment.column.SimpleImmutableBitmapIndex;
+import org.apache.druid.segment.column.SimpleImmutableBitmapIterableIndex;
import org.apache.druid.segment.column.SpatialIndex;
import org.apache.druid.segment.column.StringValueSetIndex;
import org.apache.druid.segment.column.Utf8ValueSetIndex;
import org.apache.druid.segment.data.GenericIndexed;
import org.apache.druid.segment.data.Indexed;
-import org.apache.druid.segment.filter.Filters;
import javax.annotation.Nullable;
import java.nio.ByteBuffer;
@@ -54,8 +55,6 @@ import java.util.SortedSet;
public class DictionaryEncodedStringIndexSupplier implements
ColumnIndexSupplier
{
- public static final ColumnIndexCapabilities CAPABILITIES = new
SimpleColumnIndexCapabilities(true, true);
-
private final BitmapFactory bitmapFactory;
private final GenericIndexed<String> dictionary;
private final GenericIndexed<ByteBuffer> dictionaryUtf8;
@@ -84,35 +83,38 @@ public class DictionaryEncodedStringIndexSupplier
implements ColumnIndexSupplier
@SuppressWarnings("unchecked")
public <T> T as(Class<T> clazz)
{
- if (bitmaps != null && clazz.equals(StringValueSetIndex.class)) {
- return (T) new
GenericIndexedDictionaryEncodedStringValueSetIndex(bitmapFactory,
dictionaryUtf8, bitmaps);
- } else if (bitmaps != null && clazz.equals(Utf8ValueSetIndex.class)) {
- return (T) new
GenericIndexedDictionaryEncodedStringValueSetIndex(bitmapFactory,
dictionaryUtf8, bitmaps);
- } else if (bitmaps != null && clazz.equals(DruidPredicateIndex.class)) {
- return (T) new
GenericIndexedDictionaryEncodedStringDruidPredicateIndex(bitmapFactory,
dictionary, bitmaps);
- } else if (bitmaps != null &&
clazz.equals(LexicographicalRangeIndex.class)) {
- return (T) new
GenericIndexedDictionaryEncodedColumnLexicographicalRangeIndex(
- bitmapFactory,
- dictionaryUtf8,
- bitmaps
- );
- } else if (bitmaps != null &&
clazz.equals(DictionaryEncodedStringValueIndex.class)) {
- return (T) new
GenericIndexedDictionaryEncodedStringValueIndex(bitmapFactory, dictionary,
bitmaps);
- } else if (indexedTree != null && clazz.equals(SpatialIndex.class)) {
+ if (bitmaps != null) {
+ if (clazz.equals(NullValueIndex.class)) {
+ final BitmapColumnIndex nullIndex;
+ if (NullHandling.isNullOrEquivalent(dictionary.get(0))) {
+ nullIndex = new SimpleImmutableBitmapIndex(bitmaps.get(0));
+ } else {
+ nullIndex = new
SimpleImmutableBitmapIndex(bitmapFactory.makeEmptyImmutableBitmap());
+ }
+ return (T) (NullValueIndex) () -> nullIndex;
+ } else if (clazz.equals(StringValueSetIndex.class)) {
+ return (T) new
GenericIndexedDictionaryEncodedStringValueSetIndex(bitmapFactory,
dictionaryUtf8, bitmaps);
+ } else if (clazz.equals(Utf8ValueSetIndex.class)) {
+ return (T) new
GenericIndexedDictionaryEncodedStringValueSetIndex(bitmapFactory,
dictionaryUtf8, bitmaps);
+ } else if (clazz.equals(DruidPredicateIndex.class)) {
+ return (T) new
GenericIndexedDictionaryEncodedStringDruidPredicateIndex(bitmapFactory,
dictionary, bitmaps);
+ } else if (clazz.equals(LexicographicalRangeIndex.class)) {
+ return (T) new
GenericIndexedDictionaryEncodedColumnLexicographicalRangeIndex(
+ bitmapFactory,
+ dictionaryUtf8,
+ bitmaps,
+ NullHandling.isNullOrEquivalent(dictionary.get(0))
+ );
+ } else if (clazz.equals(DictionaryEncodedStringValueIndex.class)) {
+ return (T) new
GenericIndexedDictionaryEncodedStringValueIndex(bitmapFactory, dictionary,
bitmaps);
+ }
+ }
+ if (indexedTree != null && clazz.equals(SpatialIndex.class)) {
return (T) (SpatialIndex) () -> indexedTree;
}
return null;
}
- private abstract static class DictionaryEncodedStringBitmapColumnIndex
implements BitmapColumnIndex
- {
- @Override
- public ColumnIndexCapabilities getIndexCapabilities()
- {
- return CAPABILITIES;
- }
- }
-
private abstract static class BaseGenericIndexedDictionaryEncodedIndex<T>
{
protected final BitmapFactory bitmapFactory;
@@ -196,7 +198,7 @@ public class DictionaryEncodedStringIndexSupplier
implements ColumnIndexSupplier
@Override
public BitmapColumnIndex forValue(@Nullable String value)
{
- return new DictionaryEncodedStringBitmapColumnIndex()
+ return new SimpleBitmapColumnIndex()
{
@Override
public double estimateSelectivity(int totalRows)
@@ -251,21 +253,10 @@ public class DictionaryEncodedStringIndexSupplier
implements ColumnIndexSupplier
*/
private BitmapColumnIndex
getBitmapColumnIndexForSortedIterableUtf8(Iterable<ByteBuffer> valuesUtf8)
{
- return new DictionaryEncodedStringBitmapColumnIndex()
+ return new SimpleImmutableBitmapIterableIndex()
{
@Override
- public double estimateSelectivity(int totalRows)
- {
- return Filters.estimateSelectivity(getBitmapsIterable().iterator(),
totalRows);
- }
-
- @Override
- public <T> T computeBitmapResult(BitmapResultFactory<T>
bitmapResultFactory)
- {
- return
bitmapResultFactory.unionDimensionValueBitmaps(getBitmapsIterable());
- }
-
- private Iterable<ImmutableBitmap> getBitmapsIterable()
+ public Iterable<ImmutableBitmap> getBitmapIterable()
{
final int dictionarySize = dictionary.size();
@@ -332,24 +323,10 @@ public class DictionaryEncodedStringIndexSupplier
implements ColumnIndexSupplier
@Override
public BitmapColumnIndex forPredicate(DruidPredicateFactory matcherFactory)
{
- return new DictionaryEncodedStringBitmapColumnIndex()
+ return new SimpleImmutableBitmapIterableIndex()
{
@Override
- public double estimateSelectivity(int totalRows)
- {
- return Filters.estimateSelectivity(
- getBitmapIterable().iterator(),
- totalRows
- );
- }
-
- @Override
- public <T> T computeBitmapResult(BitmapResultFactory<T>
bitmapResultFactory)
- {
- return
bitmapResultFactory.unionDimensionValueBitmaps(getBitmapIterable());
- }
-
- private Iterable<ImmutableBitmap> getBitmapIterable()
+ public Iterable<ImmutableBitmap> getBitmapIterable()
{
return () -> new Iterator<ImmutableBitmap>()
{
@@ -406,14 +383,17 @@ public class DictionaryEncodedStringIndexSupplier
implements ColumnIndexSupplier
public static final class
GenericIndexedDictionaryEncodedColumnLexicographicalRangeIndex
extends BaseGenericIndexedDictionaryEncodedIndex<ByteBuffer> implements
LexicographicalRangeIndex
{
+ private final boolean hasNull;
public GenericIndexedDictionaryEncodedColumnLexicographicalRangeIndex(
BitmapFactory bitmapFactory,
GenericIndexed<ByteBuffer> dictionary,
- GenericIndexed<ImmutableBitmap> bitmaps
+ GenericIndexed<ImmutableBitmap> bitmaps,
+ boolean hasNull
)
{
super(bitmapFactory, dictionary, bitmaps);
+ this.hasNull = hasNull;
}
@Override
@@ -424,21 +404,10 @@ public class DictionaryEncodedStringIndexSupplier
implements ColumnIndexSupplier
boolean endStrict
)
{
- return new DictionaryEncodedStringBitmapColumnIndex()
+ return new SimpleImmutableBitmapIterableIndex()
{
@Override
- public double estimateSelectivity(int totalRows)
- {
- return Filters.estimateSelectivity(getBitmapIterable().iterator(),
totalRows);
- }
-
- @Override
- public <T> T computeBitmapResult(BitmapResultFactory<T>
bitmapResultFactory)
- {
- return
bitmapResultFactory.unionDimensionValueBitmaps(getBitmapIterable());
- }
-
- private Iterable<ImmutableBitmap> getBitmapIterable()
+ public Iterable<ImmutableBitmap> getBitmapIterable()
{
final IntIntPair range = getRange(startValue, startStrict, endValue,
endStrict);
final int start = range.leftInt(), end = range.rightInt();
@@ -471,22 +440,10 @@ public class DictionaryEncodedStringIndexSupplier
implements ColumnIndexSupplier
Predicate<String> matcher
)
{
- return new DictionaryEncodedStringBitmapColumnIndex()
+ return new SimpleImmutableBitmapIterableIndex()
{
@Override
- public double estimateSelectivity(int totalRows)
- {
- return Filters.estimateSelectivity(getBitmapIterable().iterator(),
totalRows);
- }
-
- @Override
- public <T> T computeBitmapResult(BitmapResultFactory<T>
bitmapResultFactory)
- {
-
- return
bitmapResultFactory.unionDimensionValueBitmaps(getBitmapIterable());
- }
-
- private Iterable<ImmutableBitmap> getBitmapIterable()
+ public Iterable<ImmutableBitmap> getBitmapIterable()
{
final IntIntPair range = getRange(startValue, startStrict, endValue,
endStrict);
final int start = range.leftInt(), end = range.rightInt();
@@ -552,13 +509,14 @@ public class DictionaryEncodedStringIndexSupplier
implements ColumnIndexSupplier
boolean endStrict
)
{
+ final int firstValue = hasNull ? 1 : 0;
int startIndex, endIndex;
if (startValue == null) {
- startIndex = 0;
+ startIndex = firstValue;
} else {
final String startValueToUse =
NullHandling.emptyToNullIfNeeded(startValue);
final int found =
dictionary.indexOf(StringUtils.toUtf8ByteBuffer(startValueToUse));
- if (found >= 0) {
+ if (found >= firstValue) {
startIndex = startStrict ? found + 1 : found;
} else {
startIndex = -(found + 1);
@@ -570,7 +528,7 @@ public class DictionaryEncodedStringIndexSupplier
implements ColumnIndexSupplier
} else {
final String endValueToUse =
NullHandling.emptyToNullIfNeeded(endValue);
final int found =
dictionary.indexOf(StringUtils.toUtf8ByteBuffer(endValueToUse));
- if (found >= 0) {
+ if (found >= firstValue) {
endIndex = endStrict ? found : found + 1;
} else {
endIndex = -(found + 1);
diff --git
a/processing/src/main/java/org/apache/druid/segment/serde/DoubleNumericColumnPartSerdeV2.java
b/processing/src/main/java/org/apache/druid/segment/serde/DoubleNumericColumnPartSerdeV2.java
index 53d43f4b84..3e851484b2 100644
---
a/processing/src/main/java/org/apache/druid/segment/serde/DoubleNumericColumnPartSerdeV2.java
+++
b/processing/src/main/java/org/apache/druid/segment/serde/DoubleNumericColumnPartSerdeV2.java
@@ -163,7 +163,8 @@ public class DoubleNumericColumnPartSerdeV2 implements
ColumnPartSerde
builder.setType(ValueType.DOUBLE)
.setHasMultipleValues(false)
.setHasNulls(hasNulls)
- .setNumericColumnSupplier(new DoubleNumericColumnSupplier(column,
bitmap));
+ .setNumericColumnSupplier(new DoubleNumericColumnSupplier(column,
bitmap))
+ .setNullValueIndexSupplier(bitmap);
};
}
}
diff --git
a/processing/src/main/java/org/apache/druid/segment/serde/FloatNumericColumnPartSerdeV2.java
b/processing/src/main/java/org/apache/druid/segment/serde/FloatNumericColumnPartSerdeV2.java
index 6e33f73cad..29a1e2c46f 100644
---
a/processing/src/main/java/org/apache/druid/segment/serde/FloatNumericColumnPartSerdeV2.java
+++
b/processing/src/main/java/org/apache/druid/segment/serde/FloatNumericColumnPartSerdeV2.java
@@ -160,7 +160,8 @@ public class FloatNumericColumnPartSerdeV2 implements
ColumnPartSerde
builder.setType(ValueType.FLOAT)
.setHasMultipleValues(false)
.setHasNulls(hasNulls)
- .setNumericColumnSupplier(new FloatNumericColumnSupplier(column,
bitmap));
+ .setNumericColumnSupplier(new FloatNumericColumnSupplier(column,
bitmap))
+ .setNullValueIndexSupplier(bitmap);
};
}
}
diff --git
a/processing/src/main/java/org/apache/druid/segment/serde/LongNumericColumnPartSerdeV2.java
b/processing/src/main/java/org/apache/druid/segment/serde/LongNumericColumnPartSerdeV2.java
index ed7ecbf6a9..c59bb99b1c 100644
---
a/processing/src/main/java/org/apache/druid/segment/serde/LongNumericColumnPartSerdeV2.java
+++
b/processing/src/main/java/org/apache/druid/segment/serde/LongNumericColumnPartSerdeV2.java
@@ -162,7 +162,8 @@ public class LongNumericColumnPartSerdeV2 implements
ColumnPartSerde
builder.setType(ValueType.LONG)
.setHasMultipleValues(false)
.setHasNulls(hasNulls)
- .setNumericColumnSupplier(new LongNumericColumnSupplier(column,
bitmap));
+ .setNumericColumnSupplier(new LongNumericColumnSupplier(column,
bitmap))
+ .setNullValueIndexSupplier(bitmap);
};
}
}
diff --git
a/processing/src/main/java/org/apache/druid/segment/serde/NullValueIndexSupplier.java
b/processing/src/main/java/org/apache/druid/segment/serde/NullValueIndexSupplier.java
new file mode 100644
index 0000000000..d66d15ca4b
--- /dev/null
+++
b/processing/src/main/java/org/apache/druid/segment/serde/NullValueIndexSupplier.java
@@ -0,0 +1,63 @@
+/*
+ * 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.segment.serde;
+
+import org.apache.druid.collections.bitmap.ImmutableBitmap;
+import org.apache.druid.segment.column.BitmapColumnIndex;
+import org.apache.druid.segment.column.ColumnIndexSupplier;
+import org.apache.druid.segment.column.NullValueIndex;
+import org.apache.druid.segment.column.SimpleImmutableBitmapIndex;
+
+import javax.annotation.Nullable;
+
+/**
+ * {@link ColumnIndexSupplier} for columns which only have an {@link
ImmutableBitmap} to indicate which rows only have
+ * null values, such as {@link LongNumericColumnPartSerdeV2}, {@link
DoubleNumericColumnPartSerdeV2}, and
+ * {@link FloatNumericColumnPartSerdeV2}.
+ *
+ */
+public class NullValueIndexSupplier implements ColumnIndexSupplier
+{
+ private final SimpleImmutableBitmapIndex nullValueIndex;
+
+ public NullValueIndexSupplier(ImmutableBitmap nullValueBitmap)
+ {
+ this.nullValueIndex = new SimpleImmutableBitmapIndex(nullValueBitmap);
+ }
+
+ @Nullable
+ @Override
+ public <T> T as(Class<T> clazz)
+ {
+ if (clazz.equals(NullValueIndex.class)) {
+ return (T) new NullableNumericNullValueIndex();
+ }
+ return null;
+ }
+
+ private final class NullableNumericNullValueIndex implements NullValueIndex
+ {
+ @Override
+ public BitmapColumnIndex forNull()
+ {
+ return nullValueIndex;
+ }
+ }
+}
diff --git
a/processing/src/main/java/org/apache/druid/segment/virtual/ListFilteredVirtualColumn.java
b/processing/src/main/java/org/apache/druid/segment/virtual/ListFilteredVirtualColumn.java
index 032542efd1..14b6f173c0 100644
---
a/processing/src/main/java/org/apache/druid/segment/virtual/ListFilteredVirtualColumn.java
+++
b/processing/src/main/java/org/apache/druid/segment/virtual/ListFilteredVirtualColumn.java
@@ -44,14 +44,15 @@ import org.apache.druid.segment.column.BitmapColumnIndex;
import org.apache.druid.segment.column.ColumnCapabilities;
import org.apache.druid.segment.column.ColumnCapabilitiesImpl;
import org.apache.druid.segment.column.ColumnHolder;
-import org.apache.druid.segment.column.ColumnIndexCapabilities;
import org.apache.druid.segment.column.ColumnIndexSupplier;
import org.apache.druid.segment.column.DictionaryEncodedStringValueIndex;
import org.apache.druid.segment.column.DruidPredicateIndex;
import org.apache.druid.segment.column.LexicographicalRangeIndex;
+import org.apache.druid.segment.column.NullValueIndex;
+import org.apache.druid.segment.column.SimpleBitmapColumnIndex;
+import org.apache.druid.segment.column.SimpleImmutableBitmapIterableIndex;
import org.apache.druid.segment.column.StringValueSetIndex;
import org.apache.druid.segment.filter.Filters;
-import org.apache.druid.segment.serde.DictionaryEncodedStringIndexSupplier;
import javax.annotation.Nullable;
import java.util.Collections;
@@ -184,16 +185,26 @@ public class ListFilteredVirtualColumn implements
VirtualColumn
@Override
public <T> T as(Class<T> clazz)
{
+
final ColumnHolder holder =
columnSelector.getColumnHolder(delegate.getDimension());
if (holder == null) {
return null;
}
- DictionaryEncodedStringValueIndex underlyingIndex =
holder.getIndexSupplier().as(
+ // someday maybe we can have a better way to get row count..
+ final ColumnHolder time =
columnSelector.getColumnHolder(ColumnHolder.TIME_COLUMN_NAME);
+ final int numRows = time.getLength();
+
+ ColumnIndexSupplier indexSupplier = holder.getIndexSupplier();
+ if (indexSupplier == null) {
+ return null;
+ }
+ DictionaryEncodedStringValueIndex underlyingIndex = indexSupplier.as(
DictionaryEncodedStringValueIndex.class
);
if (underlyingIndex == null) {
return null;
}
+
final IdMapping idMapping;
if (allowList) {
idMapping = ListFilteredDimensionSpec.buildAllowListIdMapping(
@@ -209,7 +220,10 @@ public class ListFilteredVirtualColumn implements
VirtualColumn
underlyingIndex::getValue
);
}
- if (clazz.equals(StringValueSetIndex.class)) {
+
+ if (clazz.equals(NullValueIndex.class)) {
+ return (T) new ListFilteredNullValueIndex(underlyingIndex,
idMapping, numRows);
+ } else if (clazz.equals(StringValueSetIndex.class)) {
return (T) new ListFilteredStringValueSetIndex(underlyingIndex,
idMapping);
} else if (clazz.equals(DruidPredicateIndex.class)) {
return (T) new ListFilteredDruidPredicateIndex(underlyingIndex,
idMapping);
@@ -254,15 +268,6 @@ public class ListFilteredVirtualColumn implements
VirtualColumn
'}';
}
- private abstract static class BaseVirtualIndex implements BitmapColumnIndex
- {
- @Override
- public ColumnIndexCapabilities getIndexCapabilities()
- {
- return DictionaryEncodedStringIndexSupplier.CAPABILITIES;
- }
- }
-
private static class BaseListFilteredColumnIndex
{
final DictionaryEncodedStringValueIndex delegate;
@@ -357,6 +362,46 @@ public class ListFilteredVirtualColumn implements
VirtualColumn
}
}
+ private static class ListFilteredNullValueIndex extends
BaseListFilteredColumnIndex implements NullValueIndex
+ {
+ private final int numRows;
+
+ private ListFilteredNullValueIndex(DictionaryEncodedStringValueIndex
delegate, IdMapping idMapping, int numRows)
+ {
+ super(delegate, idMapping);
+ this.numRows = numRows;
+ }
+
+ @Override
+ public BitmapColumnIndex forNull()
+ {
+ return new SimpleImmutableBitmapIterableIndex()
+ {
+ @Override
+ public double estimateSelectivity(int totalRows)
+ {
+ return 1.0 -
Filters.estimateSelectivity(getBitmapIterable().iterator(), totalRows);
+ }
+
+ @Override
+ public <T> T computeBitmapResult(BitmapResultFactory<T>
bitmapResultFactory)
+ {
+ return bitmapResultFactory.complement(
+
bitmapResultFactory.unionDimensionValueBitmaps(getBitmapIterable()),
+ numRows
+ );
+ }
+
+ @Override
+ protected Iterable<ImmutableBitmap> getBitmapIterable()
+ {
+ final int start =
NullHandling.isNullOrEquivalent(delegate.getValue(idMapping.getReverseId(0))) ?
1 : 0;
+ return getBitmapsInRange(v -> true, start,
idMapping.getValueCardinality());
+ }
+ };
+ }
+ }
+
private static class ListFilteredStringValueSetIndex extends
BaseListFilteredColumnIndex
implements StringValueSetIndex
{
@@ -372,9 +417,8 @@ public class ListFilteredVirtualColumn implements
VirtualColumn
@Override
public BitmapColumnIndex forValue(@Nullable String value)
{
- return new BaseVirtualIndex()
+ return new SimpleBitmapColumnIndex()
{
-
@Override
public double estimateSelectivity(int totalRows)
{
@@ -401,21 +445,10 @@ public class ListFilteredVirtualColumn implements
VirtualColumn
@Override
public BitmapColumnIndex forSortedValues(SortedSet<String> values)
{
- return new BaseVirtualIndex()
+ return new SimpleImmutableBitmapIterableIndex()
{
@Override
- public double estimateSelectivity(int totalRows)
- {
- return Filters.estimateSelectivity(getBitmapsIterable().iterator(),
totalRows);
- }
-
- @Override
- public <T> T computeBitmapResult(BitmapResultFactory<T>
bitmapResultFactory)
- {
- return
bitmapResultFactory.unionDimensionValueBitmaps(getBitmapsIterable());
- }
-
- private Iterable<ImmutableBitmap> getBitmapsIterable()
+ public Iterable<ImmutableBitmap> getBitmapIterable()
{
return () -> new Iterator<ImmutableBitmap>()
{
@@ -470,9 +503,8 @@ public class ListFilteredVirtualColumn implements
VirtualColumn
@Override
public BitmapColumnIndex forPredicate(DruidPredicateFactory matcherFactory)
{
- return new BaseVirtualIndex()
+ return new SimpleBitmapColumnIndex()
{
-
@Override
public double estimateSelectivity(int totalRows)
{
@@ -527,22 +559,10 @@ public class ListFilteredVirtualColumn implements
VirtualColumn
Predicate<String> matcher
)
{
- return new BaseVirtualIndex()
+ return new SimpleImmutableBitmapIterableIndex()
{
@Override
- public double estimateSelectivity(int totalRows)
- {
- return Filters.estimateSelectivity(getBitmapIterable().iterator(),
totalRows);
- }
-
- @Override
- public <T> T computeBitmapResult(BitmapResultFactory<T>
bitmapResultFactory)
- {
-
- return
bitmapResultFactory.unionDimensionValueBitmaps(getBitmapIterable());
- }
-
- private Iterable<ImmutableBitmap> getBitmapIterable()
+ public Iterable<ImmutableBitmap> getBitmapIterable()
{
int startIndex, endIndex;
if (startValue == null) {
diff --git
a/processing/src/test/java/org/apache/druid/segment/filter/BoundFilterTest.java
b/processing/src/test/java/org/apache/druid/segment/filter/BoundFilterTest.java
index 033b5bd5db..ec952c31d1 100644
---
a/processing/src/test/java/org/apache/druid/segment/filter/BoundFilterTest.java
+++
b/processing/src/test/java/org/apache/druid/segment/filter/BoundFilterTest.java
@@ -450,6 +450,12 @@ public class BoundFilterTest extends BaseFilterTest
new BoundDimFilter("allow-dim0", "0", "6", false, false, false, null,
StringComparators.LEXICOGRAPHIC),
ImmutableList.of("3", "4")
);
+ // the bound filter matches null, so it is what it is...
+ assertFilterMatchesSkipVectorize(
+ new BoundDimFilter("allow-dim0", null, "6", false, false, false, null,
StringComparators.LEXICOGRAPHIC),
+ ImmutableList.of("0", "1", "2", "3", "4", "5", "6", "7")
+ );
+
assertFilterMatchesSkipVectorize(
new BoundDimFilter("deny-dim0", "0", "6", false, false, false, null,
StringComparators.LEXICOGRAPHIC),
ImmutableList.of("0", "1", "2", "5", "6")
@@ -458,6 +464,11 @@ public class BoundFilterTest extends BaseFilterTest
new BoundDimFilter("deny-dim0", "3", "4", false, false, false, null,
StringComparators.LEXICOGRAPHIC),
ImmutableList.of()
);
+ // the bound filter matches null, so it is what it is...
+ assertFilterMatchesSkipVectorize(
+ new BoundDimFilter("deny-dim0", null, "6", false, false, false, null,
StringComparators.LEXICOGRAPHIC),
+ ImmutableList.of("0", "1", "2", "3", "4", "5", "6")
+ );
assertFilterMatchesSkipVectorize(
new BoundDimFilter("allow-dim2", "a", "c", false, false, false, null,
StringComparators.LEXICOGRAPHIC),
@@ -467,6 +478,11 @@ public class BoundFilterTest extends BaseFilterTest
new BoundDimFilter("allow-dim2", "c", "z", false, false, false, null,
StringComparators.LEXICOGRAPHIC),
ImmutableList.of()
);
+ // the bound filter matches null, so it is what it is...
+ assertFilterMatchesSkipVectorize(
+ new BoundDimFilter("allow-dim2", null, "z", false, false, false, null,
StringComparators.LEXICOGRAPHIC),
+ ImmutableList.of("0", "1", "2", "3", "4", "5", "6", "7")
+ );
assertFilterMatchesSkipVectorize(
new BoundDimFilter("deny-dim2", "a", "b", false, true, false, null,
StringComparators.LEXICOGRAPHIC),
@@ -476,6 +492,11 @@ public class BoundFilterTest extends BaseFilterTest
new BoundDimFilter("deny-dim2", "c", "z", false, false, false, null,
StringComparators.LEXICOGRAPHIC),
ImmutableList.of("4", "7")
);
+ // the bound filter matches null, so it is what it is...
+ assertFilterMatchesSkipVectorize(
+ new BoundDimFilter("deny-dim2", null, "z", false, false, false, null,
StringComparators.LEXICOGRAPHIC),
+ ImmutableList.of("0", "1", "2", "3", "4", "5", "6", "7")
+ );
}
@Test
diff --git
a/processing/src/test/java/org/apache/druid/segment/filter/LikeFilterTest.java
b/processing/src/test/java/org/apache/druid/segment/filter/LikeFilterTest.java
index 94455cd0a1..eb81334acb 100644
---
a/processing/src/test/java/org/apache/druid/segment/filter/LikeFilterTest.java
+++
b/processing/src/test/java/org/apache/druid/segment/filter/LikeFilterTest.java
@@ -272,6 +272,23 @@ public class LikeFilterTest extends BaseFilterTest
);
}
+ @Test
+ public void testListFilteredVirtualColumn()
+ {
+ assertFilterMatchesSkipVectorize(
+ new LikeDimFilter("allow-dim0", "1%", null, null),
+ ImmutableList.of()
+ );
+ assertFilterMatchesSkipVectorize(
+ new LikeDimFilter("allow-dim0", "3%", null, null),
+ ImmutableList.of("3")
+ );
+ assertFilterMatchesSkipVectorize(
+ new LikeDimFilter("allow-dim0", "%3", null, null),
+ ImmutableList.of("3")
+ );
+ }
+
@Test
public void testRequiredColumnRewrite()
{
diff --git
a/processing/src/test/java/org/apache/druid/segment/filter/SelectorFilterTest.java
b/processing/src/test/java/org/apache/druid/segment/filter/SelectorFilterTest.java
index 3939cf8af6..95765949ac 100644
---
a/processing/src/test/java/org/apache/druid/segment/filter/SelectorFilterTest.java
+++
b/processing/src/test/java/org/apache/druid/segment/filter/SelectorFilterTest.java
@@ -120,13 +120,26 @@ public class SelectorFilterTest extends BaseFilterTest
{
assertFilterMatchesSkipVectorize(new SelectorDimFilter("allow-dim0", "1",
null), ImmutableList.of());
assertFilterMatchesSkipVectorize(new SelectorDimFilter("allow-dim0", "4",
null), ImmutableList.of("4"));
+ assertFilterMatchesSkipVectorize(new SelectorDimFilter("allow-dim0", null,
null), ImmutableList.of("0", "1", "2", "5"));
assertFilterMatchesSkipVectorize(new SelectorDimFilter("deny-dim0", "0",
null), ImmutableList.of("0"));
assertFilterMatchesSkipVectorize(new SelectorDimFilter("deny-dim0", "4",
null), ImmutableList.of());
-
+ assertFilterMatchesSkipVectorize(new SelectorDimFilter("deny-dim0", null,
null), ImmutableList.of("3", "4"));
assertFilterMatchesSkipVectorize(new SelectorDimFilter("allow-dim2", "b",
null), ImmutableList.of());
assertFilterMatchesSkipVectorize(new SelectorDimFilter("allow-dim2", "a",
null), ImmutableList.of("0", "3"));
+ assertFilterMatchesSkipVectorize(new SelectorDimFilter("allow-dim2", null,
null), ImmutableList.of("1", "2", "4", "5"));
assertFilterMatchesSkipVectorize(new SelectorDimFilter("deny-dim2", "b",
null), ImmutableList.of("0"));
assertFilterMatchesSkipVectorize(new SelectorDimFilter("deny-dim2", "a",
null), ImmutableList.of());
+ if (NullHandling.replaceWithDefault()) {
+ assertFilterMatchesSkipVectorize(
+ new SelectorDimFilter("deny-dim2", null, null),
+ ImmutableList.of("1", "2", "3", "5")
+ );
+ } else {
+ assertFilterMatchesSkipVectorize(
+ new SelectorDimFilter("deny-dim2", null, null),
+ ImmutableList.of("1", "3", "5")
+ );
+ }
}
@Test
diff --git
a/processing/src/test/java/org/apache/druid/segment/virtual/ListFilteredVirtualColumnSelectorTest.java
b/processing/src/test/java/org/apache/druid/segment/virtual/ListFilteredVirtualColumnSelectorTest.java
index e614d06756..d2c146b193 100644
---
a/processing/src/test/java/org/apache/druid/segment/virtual/ListFilteredVirtualColumnSelectorTest.java
+++
b/processing/src/test/java/org/apache/druid/segment/virtual/ListFilteredVirtualColumnSelectorTest.java
@@ -169,12 +169,15 @@ public class ListFilteredVirtualColumnSelectorTest
extends InitializedNullHandli
ColumnSelector selector = EasyMock.createMock(ColumnSelector.class);
ColumnHolder holder = EasyMock.createMock(ColumnHolder.class);
+ ColumnHolder timeHolder = EasyMock.createMock(ColumnHolder.class);
DictionaryEncodedStringValueIndex index =
EasyMock.createMock(DictionaryEncodedStringValueIndex.class);
ImmutableBitmap bitmap = EasyMock.createMock(ImmutableBitmap.class);
BitmapFactory bitmapFactory = EasyMock.createMock(BitmapFactory.class);
ColumnIndexSupplier indexSupplier =
EasyMock.createMock(ColumnIndexSupplier.class);
EasyMock.expect(selector.getColumnHolder(COLUMN_NAME)).andReturn(holder).atLeastOnce();
+
EasyMock.expect(selector.getColumnHolder(ColumnHolder.TIME_COLUMN_NAME)).andReturn(timeHolder).atLeastOnce();
+ EasyMock.expect(timeHolder.getLength()).andReturn(10).anyTimes();
EasyMock.expect(selector.getColumnCapabilities(COLUMN_NAME))
.andReturn(new ColumnCapabilitiesImpl().setType(ColumnType.STRING)
.setDictionaryEncoded(true)
@@ -195,7 +198,7 @@ public class ListFilteredVirtualColumnSelectorTest extends
InitializedNullHandli
EasyMock.expect(index.getBitmap(2)).andReturn(bitmap).once();
EasyMock.expect(index.hasNulls()).andReturn(true).once();
- EasyMock.replay(selector, holder, indexSupplier, index, bitmap,
bitmapFactory);
+ EasyMock.replay(selector, holder, timeHolder, indexSupplier, index,
bitmap, bitmapFactory);
ColumnSelectorColumnIndexSelector bitmapIndexSelector = new
ColumnSelectorColumnIndexSelector(
new RoaringBitmapFactory(),
@@ -217,7 +220,7 @@ public class ListFilteredVirtualColumnSelectorTest extends
InitializedNullHandli
Assert.assertEquals(bitmap, listFilteredIndex.getBitmap(1));
Assert.assertTrue(listFilteredIndex.hasNulls());
- EasyMock.verify(selector, holder, indexSupplier, index, bitmap,
bitmapFactory);
+ EasyMock.verify(selector, holder, timeHolder, indexSupplier, index,
bitmap, bitmapFactory);
}
@Test
@@ -233,12 +236,15 @@ public class ListFilteredVirtualColumnSelectorTest
extends InitializedNullHandli
ColumnSelector selector = EasyMock.createMock(ColumnSelector.class);
ColumnHolder holder = EasyMock.createMock(ColumnHolder.class);
+ ColumnHolder timeHolder = EasyMock.createMock(ColumnHolder.class);
DictionaryEncodedStringValueIndex index =
EasyMock.createMock(DictionaryEncodedStringValueIndex.class);
ImmutableBitmap bitmap = EasyMock.createMock(ImmutableBitmap.class);
ColumnIndexSupplier indexSupplier =
EasyMock.createMock(ColumnIndexSupplier.class);
BitmapFactory bitmapFactory = EasyMock.createMock(BitmapFactory.class);
EasyMock.expect(selector.getColumnHolder(COLUMN_NAME)).andReturn(holder).atLeastOnce();
+
EasyMock.expect(selector.getColumnHolder(ColumnHolder.TIME_COLUMN_NAME)).andReturn(timeHolder).atLeastOnce();
+ EasyMock.expect(timeHolder.getLength()).andReturn(10).anyTimes();
EasyMock.expect(selector.getColumnCapabilities(COLUMN_NAME))
.andReturn(new ColumnCapabilitiesImpl().setType(ColumnType.STRING)
.setDictionaryEncoded(true)
@@ -256,7 +262,7 @@ public class ListFilteredVirtualColumnSelectorTest extends
InitializedNullHandli
EasyMock.expect(index.getBitmap(0)).andReturn(bitmap).once();
EasyMock.expect(index.hasNulls()).andReturn(true).once();
- EasyMock.replay(selector, holder, indexSupplier, index, bitmap,
bitmapFactory);
+ EasyMock.replay(selector, holder, timeHolder, indexSupplier, index,
bitmap, bitmapFactory);
ColumnSelectorColumnIndexSelector bitmapIndexSelector = new
ColumnSelectorColumnIndexSelector(
new RoaringBitmapFactory(),
@@ -276,7 +282,7 @@ public class ListFilteredVirtualColumnSelectorTest extends
InitializedNullHandli
Assert.assertEquals(bitmap, listFilteredIndex.getBitmap(1));
Assert.assertTrue(listFilteredIndex.hasNulls());
- EasyMock.verify(selector, holder, indexSupplier, index, bitmap,
bitmapFactory);
+ EasyMock.verify(selector, holder, timeHolder, indexSupplier, index,
bitmap, bitmapFactory);
}
private void assertCapabilities(VirtualizedColumnSelectorFactory
selectorFactory, String columnName)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]