This is an automated email from the ASF dual-hosted git repository.
jihoonson 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 6674d72 Avoid sorting values in InDimFilter if possible (#9800)
6674d72 is described below
commit 6674d721bcc93ff959ae6d63c3eb71255179363d
Author: Jihoon Son <[email protected]>
AuthorDate: Wed May 6 15:26:36 2020 -0700
Avoid sorting values in InDimFilter if possible (#9800)
* Avoid sorting values in InDimFilter if possible
* tests
* more tests
* fix and and or filters
* fix build
* false and true vector matchers
* fix vector matchers
* checkstyle
* in filter null handling
* remove wrong test
* address comments
* remove unnecessary null check
* redundant separator
* address comments
* typo
* tests
---
.../apache/druid/common/config/NullHandling.java | 5 +
.../IngestSegmentFirehoseFactoryTimelineTest.java | 2 +-
.../main/java/org/apache/druid/query/Druids.java | 7 +-
.../apache/druid/query/filter/AndDimFilter.java | 17 ++-
.../org/apache/druid/query/filter/DimFilter.java | 4 +-
.../apache/druid/query/filter/DimFilterUtils.java | 1 +
.../{TrueDimFilter.java => FalseDimFilter.java} | 51 +++++--
.../org/apache/druid/query/filter/InDimFilter.java | 81 ++++++++----
.../apache/druid/query/filter/NotDimFilter.java | 9 +-
.../org/apache/druid/query/filter/OrDimFilter.java | 21 ++-
.../druid/query/filter/SelectorDimFilter.java | 2 +-
.../apache/druid/query/filter/TrueDimFilter.java | 36 ++++-
.../FalseVectorMatcher.java} | 36 ++---
.../TrueVectorMatcher.java} | 37 ++----
.../apache/druid/query/topn/TopNQueryBuilder.java | 7 +-
.../apache/druid/segment/filter/FalseFilter.java | 15 +++
.../org/apache/druid/segment/filter/InFilter.java | 5 +
.../druid/segment/filter/SelectorFilter.java | 5 +
.../apache/druid/segment/filter/TrueFilter.java | 15 +++
.../QueryableIndexVectorColumnSelectorFactory.java | 4 +-
.../vector/VectorColumnSelectorFactory.java | 10 +-
.../aggregation/FilteredAggregatorFactoryTest.java | 6 +-
.../druid/query/filter/AndDimFilterTest.java | 35 +++++
.../FalseDimFilterTest.java} | 38 +++---
.../druid/query/filter/InDimFilterSerDesrTest.java | 85 ------------
.../apache/druid/query/filter/InDimFilterTest.java | 147 +++++++++++++++++++++
.../apache/druid/query/filter/OrDimFilterTest.java | 35 +++++
.../TrueDimFilterTest.java} | 38 +++---
.../builtin/ArrayOverlapOperatorConversion.java | 3 +-
.../calcite/filtration/ConvertSelectorsToIns.java | 4 +-
.../druid/sql/calcite/filtration/Filtration.java | 12 +-
31 files changed, 532 insertions(+), 241 deletions(-)
diff --git
a/core/src/main/java/org/apache/druid/common/config/NullHandling.java
b/core/src/main/java/org/apache/druid/common/config/NullHandling.java
index bd0f0ee..51cb265 100644
--- a/core/src/main/java/org/apache/druid/common/config/NullHandling.java
+++ b/core/src/main/java/org/apache/druid/common/config/NullHandling.java
@@ -94,6 +94,11 @@ public class NullHandling
//CHECKSTYLE.ON: Regexp
}
+ public static boolean needsEmptyToNull(@Nullable String value)
+ {
+ return replaceWithDefault() && Strings.isNullOrEmpty(value);
+ }
+
@Nullable
public static String defaultStringValue()
{
diff --git
a/indexing-service/src/test/java/org/apache/druid/indexing/firehose/IngestSegmentFirehoseFactoryTimelineTest.java
b/indexing-service/src/test/java/org/apache/druid/indexing/firehose/IngestSegmentFirehoseFactoryTimelineTest.java
index 7c2760c..e8dff5d 100644
---
a/indexing-service/src/test/java/org/apache/druid/indexing/firehose/IngestSegmentFirehoseFactoryTimelineTest.java
+++
b/indexing-service/src/test/java/org/apache/druid/indexing/firehose/IngestSegmentFirehoseFactoryTimelineTest.java
@@ -348,7 +348,7 @@ public class IngestSegmentFirehoseFactoryTimelineTest
DATA_SOURCE,
testCase.interval,
null,
- new TrueDimFilter(),
+ TrueDimFilter.instance(),
Arrays.asList(DIMENSIONS),
Arrays.asList(METRICS),
// Split as much as possible
diff --git a/processing/src/main/java/org/apache/druid/query/Druids.java
b/processing/src/main/java/org/apache/druid/query/Druids.java
index 1dcd076..522f26b 100644
--- a/processing/src/main/java/org/apache/druid/query/Druids.java
+++ b/processing/src/main/java/org/apache/druid/query/Druids.java
@@ -23,7 +23,7 @@ import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
import org.apache.druid.java.util.common.granularity.Granularities;
import org.apache.druid.java.util.common.granularity.Granularity;
import org.apache.druid.query.aggregation.AggregatorFactory;
@@ -58,6 +58,7 @@ import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
*/
@@ -202,7 +203,9 @@ public class Druids
public TimeseriesQueryBuilder filters(String dimensionName, String value,
String... values)
{
- dimFilter = new InDimFilter(dimensionName, Lists.asList(value, values),
null, null);
+ final Set<String> filterValues = Sets.newHashSet(values);
+ filterValues.add(value);
+ dimFilter = new InDimFilter(dimensionName, filterValues, null, null);
return this;
}
diff --git
a/processing/src/main/java/org/apache/druid/query/filter/AndDimFilter.java
b/processing/src/main/java/org/apache/druid/query/filter/AndDimFilter.java
index 682c247..18df9d6 100644
--- a/processing/src/main/java/org/apache/druid/query/filter/AndDimFilter.java
+++ b/processing/src/main/java/org/apache/druid/query/filter/AndDimFilter.java
@@ -33,6 +33,7 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.stream.Collectors;
/**
*/
@@ -72,8 +73,20 @@ public class AndDimFilter implements DimFilter
@Override
public DimFilter optimize()
{
- List<DimFilter> elements = DimFilters.optimize(fields);
- return elements.size() == 1 ? elements.get(0) : new AndDimFilter(elements);
+ List<DimFilter> elements = DimFilters.optimize(fields)
+ .stream()
+ .filter(filter -> !(filter instanceof
TrueDimFilter))
+ .collect(Collectors.toList());
+ if (elements.isEmpty()) {
+ // All elements were TrueDimFilter after optimization
+ return TrueDimFilter.instance();
+ } else if (elements.size() == 1) {
+ return elements.get(0);
+ } else if (elements.stream().anyMatch(filter -> filter instanceof
FalseDimFilter)) {
+ return FalseDimFilter.instance();
+ } else {
+ return new AndDimFilter(elements);
+ }
}
@Override
diff --git
a/processing/src/main/java/org/apache/druid/query/filter/DimFilter.java
b/processing/src/main/java/org/apache/druid/query/filter/DimFilter.java
index 7688d36..6a38457 100644
--- a/processing/src/main/java/org/apache/druid/query/filter/DimFilter.java
+++ b/processing/src/main/java/org/apache/druid/query/filter/DimFilter.java
@@ -47,7 +47,8 @@ import java.util.Set;
@JsonSubTypes.Type(name = "interval", value = IntervalDimFilter.class),
@JsonSubTypes.Type(name = "like", value = LikeDimFilter.class),
@JsonSubTypes.Type(name = "expression", value = ExpressionDimFilter.class),
- @JsonSubTypes.Type(name = "true", value = TrueDimFilter.class)
+ @JsonSubTypes.Type(name = "true", value = TrueDimFilter.class),
+ @JsonSubTypes.Type(name = "false", value = FalseDimFilter.class)
})
public interface DimFilter extends Cacheable
{
@@ -78,6 +79,7 @@ public interface DimFilter extends Cacheable
* @return a RangeSet that represent the possible range of the input
dimension, or null if it is not possible to
* determine for this DimFilter.
*/
+ @Nullable
RangeSet<String> getDimensionRangeSet(String dimension);
/**
diff --git
a/processing/src/main/java/org/apache/druid/query/filter/DimFilterUtils.java
b/processing/src/main/java/org/apache/druid/query/filter/DimFilterUtils.java
index c980adb..3fcd719 100644
--- a/processing/src/main/java/org/apache/druid/query/filter/DimFilterUtils.java
+++ b/processing/src/main/java/org/apache/druid/query/filter/DimFilterUtils.java
@@ -52,6 +52,7 @@ public class DimFilterUtils
static final byte COLUMN_COMPARISON_CACHE_ID = 0xD;
static final byte EXPRESSION_CACHE_ID = 0xE;
static final byte TRUE_CACHE_ID = 0xF;
+ static final byte FALSE_CACHE_ID = 0x11;
public static final byte BLOOM_DIM_FILTER_CACHE_ID = 0x10;
public static final byte STRING_SEPARATOR = (byte) 0xFF;
diff --git
a/processing/src/main/java/org/apache/druid/query/filter/TrueDimFilter.java
b/processing/src/main/java/org/apache/druid/query/filter/FalseDimFilter.java
similarity index 59%
copy from
processing/src/main/java/org/apache/druid/query/filter/TrueDimFilter.java
copy to
processing/src/main/java/org/apache/druid/query/filter/FalseDimFilter.java
index 2254358..4b21e5e 100644
--- a/processing/src/main/java/org/apache/druid/query/filter/TrueDimFilter.java
+++ b/processing/src/main/java/org/apache/druid/query/filter/FalseDimFilter.java
@@ -19,21 +19,29 @@
package org.apache.druid.query.filter;
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.google.common.collect.ImmutableRangeSet;
import com.google.common.collect.RangeSet;
import org.apache.druid.query.cache.CacheKeyBuilder;
-import org.apache.druid.segment.filter.TrueFilter;
+import org.apache.druid.segment.filter.FalseFilter;
+import javax.annotation.Nullable;
import java.util.Collections;
import java.util.Set;
-/**
- */
-public class TrueDimFilter implements DimFilter
+public class FalseDimFilter implements DimFilter
{
- @Override
- public byte[] getCacheKey()
+ private static final FalseDimFilter INSTANCE = new FalseDimFilter();
+ private static final byte[] CACHE_KEY = new
CacheKeyBuilder(DimFilterUtils.FALSE_CACHE_ID).build();
+
+ @JsonCreator
+ public static FalseDimFilter instance()
+ {
+ return INSTANCE;
+ }
+
+ private FalseDimFilter()
{
- return new CacheKeyBuilder(DimFilterUtils.TRUE_CACHE_ID).build();
}
@Override
@@ -45,13 +53,14 @@ public class TrueDimFilter implements DimFilter
@Override
public Filter toFilter()
{
- return TrueFilter.instance();
+ return FalseFilter.instance();
}
+ @Nullable
@Override
public RangeSet<String> getDimensionRangeSet(String dimension)
{
- return null;
+ return ImmutableRangeSet.of();
}
@Override
@@ -59,4 +68,28 @@ public class TrueDimFilter implements DimFilter
{
return Collections.emptySet();
}
+
+ @Override
+ public byte[] getCacheKey()
+ {
+ return CACHE_KEY;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return DimFilterUtils.FALSE_CACHE_ID;
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ return o != null && o.getClass() == this.getClass();
+ }
+
+ @Override
+ public String toString()
+ {
+ return "FALSE";
+ }
}
diff --git
a/processing/src/main/java/org/apache/druid/query/filter/InDimFilter.java
b/processing/src/main/java/org/apache/druid/query/filter/InDimFilter.java
index d97d086..d5ec558 100644
--- a/processing/src/main/java/org/apache/druid/query/filter/InDimFilter.java
+++ b/processing/src/main/java/org/apache/druid/query/filter/InDimFilter.java
@@ -20,6 +20,7 @@
package org.apache.druid.query.filter;
import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.annotations.VisibleForTesting;
@@ -29,16 +30,18 @@ import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
+import com.google.common.collect.Ordering;
import com.google.common.collect.Range;
import com.google.common.collect.RangeSet;
import com.google.common.collect.TreeRangeSet;
+import com.google.common.hash.Hasher;
+import com.google.common.hash.Hashing;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import org.apache.druid.common.config.NullHandling;
import org.apache.druid.java.util.common.StringUtils;
-import org.apache.druid.java.util.common.guava.Comparators;
import org.apache.druid.query.cache.CacheKeyBuilder;
import org.apache.druid.query.extraction.ExtractionFn;
import org.apache.druid.query.lookup.LookupExtractionFn;
@@ -47,14 +50,16 @@ import org.apache.druid.segment.DimensionHandlerUtils;
import org.apache.druid.segment.filter.InFilter;
import javax.annotation.Nullable;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
+import java.util.stream.Collectors;
public class InDimFilter implements DimFilter
{
@@ -63,7 +68,7 @@ public class InDimFilter implements DimFilter
public static final int NUMERIC_HASHING_THRESHOLD = 16;
// Values can contain `null` object
- private final SortedSet<String> values;
+ private final Set<String> values;
private final String dimension;
@Nullable
private final ExtractionFn extractionFn;
@@ -73,10 +78,15 @@ public class InDimFilter implements DimFilter
private final Supplier<DruidFloatPredicate> floatPredicateSupplier;
private final Supplier<DruidDoublePredicate> doublePredicateSupplier;
+ @JsonIgnore
+ private byte[] cacheKey;
+
@JsonCreator
public InDimFilter(
@JsonProperty("dimension") String dimension,
- @JsonProperty("values") Collection<String> values,
+ // This 'values' collection instance can be reused if possible to avoid
copying a big collection.
+ // Callers should _not_ modify the collection after it is passed to this
constructor.
+ @JsonProperty("values") Set<String> values,
@JsonProperty("extractionFn") @Nullable ExtractionFn extractionFn,
@JsonProperty("filterTuning") @Nullable FilterTuning filterTuning
)
@@ -84,9 +94,12 @@ public class InDimFilter implements DimFilter
Preconditions.checkNotNull(dimension, "dimension can not be null");
Preconditions.checkArgument(values != null, "values can not be null");
- this.values = new TreeSet<>(Comparators.naturalNullsFirst());
- for (String value : values) {
- this.values.add(NullHandling.emptyToNullIfNeeded(value));
+ // The values set can be huge. Try to avoid copying the set if possible.
+ // Note that we may still need to copy values to a list for caching. See
getCacheKey().
+ if ((NullHandling.sqlCompatible() ||
values.stream().noneMatch(NullHandling::needsEmptyToNull))) {
+ this.values = values;
+ } else {
+ this.values =
values.stream().map(NullHandling::emptyToNullIfNeeded).collect(Collectors.toSet());
}
this.dimension = dimension;
this.extractionFn = extractionFn;
@@ -96,10 +109,13 @@ public class InDimFilter implements DimFilter
this.doublePredicateSupplier = getDoublePredicateSupplier();
}
+ /**
+ * This constructor should be called only in unit tests since it creates a
new hash set wrapping the given values.
+ */
@VisibleForTesting
public InDimFilter(String dimension, Collection<String> values, @Nullable
ExtractionFn extractionFn)
{
- this(dimension, values, extractionFn, null);
+ this(dimension, new HashSet<>(values), extractionFn, null);
}
@JsonProperty
@@ -115,6 +131,7 @@ public class InDimFilter implements DimFilter
}
@Nullable
+ @JsonInclude(JsonInclude.Include.NON_NULL)
@JsonProperty
public ExtractionFn getExtractionFn()
{
@@ -132,31 +149,40 @@ public class InDimFilter implements DimFilter
@Override
public byte[] getCacheKey()
{
- boolean hasNull = false;
- for (String value : values) {
- if (value == null) {
- hasNull = true;
- break;
+ if (cacheKey == null) {
+ final List<String> sortedValues = new ArrayList<>(values);
+ sortedValues.sort(Comparator.nullsFirst(Ordering.natural()));
+ final Hasher hasher = Hashing.sha256().newHasher();
+ for (String v : sortedValues) {
+ if (v == null) {
+ hasher.putInt(0);
+ } else {
+ hasher.putString(v, StandardCharsets.UTF_8);
+ }
}
+ cacheKey = new CacheKeyBuilder(DimFilterUtils.IN_CACHE_ID)
+ .appendString(dimension)
+ .appendByte(DimFilterUtils.STRING_SEPARATOR)
+ .appendByteArray(extractionFn == null ? new byte[0] :
extractionFn.getCacheKey())
+ .appendByte(DimFilterUtils.STRING_SEPARATOR)
+ .appendByteArray(hasher.hash().asBytes())
+ .build();
}
- return new CacheKeyBuilder(DimFilterUtils.IN_CACHE_ID)
- .appendString(dimension)
- .appendByte(DimFilterUtils.STRING_SEPARATOR)
- .appendByteArray(extractionFn == null ? new byte[0] :
extractionFn.getCacheKey())
- .appendByte(DimFilterUtils.STRING_SEPARATOR)
- .appendByte(hasNull ? NullHandling.IS_NULL_BYTE :
NullHandling.IS_NOT_NULL_BYTE)
- .appendByte(DimFilterUtils.STRING_SEPARATOR)
- .appendStrings(values).build();
+ return cacheKey;
}
@Override
public DimFilter optimize()
{
InDimFilter inFilter = optimizeLookup();
+
+ if (inFilter.values.isEmpty()) {
+ return FalseDimFilter.instance();
+ }
if (inFilter.values.size() == 1) {
return new SelectorDimFilter(
inFilter.dimension,
- inFilter.values.first(),
+ inFilter.values.iterator().next(),
inFilter.getExtractionFn(),
filterTuning
);
@@ -171,7 +197,7 @@ public class InDimFilter implements DimFilter
LookupExtractionFn exFn = (LookupExtractionFn) extractionFn;
LookupExtractor lookup = exFn.getLookup();
- final List<String> keys = new ArrayList<>();
+ final Set<String> keys = new HashSet<>();
for (String value : values) {
// We cannot do an unapply()-based optimization if the selector value
@@ -215,6 +241,7 @@ public class InDimFilter implements DimFilter
);
}
+ @Nullable
@Override
public RangeSet<String> getDimensionRangeSet(String dimension)
{
@@ -302,7 +329,7 @@ public class InDimFilter implements DimFilter
// This supplier must be thread-safe, since this DimFilter will be accessed
in the query runners.
private Supplier<DruidLongPredicate> getLongPredicateSupplier()
{
- Supplier<DruidLongPredicate> longPredicate = () -> createLongPredicate();
+ Supplier<DruidLongPredicate> longPredicate = this::createLongPredicate;
return Suppliers.memoize(longPredicate);
}
@@ -330,7 +357,7 @@ public class InDimFilter implements DimFilter
private Supplier<DruidFloatPredicate> getFloatPredicateSupplier()
{
- Supplier<DruidFloatPredicate> floatPredicate = () ->
createFloatPredicate();
+ Supplier<DruidFloatPredicate> floatPredicate = this::createFloatPredicate;
return Suppliers.memoize(floatPredicate);
}
@@ -358,7 +385,7 @@ public class InDimFilter implements DimFilter
private Supplier<DruidDoublePredicate> getDoublePredicateSupplier()
{
- Supplier<DruidDoublePredicate> doublePredicate = () ->
createDoublePredicate();
+ Supplier<DruidDoublePredicate> doublePredicate =
this::createDoublePredicate;
return Suppliers.memoize(doublePredicate);
}
}
diff --git
a/processing/src/main/java/org/apache/druid/query/filter/NotDimFilter.java
b/processing/src/main/java/org/apache/druid/query/filter/NotDimFilter.java
index 039667e..0cd2969 100644
--- a/processing/src/main/java/org/apache/druid/query/filter/NotDimFilter.java
+++ b/processing/src/main/java/org/apache/druid/query/filter/NotDimFilter.java
@@ -60,10 +60,17 @@ public class NotDimFilter implements DimFilter
return ByteBuffer.allocate(1 +
subKey.length).put(DimFilterUtils.NOT_CACHE_ID).put(subKey).array();
}
+ @SuppressWarnings("ObjectEquality")
@Override
public DimFilter optimize()
{
- return new NotDimFilter(this.getField().optimize());
+ final DimFilter optimized = this.getField().optimize();
+ if (optimized == FalseDimFilter.instance()) {
+ return TrueDimFilter.instance();
+ } else if (optimized == TrueDimFilter.instance()) {
+ return FalseDimFilter.instance();
+ }
+ return new NotDimFilter(optimized);
}
@Override
diff --git
a/processing/src/main/java/org/apache/druid/query/filter/OrDimFilter.java
b/processing/src/main/java/org/apache/druid/query/filter/OrDimFilter.java
index 762ad72..ca8c105 100644
--- a/processing/src/main/java/org/apache/druid/query/filter/OrDimFilter.java
+++ b/processing/src/main/java/org/apache/druid/query/filter/OrDimFilter.java
@@ -34,6 +34,7 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.stream.Collectors;
/**
*/
@@ -44,9 +45,7 @@ public class OrDimFilter implements DimFilter
private final List<DimFilter> fields;
@JsonCreator
- public OrDimFilter(
- @JsonProperty("fields") List<DimFilter> fields
- )
+ public OrDimFilter(@JsonProperty("fields") List<DimFilter> fields)
{
fields = DimFilters.filterNulls(fields);
Preconditions.checkArgument(fields.size() > 0, "OR operator requires at
least one field");
@@ -82,8 +81,20 @@ public class OrDimFilter implements DimFilter
@Override
public DimFilter optimize()
{
- List<DimFilter> elements = DimFilters.optimize(fields);
- return elements.size() == 1 ? elements.get(0) : new OrDimFilter(elements);
+ List<DimFilter> elements = DimFilters.optimize(fields)
+ .stream()
+ .filter(filter -> !(filter instanceof
FalseDimFilter))
+ .collect(Collectors.toList());
+ if (elements.isEmpty()) {
+ // All elements were FalseDimFilter after optimization
+ return FalseDimFilter.instance();
+ } else if (elements.size() == 1) {
+ return elements.get(0);
+ } else if (elements.stream().anyMatch(filter -> filter instanceof
TrueDimFilter)) {
+ return TrueDimFilter.instance();
+ } else {
+ return new OrDimFilter(elements);
+ }
}
@Override
diff --git
a/processing/src/main/java/org/apache/druid/query/filter/SelectorDimFilter.java
b/processing/src/main/java/org/apache/druid/query/filter/SelectorDimFilter.java
index 91ec334..d27f413 100644
---
a/processing/src/main/java/org/apache/druid/query/filter/SelectorDimFilter.java
+++
b/processing/src/main/java/org/apache/druid/query/filter/SelectorDimFilter.java
@@ -96,7 +96,7 @@ public class SelectorDimFilter implements DimFilter
@Override
public DimFilter optimize()
{
- return new InDimFilter(dimension, Collections.singletonList(value),
extractionFn, filterTuning).optimize();
+ return new InDimFilter(dimension, Collections.singleton(value),
extractionFn, filterTuning).optimize();
}
@Override
diff --git
a/processing/src/main/java/org/apache/druid/query/filter/TrueDimFilter.java
b/processing/src/main/java/org/apache/druid/query/filter/TrueDimFilter.java
index 2254358..af29710 100644
--- a/processing/src/main/java/org/apache/druid/query/filter/TrueDimFilter.java
+++ b/processing/src/main/java/org/apache/druid/query/filter/TrueDimFilter.java
@@ -19,6 +19,7 @@
package org.apache.druid.query.filter;
+import com.fasterxml.jackson.annotation.JsonCreator;
import com.google.common.collect.RangeSet;
import org.apache.druid.query.cache.CacheKeyBuilder;
import org.apache.druid.segment.filter.TrueFilter;
@@ -26,14 +27,25 @@ import org.apache.druid.segment.filter.TrueFilter;
import java.util.Collections;
import java.util.Set;
-/**
- */
public class TrueDimFilter implements DimFilter
{
+ private static final TrueDimFilter INSTANCE = new TrueDimFilter();
+ private static final byte[] CACHE_KEY = new
CacheKeyBuilder(DimFilterUtils.TRUE_CACHE_ID).build();
+
+ @JsonCreator
+ public static TrueDimFilter instance()
+ {
+ return INSTANCE;
+ }
+
+ private TrueDimFilter()
+ {
+ }
+
@Override
public byte[] getCacheKey()
{
- return new CacheKeyBuilder(DimFilterUtils.TRUE_CACHE_ID).build();
+ return CACHE_KEY;
}
@Override
@@ -59,4 +71,22 @@ public class TrueDimFilter implements DimFilter
{
return Collections.emptySet();
}
+
+ @Override
+ public int hashCode()
+ {
+ return DimFilterUtils.TRUE_CACHE_ID;
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ return o != null && o.getClass() == this.getClass();
+ }
+
+ @Override
+ public String toString()
+ {
+ return "TRUE";
+ }
}
diff --git
a/processing/src/main/java/org/apache/druid/query/filter/TrueDimFilter.java
b/processing/src/main/java/org/apache/druid/query/filter/vector/FalseVectorMatcher.java
similarity index 56%
copy from
processing/src/main/java/org/apache/druid/query/filter/TrueDimFilter.java
copy to
processing/src/main/java/org/apache/druid/query/filter/vector/FalseVectorMatcher.java
index 2254358..9d20c1d 100644
--- a/processing/src/main/java/org/apache/druid/query/filter/TrueDimFilter.java
+++
b/processing/src/main/java/org/apache/druid/query/filter/vector/FalseVectorMatcher.java
@@ -17,46 +17,34 @@
* under the License.
*/
-package org.apache.druid.query.filter;
+package org.apache.druid.query.filter.vector;
-import com.google.common.collect.RangeSet;
-import org.apache.druid.query.cache.CacheKeyBuilder;
-import org.apache.druid.segment.filter.TrueFilter;
+import org.apache.druid.segment.vector.VectorSizeInspector;
-import java.util.Collections;
-import java.util.Set;
-
-/**
- */
-public class TrueDimFilter implements DimFilter
+public class FalseVectorMatcher implements VectorValueMatcher
{
- @Override
- public byte[] getCacheKey()
- {
- return new CacheKeyBuilder(DimFilterUtils.TRUE_CACHE_ID).build();
- }
+ private final VectorSizeInspector vectorSizeInspector;
- @Override
- public DimFilter optimize()
+ public FalseVectorMatcher(VectorSizeInspector vectorSizeInspector)
{
- return this;
+ this.vectorSizeInspector = vectorSizeInspector;
}
@Override
- public Filter toFilter()
+ public ReadableVectorMatch match(ReadableVectorMatch mask)
{
- return TrueFilter.instance();
+ return VectorMatch.allFalse();
}
@Override
- public RangeSet<String> getDimensionRangeSet(String dimension)
+ public int getMaxVectorSize()
{
- return null;
+ return vectorSizeInspector.getMaxVectorSize();
}
@Override
- public Set<String> getRequiredColumns()
+ public int getCurrentVectorSize()
{
- return Collections.emptySet();
+ return vectorSizeInspector.getCurrentVectorSize();
}
}
diff --git
a/processing/src/main/java/org/apache/druid/query/filter/TrueDimFilter.java
b/processing/src/main/java/org/apache/druid/query/filter/vector/TrueVectorMatcher.java
similarity index 56%
copy from
processing/src/main/java/org/apache/druid/query/filter/TrueDimFilter.java
copy to
processing/src/main/java/org/apache/druid/query/filter/vector/TrueVectorMatcher.java
index 2254358..24b2b27 100644
--- a/processing/src/main/java/org/apache/druid/query/filter/TrueDimFilter.java
+++
b/processing/src/main/java/org/apache/druid/query/filter/vector/TrueVectorMatcher.java
@@ -17,46 +17,35 @@
* under the License.
*/
-package org.apache.druid.query.filter;
+package org.apache.druid.query.filter.vector;
-import com.google.common.collect.RangeSet;
-import org.apache.druid.query.cache.CacheKeyBuilder;
-import org.apache.druid.segment.filter.TrueFilter;
+import org.apache.druid.segment.vector.VectorSizeInspector;
-import java.util.Collections;
-import java.util.Set;
-
-/**
- */
-public class TrueDimFilter implements DimFilter
+public class TrueVectorMatcher implements VectorValueMatcher
{
- @Override
- public byte[] getCacheKey()
- {
- return new CacheKeyBuilder(DimFilterUtils.TRUE_CACHE_ID).build();
- }
+ private final VectorSizeInspector vectorSizeInspector;
- @Override
- public DimFilter optimize()
+ public TrueVectorMatcher(VectorSizeInspector vectorSizeInspector)
{
- return this;
+ this.vectorSizeInspector = vectorSizeInspector;
}
@Override
- public Filter toFilter()
+ public ReadableVectorMatch match(ReadableVectorMatch mask)
{
- return TrueFilter.instance();
+ // The given mask is all true for its valid selections.
+ return mask;
}
@Override
- public RangeSet<String> getDimensionRangeSet(String dimension)
+ public int getMaxVectorSize()
{
- return null;
+ return vectorSizeInspector.getMaxVectorSize();
}
@Override
- public Set<String> getRequiredColumns()
+ public int getCurrentVectorSize()
{
- return Collections.emptySet();
+ return vectorSizeInspector.getCurrentVectorSize();
}
}
diff --git
a/processing/src/main/java/org/apache/druid/query/topn/TopNQueryBuilder.java
b/processing/src/main/java/org/apache/druid/query/topn/TopNQueryBuilder.java
index d50c565..c6715df 100644
--- a/processing/src/main/java/org/apache/druid/query/topn/TopNQueryBuilder.java
+++ b/processing/src/main/java/org/apache/druid/query/topn/TopNQueryBuilder.java
@@ -19,7 +19,7 @@
package org.apache.druid.query.topn;
-import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
import org.apache.druid.java.util.common.granularity.Granularities;
import org.apache.druid.java.util.common.granularity.Granularity;
import org.apache.druid.query.DataSource;
@@ -42,6 +42,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* A Builder for TopNQuery.
@@ -230,7 +231,9 @@ public class TopNQueryBuilder
public TopNQueryBuilder filters(String dimensionName, String value,
String... values)
{
- dimFilter = new InDimFilter(dimensionName, Lists.asList(value, values),
null, null);
+ final Set<String> filterValues = Sets.newHashSet(values);
+ filterValues.add(value);
+ dimFilter = new InDimFilter(dimensionName, filterValues, null, null);
return this;
}
diff --git
a/processing/src/main/java/org/apache/druid/segment/filter/FalseFilter.java
b/processing/src/main/java/org/apache/druid/segment/filter/FalseFilter.java
index e143b70..902dae4 100644
--- a/processing/src/main/java/org/apache/druid/segment/filter/FalseFilter.java
+++ b/processing/src/main/java/org/apache/druid/segment/filter/FalseFilter.java
@@ -23,8 +23,11 @@ import org.apache.druid.query.BitmapResultFactory;
import org.apache.druid.query.filter.BitmapIndexSelector;
import org.apache.druid.query.filter.Filter;
import org.apache.druid.query.filter.ValueMatcher;
+import org.apache.druid.query.filter.vector.FalseVectorMatcher;
+import org.apache.druid.query.filter.vector.VectorValueMatcher;
import org.apache.druid.segment.ColumnSelector;
import org.apache.druid.segment.ColumnSelectorFactory;
+import org.apache.druid.segment.vector.VectorColumnSelectorFactory;
import java.util.Collections;
import java.util.Set;
@@ -61,6 +64,12 @@ public class FalseFilter implements Filter
}
@Override
+ public VectorValueMatcher makeVectorMatcher(VectorColumnSelectorFactory
factory)
+ {
+ return new FalseVectorMatcher(factory.getVectorSizeInspector());
+ }
+
+ @Override
public boolean supportsBitmapIndex(BitmapIndexSelector selector)
{
return true;
@@ -79,6 +88,12 @@ public class FalseFilter implements Filter
}
@Override
+ public boolean canVectorizeMatcher()
+ {
+ return true;
+ }
+
+ @Override
public Set<String> getRequiredColumns()
{
return Collections.emptySet();
diff --git
a/processing/src/main/java/org/apache/druid/segment/filter/InFilter.java
b/processing/src/main/java/org/apache/druid/segment/filter/InFilter.java
index 6e1da91..d609a54 100644
--- a/processing/src/main/java/org/apache/druid/segment/filter/InFilter.java
+++ b/processing/src/main/java/org/apache/druid/segment/filter/InFilter.java
@@ -54,6 +54,11 @@ import java.util.Set;
* given {@link #values}.
* For multi-valued dimension, this filter returns true if one of the
dimension values matches to one of the
* given {@link #values}.
+ *
+ * In SQL-compatible null handling mode, this filter is equivalent to {@code
(dimension IN [values])} or
+ * {@code (dimension IN [non-null values] OR dimension IS NULL)} when {@link
#values} contains nulls.
+ * In default null handling mode, this filter is equivalent to {@code
(dimension IN [values])} or
+ * {@code (dimension IN [non-null values, ''])} when {@link #values} contains
nulls.
*/
public class InFilter implements Filter
{
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 7587427..f56bfac 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
@@ -38,6 +38,11 @@ import java.util.Objects;
import java.util.Set;
/**
+ * This filter is to select the rows where the {@link #dimension} has the
{@link #value}. The value can be null.
+ * In SQL-compatible null handling mode, this filter is equivalent to {@code
dimension = value}
+ * or {@code dimension IS NULL} when the value is null.
+ * In default null handling mode, this filter is equivalent to {@code
dimension = value} or
+ * {@code dimension = ''} when the value is null.
*/
public class SelectorFilter implements Filter
{
diff --git
a/processing/src/main/java/org/apache/druid/segment/filter/TrueFilter.java
b/processing/src/main/java/org/apache/druid/segment/filter/TrueFilter.java
index 58cda8c..bb35b4f 100644
--- a/processing/src/main/java/org/apache/druid/segment/filter/TrueFilter.java
+++ b/processing/src/main/java/org/apache/druid/segment/filter/TrueFilter.java
@@ -23,8 +23,11 @@ import org.apache.druid.query.BitmapResultFactory;
import org.apache.druid.query.filter.BitmapIndexSelector;
import org.apache.druid.query.filter.Filter;
import org.apache.druid.query.filter.ValueMatcher;
+import org.apache.druid.query.filter.vector.TrueVectorMatcher;
+import org.apache.druid.query.filter.vector.VectorValueMatcher;
import org.apache.druid.segment.ColumnSelector;
import org.apache.druid.segment.ColumnSelectorFactory;
+import org.apache.druid.segment.vector.VectorColumnSelectorFactory;
import java.util.Collections;
import java.util.Set;
@@ -57,6 +60,12 @@ public class TrueFilter implements Filter
}
@Override
+ public VectorValueMatcher makeVectorMatcher(VectorColumnSelectorFactory
factory)
+ {
+ return new TrueVectorMatcher(factory.getVectorSizeInspector());
+ }
+
+ @Override
public boolean supportsBitmapIndex(BitmapIndexSelector selector)
{
return true;
@@ -75,6 +84,12 @@ public class TrueFilter implements Filter
}
@Override
+ public boolean canVectorizeMatcher()
+ {
+ return true;
+ }
+
+ @Override
public Set<String> getRequiredColumns()
{
return Collections.emptySet();
diff --git
a/processing/src/main/java/org/apache/druid/segment/vector/QueryableIndexVectorColumnSelectorFactory.java
b/processing/src/main/java/org/apache/druid/segment/vector/QueryableIndexVectorColumnSelectorFactory.java
index d816589..b9cfe4f 100644
---
a/processing/src/main/java/org/apache/druid/segment/vector/QueryableIndexVectorColumnSelectorFactory.java
+++
b/processing/src/main/java/org/apache/druid/segment/vector/QueryableIndexVectorColumnSelectorFactory.java
@@ -66,9 +66,9 @@ public class QueryableIndexVectorColumnSelectorFactory
implements VectorColumnSe
}
@Override
- public int getMaxVectorSize()
+ public VectorSizeInspector getVectorSizeInspector()
{
- return offset.getMaxVectorSize();
+ return offset;
}
@Override
diff --git
a/processing/src/main/java/org/apache/druid/segment/vector/VectorColumnSelectorFactory.java
b/processing/src/main/java/org/apache/druid/segment/vector/VectorColumnSelectorFactory.java
index 1634cc6..bea845f 100644
---
a/processing/src/main/java/org/apache/druid/segment/vector/VectorColumnSelectorFactory.java
+++
b/processing/src/main/java/org/apache/druid/segment/vector/VectorColumnSelectorFactory.java
@@ -32,11 +32,19 @@ import javax.annotation.Nullable;
public interface VectorColumnSelectorFactory
{
/**
+ * Returns a {@link VectorSizeInspector} for the {@link VectorCursor} that
generated this object.
+ */
+ VectorSizeInspector getVectorSizeInspector();
+
+ /**
* Returns the maximum vector size for the {@link VectorCursor} that
generated this object.
*
* @see VectorCursor#getMaxVectorSize()
*/
- int getMaxVectorSize();
+ default int getMaxVectorSize()
+ {
+ return getVectorSizeInspector().getMaxVectorSize();
+ }
/**
* Returns a string-typed, single-value-per-row column selector.
diff --git
a/processing/src/test/java/org/apache/druid/query/aggregation/FilteredAggregatorFactoryTest.java
b/processing/src/test/java/org/apache/druid/query/aggregation/FilteredAggregatorFactoryTest.java
index 4db7b0e..879a252 100644
---
a/processing/src/test/java/org/apache/druid/query/aggregation/FilteredAggregatorFactoryTest.java
+++
b/processing/src/test/java/org/apache/druid/query/aggregation/FilteredAggregatorFactoryTest.java
@@ -30,17 +30,17 @@ public class FilteredAggregatorFactoryTest
{
Assert.assertEquals("overrideName", new FilteredAggregatorFactory(
new CountAggregatorFactory("foo"),
- new TrueDimFilter(),
+ TrueDimFilter.instance(),
"overrideName"
).getName());
Assert.assertEquals("delegateName", new FilteredAggregatorFactory(
new CountAggregatorFactory("delegateName"),
- new TrueDimFilter(),
+ TrueDimFilter.instance(),
""
).getName());
Assert.assertEquals("delegateName", new FilteredAggregatorFactory(
new CountAggregatorFactory("delegateName"),
- new TrueDimFilter(),
+ TrueDimFilter.instance(),
null
).getName());
}
diff --git
a/processing/src/test/java/org/apache/druid/query/filter/AndDimFilterTest.java
b/processing/src/test/java/org/apache/druid/query/filter/AndDimFilterTest.java
index 7aeae01..e45ed29 100644
---
a/processing/src/test/java/org/apache/druid/query/filter/AndDimFilterTest.java
+++
b/processing/src/test/java/org/apache/druid/query/filter/AndDimFilterTest.java
@@ -65,4 +65,39 @@ public class AndDimFilterTest extends
InitializedNullHandlingTest
);
Assert.assertEquals(expected, dimFilter.toFilter());
}
+
+ @Test
+ public void testOptimieShortCircuitWithFalseFilter()
+ {
+ DimFilter filter = DimFilterTestUtils.and(
+ DimFilterTestUtils.selector("col1", "1"),
+ FalseDimFilter.instance()
+ );
+ Assert.assertTrue(filter.optimize() instanceof FalseDimFilter);
+ }
+
+ @Test
+ public void testOptimizeOringTrueFilters()
+ {
+ DimFilter filter = DimFilterTestUtils.and(TrueDimFilter.instance(),
TrueDimFilter.instance());
+ Assert.assertSame(TrueDimFilter.instance(), filter.optimize());
+ }
+
+ @Test
+ public void testOptimizeAndOfSingleFilterUnwrapAnd()
+ {
+ DimFilter expected = DimFilterTestUtils.selector("col1", "1");
+ DimFilter filter = DimFilterTestUtils.and(expected);
+ Assert.assertEquals(expected, filter.optimize());
+ }
+
+ @Test
+ public void testOptimizeAndOfMultipleFiltersReturningAsItIs()
+ {
+ DimFilter filter = DimFilterTestUtils.and(
+ DimFilterTestUtils.selector("col1", "1"),
+ DimFilterTestUtils.selector("col1", "2")
+ );
+ Assert.assertEquals(filter, filter.optimize());
+ }
}
diff --git
a/processing/src/test/java/org/apache/druid/query/aggregation/FilteredAggregatorFactoryTest.java
b/processing/src/test/java/org/apache/druid/query/filter/FalseDimFilterTest.java
similarity index 54%
copy from
processing/src/test/java/org/apache/druid/query/aggregation/FilteredAggregatorFactoryTest.java
copy to
processing/src/test/java/org/apache/druid/query/filter/FalseDimFilterTest.java
index 4db7b0e..a512bca 100644
---
a/processing/src/test/java/org/apache/druid/query/aggregation/FilteredAggregatorFactoryTest.java
+++
b/processing/src/test/java/org/apache/druid/query/filter/FalseDimFilterTest.java
@@ -17,31 +17,31 @@
* under the License.
*/
-package org.apache.druid.query.aggregation;
+package org.apache.druid.query.filter;
-import org.apache.druid.query.filter.TrueDimFilter;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import nl.jqno.equalsverifier.EqualsVerifier;
+import org.apache.druid.jackson.DefaultObjectMapper;
import org.junit.Assert;
import org.junit.Test;
-public class FilteredAggregatorFactoryTest
+import java.io.IOException;
+
+public class FalseDimFilterTest
{
@Test
- public void testSimpleNaming()
+ public void testSerde() throws IOException
+ {
+ final ObjectMapper mapper = new DefaultObjectMapper();
+ final FalseDimFilter original = FalseDimFilter.instance();
+ final byte[] bytes = mapper.writeValueAsBytes(original);
+ final FalseDimFilter fromBytes = (FalseDimFilter) mapper.readValue(bytes,
DimFilter.class);
+ Assert.assertSame(original, fromBytes);
+ }
+
+ @Test
+ public void testEquals()
{
- Assert.assertEquals("overrideName", new FilteredAggregatorFactory(
- new CountAggregatorFactory("foo"),
- new TrueDimFilter(),
- "overrideName"
- ).getName());
- Assert.assertEquals("delegateName", new FilteredAggregatorFactory(
- new CountAggregatorFactory("delegateName"),
- new TrueDimFilter(),
- ""
- ).getName());
- Assert.assertEquals("delegateName", new FilteredAggregatorFactory(
- new CountAggregatorFactory("delegateName"),
- new TrueDimFilter(),
- null
- ).getName());
+ EqualsVerifier.forClass(FalseDimFilter.class).usingGetClass().verify();
}
}
diff --git
a/processing/src/test/java/org/apache/druid/query/filter/InDimFilterSerDesrTest.java
b/processing/src/test/java/org/apache/druid/query/filter/InDimFilterSerDesrTest.java
deleted file mode 100644
index 691769a..0000000
---
a/processing/src/test/java/org/apache/druid/query/filter/InDimFilterSerDesrTest.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.druid.query.filter;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.inject.Injector;
-import com.google.inject.Key;
-import org.apache.druid.guice.GuiceInjectors;
-import org.apache.druid.guice.annotations.Json;
-import org.apache.druid.query.extraction.RegexDimExtractionFn;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Collections;
-
-public class InDimFilterSerDesrTest
-{
- private static ObjectMapper mapper;
-
- private final String serializedFilter =
-
"{\"type\":\"in\",\"dimension\":\"dimTest\",\"values\":[\"bad\",\"good\"],\"extractionFn\":null}";
-
- @Before
- public void setUp()
- {
- Injector defaultInjector = GuiceInjectors.makeStartupInjector();
- mapper = defaultInjector.getInstance(Key.get(ObjectMapper.class,
Json.class));
- }
-
- @Test
- public void testDeserialization() throws IOException
- {
- final InDimFilter actualInDimFilter =
mapper.readerFor(DimFilter.class).readValue(serializedFilter);
- final InDimFilter expectedInDimFilter = new InDimFilter("dimTest",
Arrays.asList("good", "bad"), null);
- Assert.assertEquals(expectedInDimFilter, actualInDimFilter);
- }
-
- @Test
- public void testSerialization() throws IOException
- {
- final InDimFilter dimInFilter = new InDimFilter("dimTest",
Arrays.asList("good", "bad"), null);
- final String actualSerializedFilter =
mapper.writeValueAsString(dimInFilter);
- Assert.assertEquals(serializedFilter, actualSerializedFilter);
- }
-
- @Test
- public void testGetCacheKey()
- {
- final InDimFilter inDimFilter_1 = new InDimFilter("dimTest",
Arrays.asList("good", "bad"), null);
- final InDimFilter inDimFilter_2 = new InDimFilter("dimTest",
Collections.singletonList("good,bad"), null);
- Assert.assertNotEquals(inDimFilter_1.getCacheKey(),
inDimFilter_2.getCacheKey());
-
- RegexDimExtractionFn regexFn = new RegexDimExtractionFn(".*", false, null);
- final InDimFilter inDimFilter_3 = new InDimFilter("dimTest",
Arrays.asList("good", "bad"), regexFn);
- final InDimFilter inDimFilter_4 = new InDimFilter("dimTest",
Collections.singletonList("good,bad"), regexFn);
- Assert.assertNotEquals(inDimFilter_3.getCacheKey(),
inDimFilter_4.getCacheKey());
- }
-
- @Test
- public void testGetCacheKeyNullValue() throws IOException
- {
- InDimFilter inDimFilter =
mapper.readValue("{\"type\":\"in\",\"dimension\":\"dimTest\",\"values\":[null]}",
InDimFilter.class);
- Assert.assertNotNull(inDimFilter.getCacheKey());
- }
-}
diff --git
a/processing/src/test/java/org/apache/druid/query/filter/InDimFilterTest.java
b/processing/src/test/java/org/apache/druid/query/filter/InDimFilterTest.java
new file mode 100644
index 0000000..9cf5b8f
--- /dev/null
+++
b/processing/src/test/java/org/apache/druid/query/filter/InDimFilterTest.java
@@ -0,0 +1,147 @@
+/*
+ * 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.query.filter;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import org.apache.druid.common.config.NullHandling;
+import org.apache.druid.jackson.DefaultObjectMapper;
+import org.apache.druid.query.extraction.RegexDimExtractionFn;
+import org.apache.druid.testing.InitializedNullHandlingTest;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+
+public class InDimFilterTest extends InitializedNullHandlingTest
+{
+ private ObjectMapper mapper = new DefaultObjectMapper();
+
+ private final String serializedFilter =
+
"{\"type\":\"in\",\"dimension\":\"dimTest\",\"values\":[\"bad\",\"good\"]}";
+
+ @Test
+ public void testDeserialization() throws IOException
+ {
+ final InDimFilter actualInDimFilter =
mapper.readerFor(DimFilter.class).readValue(serializedFilter);
+ final InDimFilter expectedInDimFilter = new InDimFilter("dimTest",
Arrays.asList("good", "bad"), null);
+ Assert.assertEquals(expectedInDimFilter, actualInDimFilter);
+ }
+
+ @Test
+ public void testSerialization() throws IOException
+ {
+ final InDimFilter dimInFilter = new InDimFilter("dimTest",
Arrays.asList("good", "bad"), null);
+ final String actualSerializedFilter =
mapper.writeValueAsString(dimInFilter);
+ Assert.assertEquals(serializedFilter, actualSerializedFilter);
+ }
+
+ @Test
+ public void testGetValuesWithValuesSetOfNonEmptyStringsUseTheGivenSet()
+ {
+ final Set<String> values = ImmutableSet.of("v1", "v2", "v3");
+ final InDimFilter filter = new InDimFilter("dim", values, null, null);
+ Assert.assertSame(values, filter.getValues());
+ }
+
+ @Test
+ public void testGetValuesWithValuesSetIncludingEmptyString()
+ {
+ final Set<String> values = Sets.newHashSet("v1", "", "v3");
+ final InDimFilter filter = new InDimFilter("dim", values, null, null);
+ if (NullHandling.replaceWithDefault()) {
+ Assert.assertNotSame(values, filter.getValues());
+ Assert.assertEquals(Sets.newHashSet("v1", null, "v3"),
filter.getValues());
+ } else {
+ Assert.assertSame(values, filter.getValues());
+ }
+ }
+
+ @Test
+ public void testGetCacheKeyReturningSameKeyForValuesOfDifferentOrders()
+ {
+ final InDimFilter dimFilter1 = new InDimFilter("dim",
ImmutableList.of("v1", "v2"), null);
+ final InDimFilter dimFilter2 = new InDimFilter("dim",
ImmutableList.of("v2", "v1"), null);
+ Assert.assertArrayEquals(dimFilter1.getCacheKey(),
dimFilter2.getCacheKey());
+ }
+
+ @Test
+ public void
testGetCacheKeyDifferentKeysForListOfStringsAndSingleStringOfLists()
+ {
+ final InDimFilter inDimFilter1 = new InDimFilter("dimTest",
Arrays.asList("good", "bad"), null);
+ final InDimFilter inDimFilter2 = new InDimFilter("dimTest",
Collections.singletonList("good,bad"), null);
+ Assert.assertFalse(Arrays.equals(inDimFilter1.getCacheKey(),
inDimFilter2.getCacheKey()));
+ }
+
+ @Test
+ public void
testGetCacheKeyDifferentKeysForListOfStringsAndSingleStringOfListsWithExtractFn()
+ {
+ RegexDimExtractionFn regexFn = new RegexDimExtractionFn(".*", false, null);
+ final InDimFilter inDimFilter1 = new InDimFilter("dimTest",
Arrays.asList("good", "bad"), regexFn);
+ final InDimFilter inDimFilter2 = new InDimFilter("dimTest",
Collections.singletonList("good,bad"), regexFn);
+ Assert.assertFalse(Arrays.equals(inDimFilter1.getCacheKey(),
inDimFilter2.getCacheKey()));
+ }
+
+ @Test
+ public void testGetCacheKeyNullValue() throws IOException
+ {
+ InDimFilter inDimFilter = mapper.readValue(
+ "{\"type\":\"in\",\"dimension\":\"dimTest\",\"values\":[null]}",
+ InDimFilter.class
+ );
+ Assert.assertNotNull(inDimFilter.getCacheKey());
+ }
+
+ @Test
+ public void testGetCacheKeyReturningDifferentKeysWithAndWithoutNull()
+ {
+ InDimFilter filter1 = new InDimFilter("dim", Arrays.asList("val", null),
null);
+ InDimFilter filter2 = new InDimFilter("dim",
Collections.singletonList("val"), null);
+ Assert.assertFalse(Arrays.equals(filter1.getCacheKey(),
filter2.getCacheKey()));
+ }
+
+ @Test
+ public void testGetCacheKeyReturningCachedCacheKey()
+ {
+ final InDimFilter filter = new InDimFilter("dim", ImmutableList.of("v1",
"v2"), null);
+ // Compares the array object, not the elements of the array
+ Assert.assertSame(filter.getCacheKey(), filter.getCacheKey());
+ }
+
+ @Test
+ public void
testGetDimensionRangeSetValuesOfDifferentOrdersReturningSameResult()
+ {
+ final InDimFilter dimFilter1 = new InDimFilter("dim",
ImmutableList.of("v1", "v2", "v3"), null);
+ final InDimFilter dimFilter2 = new InDimFilter("dim",
ImmutableList.of("v3", "v2", "v1"), null);
+ Assert.assertEquals(dimFilter1.getDimensionRangeSet("dim"),
dimFilter2.getDimensionRangeSet("dim"));
+ }
+
+ @Test
+ public void testOptimizeSingleValueInToSelector()
+ {
+ final InDimFilter filter = new InDimFilter("dim",
Collections.singleton("v1"), null);
+ Assert.assertEquals(new SelectorDimFilter("dim", "v1", null),
filter.optimize());
+ }
+}
diff --git
a/processing/src/test/java/org/apache/druid/query/filter/OrDimFilterTest.java
b/processing/src/test/java/org/apache/druid/query/filter/OrDimFilterTest.java
index 9f02194..fe080db 100644
---
a/processing/src/test/java/org/apache/druid/query/filter/OrDimFilterTest.java
+++
b/processing/src/test/java/org/apache/druid/query/filter/OrDimFilterTest.java
@@ -50,4 +50,39 @@ public class OrDimFilterTest extends
InitializedNullHandlingTest
);
Assert.assertEquals(expected, dimFilter.toFilter());
}
+
+ @Test
+ public void testOptimieShortCircuitWithTrueFilter()
+ {
+ DimFilter filter = DimFilterTestUtils.or(
+ DimFilterTestUtils.selector("col1", "1"),
+ TrueDimFilter.instance()
+ );
+ Assert.assertTrue(filter.optimize() instanceof TrueDimFilter);
+ }
+
+ @Test
+ public void testOptimizeOringFalseFilters()
+ {
+ DimFilter filter = DimFilterTestUtils.or(FalseDimFilter.instance(),
FalseDimFilter.instance());
+ Assert.assertSame(FalseDimFilter.instance(), filter.optimize());
+ }
+
+ @Test
+ public void testOptimizeOrOfSingleFilterUnwrapOr()
+ {
+ DimFilter expected = DimFilterTestUtils.selector("col1", "1");
+ DimFilter filter = DimFilterTestUtils.or(expected);
+ Assert.assertEquals(expected, filter.optimize());
+ }
+
+ @Test
+ public void testOptimizeOrOfMultipleFiltersReturningAsItIs()
+ {
+ DimFilter filter = DimFilterTestUtils.or(
+ DimFilterTestUtils.selector("col1", "1"),
+ DimFilterTestUtils.selector("col1", "2")
+ );
+ Assert.assertEquals(filter, filter.optimize());
+ }
}
diff --git
a/processing/src/test/java/org/apache/druid/query/aggregation/FilteredAggregatorFactoryTest.java
b/processing/src/test/java/org/apache/druid/query/filter/TrueDimFilterTest.java
similarity index 54%
copy from
processing/src/test/java/org/apache/druid/query/aggregation/FilteredAggregatorFactoryTest.java
copy to
processing/src/test/java/org/apache/druid/query/filter/TrueDimFilterTest.java
index 4db7b0e..3c88382 100644
---
a/processing/src/test/java/org/apache/druid/query/aggregation/FilteredAggregatorFactoryTest.java
+++
b/processing/src/test/java/org/apache/druid/query/filter/TrueDimFilterTest.java
@@ -17,31 +17,31 @@
* under the License.
*/
-package org.apache.druid.query.aggregation;
+package org.apache.druid.query.filter;
-import org.apache.druid.query.filter.TrueDimFilter;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import nl.jqno.equalsverifier.EqualsVerifier;
+import org.apache.druid.jackson.DefaultObjectMapper;
import org.junit.Assert;
import org.junit.Test;
-public class FilteredAggregatorFactoryTest
+import java.io.IOException;
+
+public class TrueDimFilterTest
{
@Test
- public void testSimpleNaming()
+ public void testSerde() throws IOException
+ {
+ final ObjectMapper mapper = new DefaultObjectMapper();
+ final TrueDimFilter original = TrueDimFilter.instance();
+ final byte[] bytes = mapper.writeValueAsBytes(original);
+ final TrueDimFilter fromBytes = (TrueDimFilter) mapper.readValue(bytes,
DimFilter.class);
+ Assert.assertSame(original, fromBytes);
+ }
+
+ @Test
+ public void testEquals()
{
- Assert.assertEquals("overrideName", new FilteredAggregatorFactory(
- new CountAggregatorFactory("foo"),
- new TrueDimFilter(),
- "overrideName"
- ).getName());
- Assert.assertEquals("delegateName", new FilteredAggregatorFactory(
- new CountAggregatorFactory("delegateName"),
- new TrueDimFilter(),
- ""
- ).getName());
- Assert.assertEquals("delegateName", new FilteredAggregatorFactory(
- new CountAggregatorFactory("delegateName"),
- new TrueDimFilter(),
- null
- ).getName());
+ EqualsVerifier.forClass(TrueDimFilter.class).usingGetClass().verify();
}
}
diff --git
a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/ArrayOverlapOperatorConversion.java
b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/ArrayOverlapOperatorConversion.java
index 175670e..cb1ddf5 100644
---
a/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/ArrayOverlapOperatorConversion.java
+++
b/sql/src/main/java/org/apache/druid/sql/calcite/expression/builtin/ArrayOverlapOperatorConversion.java
@@ -123,7 +123,8 @@ public class ArrayOverlapOperatorConversion extends
BaseExpressionDimFilterOpera
return new InDimFilter(
simpleExtractionExpr.getSimpleExtraction().getColumn(),
Sets.newHashSet(arrayElements),
- simpleExtractionExpr.getSimpleExtraction().getExtractionFn()
+ simpleExtractionExpr.getSimpleExtraction().getExtractionFn(),
+ null
);
}
}
diff --git
a/sql/src/main/java/org/apache/druid/sql/calcite/filtration/ConvertSelectorsToIns.java
b/sql/src/main/java/org/apache/druid/sql/calcite/filtration/ConvertSelectorsToIns.java
index 83da057..54b2625 100644
---
a/sql/src/main/java/org/apache/druid/sql/calcite/filtration/ConvertSelectorsToIns.java
+++
b/sql/src/main/java/org/apache/druid/sql/calcite/filtration/ConvertSelectorsToIns.java
@@ -20,6 +20,7 @@
package org.apache.druid.sql.calcite.filtration;
import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
import org.apache.druid.java.util.common.ISE;
import org.apache.druid.query.filter.DimFilter;
import org.apache.druid.query.filter.InDimFilter;
@@ -33,6 +34,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
public class ConvertSelectorsToIns extends BottomUpTransform
{
@@ -78,7 +80,7 @@ public class ConvertSelectorsToIns extends BottomUpTransform
final List<SelectorDimFilter> filterList = entry.getValue();
if (filterList.size() > 1) {
// We found a simplification. Remove the old filters and add new
ones.
- final List<String> values = new ArrayList<>();
+ final Set<String> values =
Sets.newHashSetWithExpectedSize(filterList.size());
for (final SelectorDimFilter selector : filterList) {
values.add(selector.getValue());
diff --git
a/sql/src/main/java/org/apache/druid/sql/calcite/filtration/Filtration.java
b/sql/src/main/java/org/apache/druid/sql/calcite/filtration/Filtration.java
index 677961e..8f2f760 100644
--- a/sql/src/main/java/org/apache/druid/sql/calcite/filtration/Filtration.java
+++ b/sql/src/main/java/org/apache/druid/sql/calcite/filtration/Filtration.java
@@ -23,9 +23,9 @@ import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import org.apache.druid.java.util.common.ISE;
import org.apache.druid.java.util.common.Intervals;
-import org.apache.druid.math.expr.ExprMacroTable;
import org.apache.druid.query.filter.DimFilter;
-import org.apache.druid.query.filter.ExpressionDimFilter;
+import org.apache.druid.query.filter.FalseDimFilter;
+import org.apache.druid.query.filter.TrueDimFilter;
import org.apache.druid.query.spec.MultipleIntervalSegmentSpec;
import org.apache.druid.query.spec.QuerySegmentSpec;
import org.apache.druid.segment.column.RowSignature;
@@ -36,12 +36,8 @@ import java.util.Objects;
public class Filtration
{
- private static final DimFilter MATCH_NOTHING = new ExpressionDimFilter(
- "1 == 2", ExprMacroTable.nil()
- );
- private static final DimFilter MATCH_EVERYTHING = new ExpressionDimFilter(
- "1 == 1", ExprMacroTable.nil()
- );
+ private static final DimFilter MATCH_NOTHING = FalseDimFilter.instance();
+ private static final DimFilter MATCH_EVERYTHING = TrueDimFilter.instance();
// 1) If "dimFilter" is null, it should be ignored and not affect filtration.
// 2) There is an implicit AND between "intervals" and "dimFilter" (if
dimFilter is non-null).
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]