This is an automated email from the ASF dual-hosted git repository.
jackie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git
The following commit(s) were added to refs/heads/master by this push:
new b09e9e645f evaluate EQ queries against range index when available
(#10043)
b09e9e645f is described below
commit b09e9e645feaf013b2257e9cfeaf33d1015892fb
Author: Richard Startin <[email protected]>
AuthorDate: Tue Jan 10 22:59:37 2023 +0000
evaluate EQ queries against range index when available (#10043)
---
.../core/operator/filter/FilterOperatorUtils.java | 5 +-
.../filter/RangeIndexBasedFilterOperator.java | 328 ++++++++-------------
.../predicate/EqualsPredicateEvaluatorFactory.java | 44 ++-
.../predicate/RangePredicateEvaluatorFactory.java | 37 ++-
.../filter/predicate/traits/DoubleRange.java | 25 ++
.../filter/predicate/traits/DoubleValue.java | 23 ++
.../filter/predicate/traits/FloatRange.java | 25 ++
.../filter/predicate/traits/FloatValue.java | 23 ++
.../operator/filter/predicate/traits/IntRange.java | 25 ++
.../operator/filter/predicate/traits/IntValue.java | 23 ++
.../filter/predicate/traits/LongRange.java | 25 ++
.../filter/predicate/traits/LongValue.java | 23 ++
.../org/apache/pinot/queries/RangeQueriesTest.java | 29 ++
.../index/readers/BitSlicedRangeIndexReader.java | 79 ++++-
.../index/creator/BitSlicedIndexCreatorTest.java | 36 +++
.../segment/spi/index/reader/RangeIndexReader.java | 101 ++++++-
16 files changed, 623 insertions(+), 228 deletions(-)
diff --git
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/FilterOperatorUtils.java
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/FilterOperatorUtils.java
index c343dcea88..aa738beab4 100644
---
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/FilterOperatorUtils.java
+++
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/FilterOperatorUtils.java
@@ -61,7 +61,7 @@ public class FilterOperatorUtils {
if (dataSource.getDataSourceMetadata().isSorted() &&
dataSource.getDictionary() != null) {
return new SortedIndexBasedFilterOperator(predicateEvaluator,
dataSource, numDocs);
}
- if (dataSource.getRangeIndex() != null) {
+ if (RangeIndexBasedFilterOperator.canEvaluate(predicateEvaluator,
dataSource)) {
return new RangeIndexBasedFilterOperator(predicateEvaluator,
dataSource, numDocs);
}
return new ScanBasedFilterOperator(predicateEvaluator, dataSource,
numDocs, nullHandlingEnabled);
@@ -80,6 +80,9 @@ public class FilterOperatorUtils {
if (dataSource.getInvertedIndex() != null) {
return new BitmapBasedFilterOperator(predicateEvaluator, dataSource,
numDocs);
}
+ if (RangeIndexBasedFilterOperator.canEvaluate(predicateEvaluator,
dataSource)) {
+ return new RangeIndexBasedFilterOperator(predicateEvaluator,
dataSource, numDocs);
+ }
return new ScanBasedFilterOperator(predicateEvaluator, dataSource,
numDocs, nullHandlingEnabled);
}
}
diff --git
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/RangeIndexBasedFilterOperator.java
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/RangeIndexBasedFilterOperator.java
index 4b968ba2ed..277fa4429f 100644
---
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/RangeIndexBasedFilterOperator.java
+++
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/RangeIndexBasedFilterOperator.java
@@ -20,19 +20,24 @@ package org.apache.pinot.core.operator.filter;
import java.util.Collections;
import java.util.List;
+import org.apache.pinot.common.request.context.predicate.Predicate;
import org.apache.pinot.core.common.Operator;
import org.apache.pinot.core.operator.blocks.FilterBlock;
import org.apache.pinot.core.operator.dociditerators.ScanBasedDocIdIterator;
import org.apache.pinot.core.operator.docidsets.BitmapDocIdSet;
import org.apache.pinot.core.operator.docidsets.FilterBlockDocIdSet;
import org.apache.pinot.core.operator.filter.predicate.PredicateEvaluator;
-import
org.apache.pinot.core.operator.filter.predicate.RangePredicateEvaluatorFactory.DoubleRawValueBasedRangePredicateEvaluator;
-import
org.apache.pinot.core.operator.filter.predicate.RangePredicateEvaluatorFactory.FloatRawValueBasedRangePredicateEvaluator;
-import
org.apache.pinot.core.operator.filter.predicate.RangePredicateEvaluatorFactory.IntRawValueBasedRangePredicateEvaluator;
-import
org.apache.pinot.core.operator.filter.predicate.RangePredicateEvaluatorFactory.LongRawValueBasedRangePredicateEvaluator;
-import
org.apache.pinot.core.operator.filter.predicate.RangePredicateEvaluatorFactory.SortedDictionaryBasedRangePredicateEvaluator;
+import org.apache.pinot.core.operator.filter.predicate.traits.DoubleRange;
+import org.apache.pinot.core.operator.filter.predicate.traits.DoubleValue;
+import org.apache.pinot.core.operator.filter.predicate.traits.FloatRange;
+import org.apache.pinot.core.operator.filter.predicate.traits.FloatValue;
+import org.apache.pinot.core.operator.filter.predicate.traits.IntRange;
+import org.apache.pinot.core.operator.filter.predicate.traits.IntValue;
+import org.apache.pinot.core.operator.filter.predicate.traits.LongRange;
+import org.apache.pinot.core.operator.filter.predicate.traits.LongValue;
import org.apache.pinot.segment.spi.datasource.DataSource;
import org.apache.pinot.segment.spi.index.reader.RangeIndexReader;
+import org.apache.pinot.spi.data.FieldSpec;
import org.apache.pinot.spi.trace.FilterType;
import org.apache.pinot.spi.trace.InvocationRecording;
import org.apache.pinot.spi.trace.Tracing;
@@ -44,24 +49,32 @@ public class RangeIndexBasedFilterOperator extends
BaseFilterOperator {
private static final String EXPLAIN_NAME = "FILTER_RANGE_INDEX";
- private final RangeEvaluator _rangeEvaluator;
- private final PredicateEvaluator _rangePredicateEvaluator;
+ private final RangeIndexReader<ImmutableRoaringBitmap> _rangeIndexReader;
+ private final PredicateEvaluator _predicateEvaluator;
private final DataSource _dataSource;
+ private final FieldSpec.DataType _parameterType;
private final int _numDocs;
+ static boolean canEvaluate(PredicateEvaluator predicateEvaluator, DataSource
dataSource) {
+ Predicate.Type type = predicateEvaluator.getPredicateType();
+ RangeIndexReader<?> rangeIndex = dataSource.getRangeIndex();
+ return rangeIndex != null && (type == Predicate.Type.RANGE || (type ==
Predicate.Type.EQ
+ && dataSource.getRangeIndex().isExact()));
+ }
+
@SuppressWarnings("unchecked")
- public RangeIndexBasedFilterOperator(PredicateEvaluator
rangePredicateEvaluator, DataSource dataSource, int numDocs) {
- _rangePredicateEvaluator = rangePredicateEvaluator;
- _rangeEvaluator =
RangeEvaluator.of((RangeIndexReader<ImmutableRoaringBitmap>)
dataSource.getRangeIndex(),
- rangePredicateEvaluator);
+ public RangeIndexBasedFilterOperator(PredicateEvaluator predicateEvaluator,
DataSource dataSource, int numDocs) {
+ _predicateEvaluator = predicateEvaluator;
+ _rangeIndexReader = (RangeIndexReader<ImmutableRoaringBitmap>)
dataSource.getRangeIndex();
_dataSource = dataSource;
_numDocs = numDocs;
+ _parameterType = predicateEvaluator.isDictionaryBased() ?
FieldSpec.DataType.INT : predicateEvaluator.getDataType();
}
@Override
protected FilterBlock getNextBlock() {
- if (_rangeEvaluator.isExact()) {
- ImmutableRoaringBitmap matches = _rangeEvaluator.getMatchingDocIds();
+ if (_rangeIndexReader.isExact()) {
+ ImmutableRoaringBitmap matches = getMatchingDocIds();
recordFilter(matches);
return new FilterBlock(new BitmapDocIdSet(matches, _numDocs));
}
@@ -69,11 +82,11 @@ public class RangeIndexBasedFilterOperator extends
BaseFilterOperator {
}
private FilterBlock evaluateLegacyRangeFilter() {
- ImmutableRoaringBitmap matches = _rangeEvaluator.getMatchingDocIds();
+ ImmutableRoaringBitmap matches = getMatchingDocIds();
// if the implementation cannot match the entire query exactly, it will
// yield partial matches, which need to be verified by scanning. If it
// can answer the query exactly, this will be null.
- ImmutableRoaringBitmap partialMatches =
_rangeEvaluator.getPartiallyMatchingDocIds();
+ ImmutableRoaringBitmap partialMatches = getPartiallyMatchingDocIds();
// this branch is likely until RangeIndexReader reimplemented and enabled
by default
if (partialMatches == null) {
return new FilterBlock(new BitmapDocIdSet(matches == null ? new
MutableRoaringBitmap() : matches, _numDocs));
@@ -81,7 +94,7 @@ public class RangeIndexBasedFilterOperator extends
BaseFilterOperator {
// TODO: support proper null handling in range index.
// Need to scan the first and last range as they might be partially matched
ScanBasedFilterOperator scanBasedFilterOperator =
- new ScanBasedFilterOperator(_rangePredicateEvaluator, _dataSource,
_numDocs, false);
+ new ScanBasedFilterOperator(_predicateEvaluator, _dataSource,
_numDocs, false);
FilterBlockDocIdSet scanBasedDocIdSet =
scanBasedFilterOperator.getNextBlock().getBlockDocIdSet();
MutableRoaringBitmap docIds = ((ScanBasedDocIdIterator)
scanBasedDocIdSet.iterator()).applyAnd(partialMatches);
if (matches != null) {
@@ -97,24 +110,114 @@ public class RangeIndexBasedFilterOperator extends
BaseFilterOperator {
});
}
+ ImmutableRoaringBitmap getMatchingDocIds() {
+ switch (_parameterType) {
+ case INT:
+ if (_predicateEvaluator instanceof IntValue) {
+ return _rangeIndexReader.getMatchingDocIds(((IntValue)
_predicateEvaluator).getInt());
+ }
+ IntRange intRange = (IntRange) _predicateEvaluator;
+ return
_rangeIndexReader.getMatchingDocIds(intRange.getInclusiveLowerBound(),
+ intRange.getInclusiveUpperBound());
+ case LONG:
+ if (_predicateEvaluator instanceof LongValue) {
+ return _rangeIndexReader.getMatchingDocIds(((LongValue)
_predicateEvaluator).getLong());
+ }
+ LongRange longRange = (LongRange) _predicateEvaluator;
+ return
_rangeIndexReader.getMatchingDocIds(longRange.getInclusiveLowerBound(),
+ longRange.getInclusiveUpperBound());
+ case FLOAT:
+ if (_predicateEvaluator instanceof FloatValue) {
+ return _rangeIndexReader.getMatchingDocIds(((FloatValue)
_predicateEvaluator).getFloat());
+ }
+ FloatRange floatRange = (FloatRange) _predicateEvaluator;
+ return
_rangeIndexReader.getMatchingDocIds(floatRange.getInclusiveLowerBound(),
+ floatRange.getInclusiveUpperBound());
+ case DOUBLE:
+ if (_predicateEvaluator instanceof DoubleValue) {
+ return _rangeIndexReader.getMatchingDocIds(((DoubleValue)
_predicateEvaluator).getDouble());
+ }
+ DoubleRange doubleRange = (DoubleRange) _predicateEvaluator;
+ return
_rangeIndexReader.getMatchingDocIds(doubleRange.getInclusiveLowerBound(),
+ doubleRange.getInclusiveUpperBound());
+ default:
+ throw unsupportedDataType(_parameterType);
+ }
+ }
+
+ ImmutableRoaringBitmap getPartiallyMatchingDocIds() {
+ assert !_rangeIndexReader.isExact();
+ switch (_parameterType) {
+ case INT:
+ IntRange intRange = (IntRange) _predicateEvaluator;
+ return
_rangeIndexReader.getPartiallyMatchingDocIds(intRange.getInclusiveLowerBound(),
+ intRange.getInclusiveUpperBound());
+ case LONG:
+ LongRange longRange = (LongRange) _predicateEvaluator;
+ return
_rangeIndexReader.getPartiallyMatchingDocIds(longRange.getInclusiveLowerBound(),
+ longRange.getInclusiveUpperBound());
+ case FLOAT:
+ FloatRange floatRange = (FloatRange) _predicateEvaluator;
+ return
_rangeIndexReader.getPartiallyMatchingDocIds(floatRange.getInclusiveLowerBound(),
+ floatRange.getInclusiveUpperBound());
+ case DOUBLE:
+ DoubleRange doubleRange = (DoubleRange) _predicateEvaluator;
+ return
_rangeIndexReader.getPartiallyMatchingDocIds(doubleRange.getInclusiveLowerBound(),
+ doubleRange.getInclusiveUpperBound());
+ default:
+ throw unsupportedDataType(_parameterType);
+ }
+ }
+
@Override
public boolean canOptimizeCount() {
- return _rangeEvaluator.isExact();
+ return _rangeIndexReader.isExact();
}
@Override
public int getNumMatchingDocs() {
- return _rangeEvaluator.getNumMatchingDocs();
+ switch (_parameterType) {
+ case INT:
+ if (_predicateEvaluator instanceof IntValue) {
+ return _rangeIndexReader.getNumMatchingDocs(((IntValue)
_predicateEvaluator).getInt());
+ }
+ IntRange intRange = (IntRange) _predicateEvaluator;
+ return
_rangeIndexReader.getNumMatchingDocs(intRange.getInclusiveLowerBound(),
+ intRange.getInclusiveUpperBound());
+ case LONG:
+ if (_predicateEvaluator instanceof LongValue) {
+ return _rangeIndexReader.getNumMatchingDocs(((LongValue)
_predicateEvaluator).getLong());
+ }
+ LongRange longRange = (LongRange) _predicateEvaluator;
+ return
_rangeIndexReader.getNumMatchingDocs(longRange.getInclusiveLowerBound(),
+ longRange.getInclusiveUpperBound());
+ case FLOAT:
+ if (_predicateEvaluator instanceof FloatValue) {
+ return _rangeIndexReader.getNumMatchingDocs(((FloatValue)
_predicateEvaluator).getFloat());
+ }
+ FloatRange floatRange = (FloatRange) _predicateEvaluator;
+ return
_rangeIndexReader.getNumMatchingDocs(floatRange.getInclusiveLowerBound(),
+ floatRange.getInclusiveUpperBound());
+ case DOUBLE:
+ if (_predicateEvaluator instanceof DoubleValue) {
+ return _rangeIndexReader.getNumMatchingDocs(((DoubleValue)
_predicateEvaluator).getDouble());
+ }
+ DoubleRange doubleRange = (DoubleRange) _predicateEvaluator;
+ return
_rangeIndexReader.getNumMatchingDocs(doubleRange.getInclusiveLowerBound(),
+ doubleRange.getInclusiveUpperBound());
+ default:
+ throw unsupportedDataType(_parameterType);
+ }
}
@Override
public boolean canProduceBitmaps() {
- return _rangeEvaluator.isExact();
+ return _rangeIndexReader.isExact();
}
@Override
public BitmapCollection getBitmaps() {
- return new BitmapCollection(_numDocs, false,
_rangeEvaluator.getMatchingDocIds());
+ return new BitmapCollection(_numDocs, false, getMatchingDocIds());
}
@Override
@@ -124,187 +227,16 @@ public class RangeIndexBasedFilterOperator extends
BaseFilterOperator {
@Override
public String toExplainString() {
- return EXPLAIN_NAME + "(indexLookUp:range_index"
- + ",operator:" + _rangePredicateEvaluator.getPredicateType()
- + ",predicate:" + _rangePredicateEvaluator.getPredicate().toString()
- + ')';
- }
-
- interface RangeEvaluator {
- static RangeEvaluator of(RangeIndexReader<ImmutableRoaringBitmap>
rangeIndexReader,
- PredicateEvaluator predicateEvaluator) {
- if (predicateEvaluator instanceof
SortedDictionaryBasedRangePredicateEvaluator) {
- return new IntRangeEvaluator(rangeIndexReader,
- (SortedDictionaryBasedRangePredicateEvaluator) predicateEvaluator);
- } else {
- switch (predicateEvaluator.getDataType()) {
- case INT:
- return new IntRangeEvaluator(rangeIndexReader,
- (IntRawValueBasedRangePredicateEvaluator) predicateEvaluator);
- case LONG:
- return new LongRangeEvaluator(rangeIndexReader,
- (LongRawValueBasedRangePredicateEvaluator) predicateEvaluator);
- case FLOAT:
- return new FloatRangeEvaluator(rangeIndexReader,
- (FloatRawValueBasedRangePredicateEvaluator)
predicateEvaluator);
- case DOUBLE:
- return new DoubleRangeEvaluator(rangeIndexReader,
- (DoubleRawValueBasedRangePredicateEvaluator)
predicateEvaluator);
- default:
- throw new IllegalStateException("String and Bytes data type not
supported for Range Indexing");
- }
- }
- }
-
- ImmutableRoaringBitmap getMatchingDocIds();
-
- ImmutableRoaringBitmap getPartiallyMatchingDocIds();
-
- int getNumMatchingDocs();
-
- boolean isExact();
- }
-
- private static final class IntRangeEvaluator implements RangeEvaluator {
- final RangeIndexReader<ImmutableRoaringBitmap> _rangeIndexReader;
- final int _min;
- final int _max;
-
- private IntRangeEvaluator(RangeIndexReader<ImmutableRoaringBitmap>
rangeIndexReader, int min, int max) {
- _rangeIndexReader = rangeIndexReader;
- _min = min;
- _max = max;
- }
-
- IntRangeEvaluator(RangeIndexReader<ImmutableRoaringBitmap>
rangeIndexReader,
- IntRawValueBasedRangePredicateEvaluator predicateEvaluator) {
- this(rangeIndexReader, predicateEvaluator.getInclusiveLowerBound(),
predicateEvaluator.getInclusiveUpperBound());
- }
-
- IntRangeEvaluator(RangeIndexReader<ImmutableRoaringBitmap>
rangeIndexReader,
- SortedDictionaryBasedRangePredicateEvaluator predicateEvaluator) {
- // NOTE: End dictionary id is exclusive in
OfflineDictionaryBasedRangePredicateEvaluator.
- this(rangeIndexReader, predicateEvaluator.getStartDictId(),
predicateEvaluator.getEndDictId() - 1);
- }
-
- @Override
- public ImmutableRoaringBitmap getMatchingDocIds() {
- return _rangeIndexReader.getMatchingDocIds(_min, _max);
- }
-
- @Override
- public ImmutableRoaringBitmap getPartiallyMatchingDocIds() {
- return _rangeIndexReader.getPartiallyMatchingDocIds(_min, _max);
- }
-
- @Override
- public int getNumMatchingDocs() {
- return _rangeIndexReader.getNumMatchingDocs(_min, _max);
- }
-
- @Override
- public boolean isExact() {
- return _rangeIndexReader.isExact();
- }
+ return EXPLAIN_NAME + "(indexLookUp:range_index" + ",operator:" +
_predicateEvaluator.getPredicateType()
+ + ",predicate:" + _predicateEvaluator.getPredicate().toString() + ')';
}
- private static final class LongRangeEvaluator implements RangeEvaluator {
- final RangeIndexReader<ImmutableRoaringBitmap> _rangeIndexReader;
- final long _min;
- final long _max;
-
- LongRangeEvaluator(RangeIndexReader<ImmutableRoaringBitmap>
rangeIndexReader,
- LongRawValueBasedRangePredicateEvaluator predicateEvaluator) {
- _rangeIndexReader = rangeIndexReader;
- _min = predicateEvaluator.getInclusiveLowerBound();
- _max = predicateEvaluator.getInclusiveUpperBound();
- }
-
- @Override
- public ImmutableRoaringBitmap getMatchingDocIds() {
- return _rangeIndexReader.getMatchingDocIds(_min, _max);
- }
-
- @Override
- public ImmutableRoaringBitmap getPartiallyMatchingDocIds() {
- return _rangeIndexReader.getPartiallyMatchingDocIds(_min, _max);
- }
-
- @Override
- public int getNumMatchingDocs() {
- return _rangeIndexReader.getNumMatchingDocs(_min, _max);
- }
-
- @Override
- public boolean isExact() {
- return _rangeIndexReader.isExact();
- }
+ static RuntimeException unsupportedPredicateType(Predicate.Type type) {
+ return new IllegalStateException("Range index cannot satisfy " + type);
}
- private static final class FloatRangeEvaluator implements RangeEvaluator {
- final RangeIndexReader<ImmutableRoaringBitmap> _rangeIndexReader;
- final float _min;
- final float _max;
-
- FloatRangeEvaluator(RangeIndexReader<ImmutableRoaringBitmap>
rangeIndexReader,
- FloatRawValueBasedRangePredicateEvaluator predicateEvaluator) {
- _rangeIndexReader = rangeIndexReader;
- _min = predicateEvaluator.getInclusiveLowerBound();
- _max = predicateEvaluator.getInclusiveUpperBound();
- }
-
- @Override
- public ImmutableRoaringBitmap getMatchingDocIds() {
- return _rangeIndexReader.getMatchingDocIds(_min, _max);
- }
-
- @Override
- public ImmutableRoaringBitmap getPartiallyMatchingDocIds() {
- return _rangeIndexReader.getPartiallyMatchingDocIds(_min, _max);
- }
-
- @Override
- public int getNumMatchingDocs() {
- return _rangeIndexReader.getNumMatchingDocs(_min, _max);
- }
-
- @Override
- public boolean isExact() {
- return _rangeIndexReader.isExact();
- }
- }
-
- private static final class DoubleRangeEvaluator implements RangeEvaluator {
- final RangeIndexReader<ImmutableRoaringBitmap> _rangeIndexReader;
- final double _min;
- final double _max;
-
- DoubleRangeEvaluator(RangeIndexReader<ImmutableRoaringBitmap>
rangeIndexReader,
- DoubleRawValueBasedRangePredicateEvaluator predicateEvaluator) {
- _rangeIndexReader = rangeIndexReader;
- _min = predicateEvaluator.getInclusiveLowerBound();
- _max = predicateEvaluator.getInclusiveUpperBound();
- }
-
- @Override
- public ImmutableRoaringBitmap getMatchingDocIds() {
- return _rangeIndexReader.getMatchingDocIds(_min, _max);
- }
-
- @Override
- public ImmutableRoaringBitmap getPartiallyMatchingDocIds() {
- return _rangeIndexReader.getPartiallyMatchingDocIds(_min, _max);
- }
-
- @Override
- public int getNumMatchingDocs() {
- return _rangeIndexReader.getNumMatchingDocs(_min, _max);
- }
-
- @Override
- public boolean isExact() {
- return _rangeIndexReader.isExact();
- }
+ static RuntimeException unsupportedDataType(FieldSpec.DataType dataType) {
+ return new IllegalStateException("Range index does not support " +
dataType);
}
private void recordFilter(ImmutableRoaringBitmap bitmap) {
@@ -312,7 +244,7 @@ public class RangeIndexBasedFilterOperator extends
BaseFilterOperator {
if (recording.isEnabled()) {
recording.setNumDocsMatchingAfterFilter(bitmap == null ? 0 :
bitmap.getCardinality());
recording.setColumnName(_dataSource.getDataSourceMetadata().getFieldSpec().getName());
- recording.setFilter(FilterType.INDEX,
_rangePredicateEvaluator.getPredicateType().name());
+ recording.setFilter(FilterType.INDEX,
_predicateEvaluator.getPredicateType().name());
recording.setNumDocsScanned(_numDocs);
}
}
diff --git
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/EqualsPredicateEvaluatorFactory.java
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/EqualsPredicateEvaluatorFactory.java
index 814a45253b..dcc3f34f65 100644
---
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/EqualsPredicateEvaluatorFactory.java
+++
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/EqualsPredicateEvaluatorFactory.java
@@ -21,6 +21,10 @@ package org.apache.pinot.core.operator.filter.predicate;
import java.math.BigDecimal;
import java.util.Arrays;
import org.apache.pinot.common.request.context.predicate.EqPredicate;
+import org.apache.pinot.core.operator.filter.predicate.traits.DoubleValue;
+import org.apache.pinot.core.operator.filter.predicate.traits.FloatValue;
+import org.apache.pinot.core.operator.filter.predicate.traits.IntValue;
+import org.apache.pinot.core.operator.filter.predicate.traits.LongValue;
import org.apache.pinot.segment.spi.index.reader.Dictionary;
import org.apache.pinot.spi.data.FieldSpec.DataType;
import org.apache.pinot.spi.utils.BooleanUtils;
@@ -82,7 +86,8 @@ public class EqualsPredicateEvaluatorFactory {
}
}
- private static final class DictionaryBasedEqPredicateEvaluator extends
BaseDictionaryBasedPredicateEvaluator {
+ private static final class DictionaryBasedEqPredicateEvaluator extends
BaseDictionaryBasedPredicateEvaluator
+ implements IntValue {
final int _matchingDictId;
final int[] _matchingDictIds;
@@ -128,9 +133,15 @@ public class EqualsPredicateEvaluatorFactory {
public int[] getMatchingDictIds() {
return _matchingDictIds;
}
+
+ @Override
+ public int getInt() {
+ return _matchingDictId;
+ }
}
- private static final class IntRawValueBasedEqPredicateEvaluator extends
BaseRawValueBasedPredicateEvaluator {
+ private static final class IntRawValueBasedEqPredicateEvaluator extends
BaseRawValueBasedPredicateEvaluator
+ implements IntValue {
final int _matchingValue;
IntRawValueBasedEqPredicateEvaluator(EqPredicate eqPredicate, int
matchingValue) {
@@ -165,9 +176,15 @@ public class EqualsPredicateEvaluatorFactory {
}
return matches;
}
+
+ @Override
+ public int getInt() {
+ return _matchingValue;
+ }
}
- private static final class LongRawValueBasedEqPredicateEvaluator extends
BaseRawValueBasedPredicateEvaluator {
+ private static final class LongRawValueBasedEqPredicateEvaluator extends
BaseRawValueBasedPredicateEvaluator
+ implements LongValue {
final long _matchingValue;
LongRawValueBasedEqPredicateEvaluator(EqPredicate eqPredicate, long
matchingValue) {
@@ -202,9 +219,15 @@ public class EqualsPredicateEvaluatorFactory {
}
return matches;
}
+
+ @Override
+ public long getLong() {
+ return _matchingValue;
+ }
}
- private static final class FloatRawValueBasedEqPredicateEvaluator extends
BaseRawValueBasedPredicateEvaluator {
+ private static final class FloatRawValueBasedEqPredicateEvaluator extends
BaseRawValueBasedPredicateEvaluator
+ implements FloatValue {
final float _matchingValue;
FloatRawValueBasedEqPredicateEvaluator(EqPredicate eqPredicate, float
matchingValue) {
@@ -239,9 +262,15 @@ public class EqualsPredicateEvaluatorFactory {
}
return matches;
}
+
+ @Override
+ public float getFloat() {
+ return _matchingValue;
+ }
}
- private static final class DoubleRawValueBasedEqPredicateEvaluator extends
BaseRawValueBasedPredicateEvaluator {
+ private static final class DoubleRawValueBasedEqPredicateEvaluator extends
BaseRawValueBasedPredicateEvaluator
+ implements DoubleValue {
final double _matchingValue;
DoubleRawValueBasedEqPredicateEvaluator(EqPredicate eqPredicate, double
matchingValue) {
@@ -276,6 +305,11 @@ public class EqualsPredicateEvaluatorFactory {
}
return matches;
}
+
+ @Override
+ public double getDouble() {
+ return _matchingValue;
+ }
}
private static final class BigDecimalRawValueBasedEqPredicateEvaluator
extends BaseRawValueBasedPredicateEvaluator {
diff --git
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/RangePredicateEvaluatorFactory.java
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/RangePredicateEvaluatorFactory.java
index f3b1cef1af..346b8440e1 100644
---
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/RangePredicateEvaluatorFactory.java
+++
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/RangePredicateEvaluatorFactory.java
@@ -22,6 +22,10 @@ import com.google.common.base.Preconditions;
import it.unimi.dsi.fastutil.ints.IntSet;
import java.math.BigDecimal;
import org.apache.pinot.common.request.context.predicate.RangePredicate;
+import org.apache.pinot.core.operator.filter.predicate.traits.DoubleRange;
+import org.apache.pinot.core.operator.filter.predicate.traits.FloatRange;
+import org.apache.pinot.core.operator.filter.predicate.traits.IntRange;
+import org.apache.pinot.core.operator.filter.predicate.traits.LongRange;
import org.apache.pinot.segment.spi.index.reader.Dictionary;
import org.apache.pinot.spi.data.FieldSpec.DataType;
import org.apache.pinot.spi.utils.BooleanUtils;
@@ -112,7 +116,8 @@ public class RangePredicateEvaluatorFactory {
}
}
- public static final class SortedDictionaryBasedRangePredicateEvaluator
extends BaseDictionaryBasedPredicateEvaluator {
+ public static final class SortedDictionaryBasedRangePredicateEvaluator
extends BaseDictionaryBasedPredicateEvaluator
+ implements IntRange {
final int _startDictId;
// Exclusive
final int _endDictId;
@@ -214,6 +219,16 @@ public class RangePredicateEvaluatorFactory {
public int getNumMatchingItems() {
return Math.max(_numMatchingDictIds, 0);
}
+
+ @Override
+ public int getInclusiveLowerBound() {
+ return getStartDictId();
+ }
+
+ @Override
+ public int getInclusiveUpperBound() {
+ return getEndDictId() - 1;
+ }
}
private static final class UnsortedDictionaryBasedRangePredicateEvaluator
@@ -294,7 +309,8 @@ public class RangePredicateEvaluatorFactory {
}
}
- public static final class IntRawValueBasedRangePredicateEvaluator extends
BaseRawValueBasedPredicateEvaluator {
+ private static final class IntRawValueBasedRangePredicateEvaluator extends
BaseRawValueBasedPredicateEvaluator
+ implements IntRange {
final int _inclusiveLowerBound;
final int _inclusiveUpperBound;
@@ -315,10 +331,12 @@ public class RangePredicateEvaluatorFactory {
}
}
+ @Override
public int getInclusiveLowerBound() {
return _inclusiveLowerBound;
}
+ @Override
public int getInclusiveUpperBound() {
return _inclusiveUpperBound;
}
@@ -347,7 +365,8 @@ public class RangePredicateEvaluatorFactory {
}
}
- public static final class LongRawValueBasedRangePredicateEvaluator extends
BaseRawValueBasedPredicateEvaluator {
+ private static final class LongRawValueBasedRangePredicateEvaluator extends
BaseRawValueBasedPredicateEvaluator
+ implements LongRange {
final long _inclusiveLowerBound;
final long _inclusiveUpperBound;
@@ -368,10 +387,12 @@ public class RangePredicateEvaluatorFactory {
}
}
+ @Override
public long getInclusiveLowerBound() {
return _inclusiveLowerBound;
}
+ @Override
public long getInclusiveUpperBound() {
return _inclusiveUpperBound;
}
@@ -400,7 +421,8 @@ public class RangePredicateEvaluatorFactory {
}
}
- public static final class FloatRawValueBasedRangePredicateEvaluator extends
BaseRawValueBasedPredicateEvaluator {
+ private static final class FloatRawValueBasedRangePredicateEvaluator extends
BaseRawValueBasedPredicateEvaluator
+ implements FloatRange {
final float _inclusiveLowerBound;
final float _inclusiveUpperBound;
@@ -421,10 +443,12 @@ public class RangePredicateEvaluatorFactory {
}
}
+ @Override
public float getInclusiveLowerBound() {
return _inclusiveLowerBound;
}
+ @Override
public float getInclusiveUpperBound() {
return _inclusiveUpperBound;
}
@@ -453,7 +477,8 @@ public class RangePredicateEvaluatorFactory {
}
}
- public static final class DoubleRawValueBasedRangePredicateEvaluator extends
BaseRawValueBasedPredicateEvaluator {
+ private static final class DoubleRawValueBasedRangePredicateEvaluator
extends BaseRawValueBasedPredicateEvaluator
+ implements DoubleRange {
final double _inclusiveLowerBound;
final double _inclusiveUpperBound;
@@ -474,10 +499,12 @@ public class RangePredicateEvaluatorFactory {
}
}
+ @Override
public double getInclusiveLowerBound() {
return _inclusiveLowerBound;
}
+ @Override
public double getInclusiveUpperBound() {
return _inclusiveUpperBound;
}
diff --git
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/traits/DoubleRange.java
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/traits/DoubleRange.java
new file mode 100644
index 0000000000..bd2fe790b6
--- /dev/null
+++
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/traits/DoubleRange.java
@@ -0,0 +1,25 @@
+/**
+ * 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.pinot.core.operator.filter.predicate.traits;
+
+public interface DoubleRange {
+ double getInclusiveLowerBound();
+
+ double getInclusiveUpperBound();
+}
diff --git
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/traits/DoubleValue.java
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/traits/DoubleValue.java
new file mode 100644
index 0000000000..27b29f93e4
--- /dev/null
+++
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/traits/DoubleValue.java
@@ -0,0 +1,23 @@
+/**
+ * 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.pinot.core.operator.filter.predicate.traits;
+
+public interface DoubleValue {
+ double getDouble();
+}
diff --git
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/traits/FloatRange.java
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/traits/FloatRange.java
new file mode 100644
index 0000000000..44b38ae626
--- /dev/null
+++
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/traits/FloatRange.java
@@ -0,0 +1,25 @@
+/**
+ * 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.pinot.core.operator.filter.predicate.traits;
+
+public interface FloatRange {
+ float getInclusiveLowerBound();
+
+ float getInclusiveUpperBound();
+}
diff --git
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/traits/FloatValue.java
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/traits/FloatValue.java
new file mode 100644
index 0000000000..4dac96a049
--- /dev/null
+++
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/traits/FloatValue.java
@@ -0,0 +1,23 @@
+/**
+ * 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.pinot.core.operator.filter.predicate.traits;
+
+public interface FloatValue {
+ float getFloat();
+}
diff --git
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/traits/IntRange.java
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/traits/IntRange.java
new file mode 100644
index 0000000000..c5b77d487f
--- /dev/null
+++
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/traits/IntRange.java
@@ -0,0 +1,25 @@
+/**
+ * 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.pinot.core.operator.filter.predicate.traits;
+
+public interface IntRange {
+ int getInclusiveLowerBound();
+
+ int getInclusiveUpperBound();
+}
diff --git
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/traits/IntValue.java
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/traits/IntValue.java
new file mode 100644
index 0000000000..4e3aa09ce1
--- /dev/null
+++
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/traits/IntValue.java
@@ -0,0 +1,23 @@
+/**
+ * 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.pinot.core.operator.filter.predicate.traits;
+
+public interface IntValue {
+ int getInt();
+}
diff --git
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/traits/LongRange.java
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/traits/LongRange.java
new file mode 100644
index 0000000000..f3a4d17aeb
--- /dev/null
+++
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/traits/LongRange.java
@@ -0,0 +1,25 @@
+/**
+ * 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.pinot.core.operator.filter.predicate.traits;
+
+public interface LongRange {
+ long getInclusiveLowerBound();
+
+ long getInclusiveUpperBound();
+}
diff --git
a/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/traits/LongValue.java
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/traits/LongValue.java
new file mode 100644
index 0000000000..62d4c097d3
--- /dev/null
+++
b/pinot-core/src/main/java/org/apache/pinot/core/operator/filter/predicate/traits/LongValue.java
@@ -0,0 +1,23 @@
+/**
+ * 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.pinot.core.operator.filter.predicate.traits;
+
+public interface LongValue {
+ long getLong();
+}
diff --git
a/pinot-core/src/test/java/org/apache/pinot/queries/RangeQueriesTest.java
b/pinot-core/src/test/java/org/apache/pinot/queries/RangeQueriesTest.java
index 44ba46b2db..099981d681 100644
--- a/pinot-core/src/test/java/org/apache/pinot/queries/RangeQueriesTest.java
+++ b/pinot-core/src/test/java/org/apache/pinot/queries/RangeQueriesTest.java
@@ -145,6 +145,16 @@ public class RangeQueriesTest extends BaseQueriesTest {
{buildSelectionQuery(RAW_LONG_COL, 250, 500, false), 250, 500, false},
{buildSelectionQuery(RAW_FLOAT_COL, 250, 500, false), 250, 500, false},
{buildSelectionQuery(RAW_DOUBLE_COL, 250, 500, false), 250, 500,
false},
+ {buildSelectionQuery(DICTIONARIZED_INT_COL, 300), 300, 300, true},
+ {buildSelectionQuery(RAW_INT_COL, 300), 300, 300, true},
+ {buildSelectionQuery(RAW_LONG_COL, 300), 300, 300, true},
+ {buildSelectionQuery(RAW_FLOAT_COL, 300), 300, 300, true},
+ {buildSelectionQuery(RAW_DOUBLE_COL, 300), 300, 300, true},
+ {buildSelectionQuery(DICTIONARIZED_INT_COL, 301), 301, 301, true},
+ {buildSelectionQuery(RAW_INT_COL, 301), 301, 301, true},
+ {buildSelectionQuery(RAW_LONG_COL, 301), 301, 301, true},
+ {buildSelectionQuery(RAW_FLOAT_COL, 301), 301, 301, true},
+ {buildSelectionQuery(RAW_DOUBLE_COL, 301), 301, 301, true}
};
}
@@ -158,6 +168,11 @@ public class RangeQueriesTest extends BaseQueriesTest {
}
}
+ private static String buildSelectionQuery(String filterCol, Number value) {
+ return "select " + RAW_INT_COL + " from " + RAW_TABLE_NAME + " where " +
filterCol + " = "
+ + formatValue(filterCol, value);
+ }
+
@DataProvider
public static Object[][] countTestCases() {
return new Object[][]{
@@ -171,6 +186,16 @@ public class RangeQueriesTest extends BaseQueriesTest {
{buildCountQuery(RAW_LONG_COL, 250, 500, false), 2},
{buildCountQuery(RAW_FLOAT_COL, 250, 500, false), 2},
{buildCountQuery(RAW_DOUBLE_COL, 250, 500, false), 2},
+ {buildCountQuery(DICTIONARIZED_INT_COL, 300), 1},
+ {buildCountQuery(RAW_INT_COL, 300), 1},
+ {buildCountQuery(RAW_LONG_COL, 300), 1},
+ {buildCountQuery(RAW_FLOAT_COL, 300), 1},
+ {buildCountQuery(RAW_DOUBLE_COL, 300), 1},
+ {buildCountQuery(DICTIONARIZED_INT_COL, 301), 0},
+ {buildCountQuery(RAW_INT_COL, 301), 0},
+ {buildCountQuery(RAW_LONG_COL, 301), 0},
+ {buildCountQuery(RAW_FLOAT_COL, 301), 0},
+ {buildCountQuery(RAW_DOUBLE_COL, 301), 0}
};
}
@@ -184,6 +209,10 @@ public class RangeQueriesTest extends BaseQueriesTest {
}
}
+ private static String buildCountQuery(String filterCol, Number value) {
+ return "select count(*) from " + RAW_TABLE_NAME + " where " + filterCol +
" = " + formatValue(filterCol, value);
+ }
+
private static String buildFilter(String filterCol, Number min, Number max) {
switch (filterCol) {
case DICTIONARIZED_INT_COL:
diff --git
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/readers/BitSlicedRangeIndexReader.java
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/readers/BitSlicedRangeIndexReader.java
index 0fde2d9ddc..7b422b74d6 100644
---
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/readers/BitSlicedRangeIndexReader.java
+++
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/index/readers/BitSlicedRangeIndexReader.java
@@ -20,7 +20,6 @@ package org.apache.pinot.segment.local.segment.index.readers;
import java.io.IOException;
import java.nio.ByteBuffer;
-import javax.annotation.Nullable;
import
org.apache.pinot.segment.local.segment.creator.impl.inv.BitSlicedRangeIndexCreator;
import org.apache.pinot.segment.local.utils.FPOrdering;
import org.apache.pinot.segment.spi.ColumnMetadata;
@@ -94,6 +93,32 @@ public class BitSlicedRangeIndexReader implements
RangeIndexReader<ImmutableRoar
return queryRangeBitmapCardinality(FPOrdering.ordinalOf(min),
FPOrdering.ordinalOf(max), 0xFFFFFFFFFFFFFFFFL);
}
+ @Override
+ public int getNumMatchingDocs(int value) {
+ if (value < _min) {
+ return 0;
+ }
+ return queryRangeBitmapCardinality(value - _min, _max - _min);
+ }
+
+ @Override
+ public int getNumMatchingDocs(long value) {
+ if (value < _min) {
+ return 0;
+ }
+ return queryRangeBitmapCardinality(value - _min, _max - _min);
+ }
+
+ @Override
+ public int getNumMatchingDocs(float value) {
+ return queryRangeBitmapCardinality(FPOrdering.ordinalOf(value),
0xFFFFFFFFL);
+ }
+
+ @Override
+ public int getNumMatchingDocs(double value) {
+ return queryRangeBitmapCardinality(FPOrdering.ordinalOf(value),
0xFFFFFFFFFFFFFFFFL);
+ }
+
@Override
public ImmutableRoaringBitmap getMatchingDocIds(int min, int max) {
// TODO: Handle this before reading the range index
@@ -130,36 +155,39 @@ public class BitSlicedRangeIndexReader implements
RangeIndexReader<ImmutableRoar
return queryRangeBitmap(FPOrdering.ordinalOf(min),
FPOrdering.ordinalOf(max), 0xFFFFFFFFFFFFFFFFL);
}
- // this index supports exact matches, so always return null for partial
matches
-
- @Nullable
@Override
- public ImmutableRoaringBitmap getPartiallyMatchingDocIds(int min, int max) {
- return null;
+ public ImmutableRoaringBitmap getMatchingDocIds(int value) {
+ if (value < _min) {
+ return new MutableRoaringBitmap();
+ }
+ return queryRangeBitmap(value - _min, _max - _min);
}
- @Nullable
@Override
- public ImmutableRoaringBitmap getPartiallyMatchingDocIds(long min, long max)
{
- return null;
+ public ImmutableRoaringBitmap getMatchingDocIds(long value) {
+ if (value < _min) {
+ return new MutableRoaringBitmap();
+ }
+ return queryRangeBitmap(value - _min, _max - _min);
}
- @Nullable
@Override
- public ImmutableRoaringBitmap getPartiallyMatchingDocIds(float min, float
max) {
- return null;
+ public ImmutableRoaringBitmap getMatchingDocIds(float value) {
+ return queryRangeBitmap(FPOrdering.ordinalOf(value), 0xFFFFFFFFL);
}
- @Nullable
@Override
- public ImmutableRoaringBitmap getPartiallyMatchingDocIds(double min, double
max) {
- return null;
+ public ImmutableRoaringBitmap getMatchingDocIds(double value) {
+ return queryRangeBitmap(FPOrdering.ordinalOf(value), 0xFFFFFFFFFFFFFFFFL);
}
private ImmutableRoaringBitmap queryRangeBitmap(long min, long max, long
columnMax) {
RangeBitmap rangeBitmap = mapRangeBitmap();
if (Long.compareUnsigned(max, columnMax) < 0) {
if (Long.compareUnsigned(min, 0) > 0) {
+ if (min == max) {
+ return rangeBitmap.eq(min).toMutableRoaringBitmap();
+ }
return rangeBitmap.between(min, max).toMutableRoaringBitmap();
}
return rangeBitmap.lte(max).toMutableRoaringBitmap();
@@ -173,10 +201,22 @@ public class BitSlicedRangeIndexReader implements
RangeIndexReader<ImmutableRoar
}
}
+ private ImmutableRoaringBitmap queryRangeBitmap(long value, long columnMax) {
+ RangeBitmap rangeBitmap = mapRangeBitmap();
+ if (Long.compareUnsigned(value, columnMax) < 0) {
+ return rangeBitmap.eq(value).toMutableRoaringBitmap();
+ } else {
+ return new MutableRoaringBitmap();
+ }
+ }
+
private int queryRangeBitmapCardinality(long min, long max, long columnMax) {
RangeBitmap rangeBitmap = mapRangeBitmap();
if (Long.compareUnsigned(max, columnMax) < 0) {
if (Long.compareUnsigned(min, 0) > 0) {
+ if (min == max) {
+ return (int) rangeBitmap.eqCardinality(min);
+ }
return (int) rangeBitmap.betweenCardinality(min, max);
}
return (int) rangeBitmap.lteCardinality(max);
@@ -188,6 +228,15 @@ public class BitSlicedRangeIndexReader implements
RangeIndexReader<ImmutableRoar
}
}
+ private int queryRangeBitmapCardinality(long value, long columnMax) {
+ RangeBitmap rangeBitmap = mapRangeBitmap();
+ if (Long.compareUnsigned(value, columnMax) < 0) {
+ return (int) rangeBitmap.eqCardinality(value);
+ } else {
+ return 0;
+ }
+ }
+
private RangeBitmap mapRangeBitmap() {
// note that this is a very cheap operation, no deserialization is required
ByteBuffer buffer = _dataBuffer.toDirectByteBuffer(_offset, (int)
(_dataBuffer.size() - _offset));
diff --git
a/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/segment/index/creator/BitSlicedIndexCreatorTest.java
b/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/segment/index/creator/BitSlicedIndexCreatorTest.java
index 28513e1766..d80723c352 100644
---
a/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/segment/index/creator/BitSlicedIndexCreatorTest.java
+++
b/pinot-segment-local/src/test/java/org/apache/pinot/segment/local/segment/index/creator/BitSlicedIndexCreatorTest.java
@@ -171,9 +171,12 @@ public class BitSlicedIndexCreatorTest {
}
testRange(reader, dataset, prev, prev + 1);
testRange(reader, dataset, prev + 1, prev + 1);
+ testPoint(reader, dataset, prev + 1);
testRange(reader, dataset, prev + 1, Integer.MAX_VALUE);
testRange(reader, dataset, Integer.MAX_VALUE, Integer.MAX_VALUE);
testRange(reader, dataset, Integer.MIN_VALUE, Integer.MAX_VALUE);
+ testPoint(reader, dataset, Integer.MIN_VALUE);
+ testPoint(reader, dataset, Integer.MAX_VALUE);
} finally {
FileUtils.forceDelete(rangeIndexFile);
}
@@ -192,6 +195,12 @@ public class BitSlicedIndexCreatorTest {
}
}
+ private static void testPoint(BitSlicedRangeIndexReader reader,
Dataset<int[]> dataset, int value) {
+ ImmutableRoaringBitmap reference = dataset.scan(value, value);
+ assertEquals(reader.getMatchingDocIds(value), reference);
+ assertEquals(reader.getNumMatchingDocs(value), reference.getCardinality());
+ }
+
private void testLong(Dataset<long[]> dataset)
throws IOException {
ColumnMetadata metadata = dataset.toColumnMetadata();
@@ -216,9 +225,12 @@ public class BitSlicedIndexCreatorTest {
}
testRange(reader, dataset, prev, prev + 1);
testRange(reader, dataset, prev + 1, prev + 1);
+ testPoint(reader, dataset, prev + 1);
testRange(reader, dataset, prev + 1, Long.MAX_VALUE);
testRange(reader, dataset, Long.MAX_VALUE, Long.MAX_VALUE);
testRange(reader, dataset, Long.MIN_VALUE, Long.MAX_VALUE);
+ testPoint(reader, dataset, Long.MIN_VALUE);
+ testPoint(reader, dataset, Long.MAX_VALUE);
} finally {
FileUtils.forceDelete(rangeIndexFile);
}
@@ -237,6 +249,12 @@ public class BitSlicedIndexCreatorTest {
}
}
+ private static void testPoint(BitSlicedRangeIndexReader reader,
Dataset<long[]> dataset, long value) {
+ ImmutableRoaringBitmap reference = dataset.scan(value, value);
+ assertEquals(reader.getMatchingDocIds(value), reference);
+ assertEquals(reader.getNumMatchingDocs(value), reference.getCardinality());
+ }
+
private void testFloat(Dataset<float[]> dataset)
throws IOException {
ColumnMetadata metadata = dataset.toColumnMetadata();
@@ -261,9 +279,12 @@ public class BitSlicedIndexCreatorTest {
}
testRange(reader, dataset, prev, prev + 1);
testRange(reader, dataset, prev + 1, prev + 1);
+ testPoint(reader, dataset, prev + 1);
testRange(reader, dataset, prev + 1, Float.POSITIVE_INFINITY);
testRange(reader, dataset, Float.POSITIVE_INFINITY,
Float.POSITIVE_INFINITY);
testRange(reader, dataset, Float.NEGATIVE_INFINITY,
Float.POSITIVE_INFINITY);
+ testPoint(reader, dataset, Float.POSITIVE_INFINITY);
+ testPoint(reader, dataset, Float.NEGATIVE_INFINITY);
} finally {
FileUtils.forceDelete(rangeIndexFile);
}
@@ -282,6 +303,12 @@ public class BitSlicedIndexCreatorTest {
}
}
+ private static void testPoint(BitSlicedRangeIndexReader reader,
Dataset<float[]> dataset, float value) {
+ ImmutableRoaringBitmap reference = dataset.scan(value, value);
+ assertEquals(reader.getMatchingDocIds(value), reference);
+ assertEquals(reader.getNumMatchingDocs(value), reference.getCardinality());
+ }
+
private void testDouble(Dataset<double[]> dataset)
throws IOException {
ColumnMetadata metadata = dataset.toColumnMetadata();
@@ -306,9 +333,12 @@ public class BitSlicedIndexCreatorTest {
}
testRange(reader, dataset, prev, prev + 1);
testRange(reader, dataset, prev + 1, prev + 1);
+ testPoint(reader, dataset, prev + 1);
testRange(reader, dataset, prev + 1, Double.POSITIVE_INFINITY);
testRange(reader, dataset, Double.POSITIVE_INFINITY,
Double.POSITIVE_INFINITY);
testRange(reader, dataset, Double.NEGATIVE_INFINITY,
Float.POSITIVE_INFINITY);
+ testPoint(reader, dataset, Double.POSITIVE_INFINITY);
+ testPoint(reader, dataset, Double.NEGATIVE_INFINITY);
} finally {
FileUtils.forceDelete(rangeIndexFile);
}
@@ -327,6 +357,12 @@ public class BitSlicedIndexCreatorTest {
}
}
+ private static void testPoint(BitSlicedRangeIndexReader reader,
Dataset<double[]> dataset, double value) {
+ ImmutableRoaringBitmap reference = dataset.scan(value, value);
+ assertEquals(reader.getMatchingDocIds(value), reference);
+ assertEquals(reader.getNumMatchingDocs(value), reference.getCardinality());
+ }
+
private static BitSlicedRangeIndexCreator
newBitSlicedIndexCreator(ColumnMetadata metadata) {
return metadata.hasDictionary() ? new BitSlicedRangeIndexCreator(INDEX_DIR,
metadata.getFieldSpec(), metadata.getCardinality()) : new
BitSlicedRangeIndexCreator(INDEX_DIR,
diff --git
a/pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/index/reader/RangeIndexReader.java
b/pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/index/reader/RangeIndexReader.java
index eabeef502a..f457056f17 100644
---
a/pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/index/reader/RangeIndexReader.java
+++
b/pinot-segment-spi/src/main/java/org/apache/pinot/segment/spi/index/reader/RangeIndexReader.java
@@ -21,6 +21,7 @@ package org.apache.pinot.segment.spi.index.reader;
import java.io.Closeable;
import javax.annotation.Nullable;
+
/**
* Interface for indexed range queries
* @param <T>
@@ -72,6 +73,46 @@ public interface RangeIndexReader<T> extends Closeable {
*/
int getNumMatchingDocs(double min, double max);
+ /**
+ * Returns the number of docs with an equal value.
+ * The count is exact unless {@see getPartiallyMatchingDocIds} returns a
non-null value.
+ * @param value the value
+ * @return the matching doc ids.
+ */
+ default int getNumMatchingDocs(int value) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns the number of docs with an equal value.
+ * The count is exact unless {@see getPartiallyMatchingDocIds} returns a
non-null value.
+ * @param value the value
+ * @return the matching doc ids.
+ */
+ default int getNumMatchingDocs(long value) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns the number of docs with an equal value.
+ * The count is exact unless {@see getPartiallyMatchingDocIds} returns a
non-null value.
+ * @param value the value
+ * @return the matching doc ids.
+ */
+ default int getNumMatchingDocs(float value) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns the number of docs with an equal value.
+ * The count is exact unless {@see getPartiallyMatchingDocIds} returns a
non-null value.
+ * @param value the value
+ * @return the matching doc ids.
+ */
+ default int getNumMatchingDocs(double value) {
+ throw new UnsupportedOperationException();
+ }
+
/**
* Returns doc ids with a value between min and max, both inclusive.
* Doc ids returned by this method must correspond to values which
@@ -116,6 +157,50 @@ public interface RangeIndexReader<T> extends Closeable {
@Nullable
T getMatchingDocIds(double min, double max);
+ /**
+ * Returns doc ids with an equal value.
+ * Doc ids returned by this method must correspond to values which
+ * satisfy the query.
+ * @param value the value
+ * @return the matching doc ids.
+ */
+ default T getMatchingDocIds(int value) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns doc ids with an equal value.
+ * Doc ids returned by this method must correspond to values which
+ * satisfy the query.
+ * @param value the value
+ * @return the matching doc ids.
+ */
+ default T getMatchingDocIds(long value) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns doc ids with an equal value.
+ * Doc ids returned by this method must correspond to values which
+ * satisfy the query.
+ * @param value the value
+ * @return the matching doc ids.
+ */
+ default T getMatchingDocIds(float value) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns doc ids with an equal value.
+ * Doc ids returned by this method must correspond to values which
+ * satisfy the query.
+ * @param value the value
+ * @return the matching doc ids.
+ */
+ default T getMatchingDocIds(double value) {
+ throw new UnsupportedOperationException();
+ }
+
/**
* Returns doc ids with a value between min and max, both inclusive.
* Doc ids returned by this method may correspond to values which
@@ -126,7 +211,9 @@ public interface RangeIndexReader<T> extends Closeable {
* @return the matching doc ids.
*/
@Nullable
- T getPartiallyMatchingDocIds(int min, int max);
+ default T getPartiallyMatchingDocIds(int min, int max) {
+ return null;
+ }
/**
* Returns doc ids with a value between min and max, both inclusive.
@@ -138,7 +225,9 @@ public interface RangeIndexReader<T> extends Closeable {
* @return the matching doc ids.
*/
@Nullable
- T getPartiallyMatchingDocIds(long min, long max);
+ default T getPartiallyMatchingDocIds(long min, long max) {
+ return null;
+ }
/**
* Returns doc ids with a value between min and max, both inclusive.
@@ -150,7 +239,9 @@ public interface RangeIndexReader<T> extends Closeable {
* @return the matching doc ids.
*/
@Nullable
- T getPartiallyMatchingDocIds(float min, float max);
+ default T getPartiallyMatchingDocIds(float min, float max) {
+ return null;
+ }
/**
* Returns doc ids with a value between min and max, both inclusive.
@@ -162,5 +253,7 @@ public interface RangeIndexReader<T> extends Closeable {
* @return the matching doc ids.
*/
@Nullable
- T getPartiallyMatchingDocIds(double min, double max);
+ default T getPartiallyMatchingDocIds(double min, double max) {
+ return null;
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]