mirror of https://github.com/apache/druid.git
add NumericRangeIndex interface and BoundFilter support (#12830)
add NumericRangeIndex interface and BoundFilter support changes: * NumericRangeIndex interface, like LexicographicalRangeIndex but for numbers * BoundFilter now uses NumericRangeIndex if comparator is numeric and there is no extractionFn * NestedFieldLiteralColumnIndexSupplier.java now supports supplying NumericRangeIndex for single typed numeric nested literal columns * better faster stronger and (ever so slightly) more understandable * more tests, fix bug * fix style
This commit is contained in:
parent
d52abe7b38
commit
189e8b9d18
|
@ -165,7 +165,13 @@ public class SqlNestedDataBenchmark
|
|||
"SELECT JSON_VALUE(nested, '$.nesteder.long2' RETURNING BIGINT) FROM foo WHERE JSON_VALUE(nested, '$.nesteder.long2' RETURNING BIGINT) IN (1, 19, 21, 23, 25, 26, 46)",
|
||||
// 24, 25
|
||||
"SELECT long2 FROM foo WHERE long2 IN (1, 19, 21, 23, 25, 26, 46) GROUP BY 1",
|
||||
"SELECT JSON_VALUE(nested, '$.nesteder.long2' RETURNING BIGINT) FROM foo WHERE JSON_VALUE(nested, '$.nesteder.long2' RETURNING BIGINT) IN (1, 19, 21, 23, 25, 26, 46) GROUP BY 1"
|
||||
"SELECT JSON_VALUE(nested, '$.nesteder.long2' RETURNING BIGINT) FROM foo WHERE JSON_VALUE(nested, '$.nesteder.long2' RETURNING BIGINT) IN (1, 19, 21, 23, 25, 26, 46) GROUP BY 1",
|
||||
// 26, 27
|
||||
"SELECT SUM(long1) FROM foo WHERE double3 < 1005.0 AND double3 > 1000.0",
|
||||
"SELECT SUM(JSON_VALUE(nested, '$.long1' RETURNING BIGINT)) FROM foo WHERE JSON_VALUE(nested, '$.nesteder.double3' RETURNING DOUBLE) < 1005.0 AND JSON_VALUE(nested, '$.nesteder.double3' RETURNING DOUBLE) > 1000.0",
|
||||
// 28, 29
|
||||
"SELECT SUM(long1) FROM foo WHERE double3 < 2000.0 AND double3 > 1000.0",
|
||||
"SELECT SUM(JSON_VALUE(nested, '$.long1' RETURNING BIGINT)) FROM foo WHERE JSON_VALUE(nested, '$.nesteder.double3' RETURNING DOUBLE) < 2000.0 AND JSON_VALUE(nested, '$.nesteder.double3' RETURNING DOUBLE) > 1000.0"
|
||||
);
|
||||
|
||||
@Param({"5000000"})
|
||||
|
@ -203,7 +209,11 @@ public class SqlNestedDataBenchmark
|
|||
"22",
|
||||
"23",
|
||||
"24",
|
||||
"25"
|
||||
"25",
|
||||
"26",
|
||||
"27",
|
||||
"28",
|
||||
"29"
|
||||
})
|
||||
private String query;
|
||||
|
||||
|
|
|
@ -523,7 +523,7 @@ public class InDimFilter extends AbstractOptimizableDimFilter implements Filter
|
|||
private final Supplier<DruidFloatPredicate> floatPredicateSupplier;
|
||||
private final Supplier<DruidDoublePredicate> doublePredicateSupplier;
|
||||
|
||||
InFilterDruidPredicateFactory(
|
||||
public InFilterDruidPredicateFactory(
|
||||
final ExtractionFn extractionFn,
|
||||
final ValuesSet values
|
||||
)
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.druid.segment.column;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* An optimized column value {@link BitmapColumnIndex} provider for specialized processing of numeric value ranges.
|
||||
* This index does not match null values, union the results of this index with {@link NullValueIndex} if null values
|
||||
* should be considered part of the value range.
|
||||
*/
|
||||
public interface NumericRangeIndex
|
||||
{
|
||||
/**
|
||||
* Get a {@link BitmapColumnIndex} corresponding to the values supplied in the specified range. If supplied starting
|
||||
* value is null, the range will begin at the first non-null value in the underlying value dictionary. If the end
|
||||
* value is null, the range will extend to the last value in the underlying value dictionary.
|
||||
*/
|
||||
BitmapColumnIndex forRange(
|
||||
@Nullable Number startValue,
|
||||
boolean startStrict,
|
||||
@Nullable Number endValue,
|
||||
boolean endStrict
|
||||
);
|
||||
}
|
|
@ -48,6 +48,7 @@ import org.apache.druid.segment.column.ColumnIndexCapabilities;
|
|||
import org.apache.druid.segment.column.ColumnIndexSupplier;
|
||||
import org.apache.druid.segment.column.LexicographicalRangeIndex;
|
||||
import org.apache.druid.segment.column.NullValueIndex;
|
||||
import org.apache.druid.segment.column.NumericRangeIndex;
|
||||
import org.apache.druid.segment.vector.VectorColumnSelectorFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
@ -75,16 +76,13 @@ public class BoundFilter implements Filter
|
|||
if (!Filters.checkFilterTuningUseIndex(boundDimFilter.getDimension(), selector, filterTuning)) {
|
||||
return null;
|
||||
}
|
||||
if (supportShortCircuit()) {
|
||||
if (supportStringShortCircuit()) {
|
||||
final ColumnIndexSupplier indexSupplier = selector.getIndexSupplier(boundDimFilter.getDimension());
|
||||
if (indexSupplier == null) {
|
||||
return Filters.makeNullIndex(doesMatchNull(), selector);
|
||||
}
|
||||
final LexicographicalRangeIndex rangeIndex = indexSupplier.as(LexicographicalRangeIndex.class);
|
||||
if (rangeIndex == null) {
|
||||
// column
|
||||
return null;
|
||||
}
|
||||
if (rangeIndex != null) {
|
||||
final BitmapColumnIndex rangeBitmaps = rangeIndex.forRange(
|
||||
boundDimFilter.getLower(),
|
||||
boundDimFilter.isLowerStrict(),
|
||||
|
@ -95,6 +93,43 @@ public class BoundFilter implements Filter
|
|||
if (boundDimFilter.hasLowerBound() && !NullHandling.isNullOrEquivalent(boundDimFilter.getLower())) {
|
||||
return rangeBitmaps;
|
||||
} else {
|
||||
return wrapRangeIndexWithNullValueIndex(indexSupplier, rangeBitmaps);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (supportNumericShortCircuit()) {
|
||||
final ColumnIndexSupplier indexSupplier = selector.getIndexSupplier(boundDimFilter.getDimension());
|
||||
if (indexSupplier == null) {
|
||||
return Filters.makeNullIndex(doesMatchNull(), selector);
|
||||
}
|
||||
final NumericRangeIndex rangeIndex = indexSupplier.as(NumericRangeIndex.class);
|
||||
if (rangeIndex != null) {
|
||||
final Number lower = boundDimFilter.hasLowerBound() ? Double.parseDouble(boundDimFilter.getLower()) : null;
|
||||
final Number upper = boundDimFilter.hasUpperBound() ? Double.parseDouble(boundDimFilter.getUpper()) : null;
|
||||
final BitmapColumnIndex rangeBitmaps = rangeIndex.forRange(
|
||||
lower,
|
||||
boundDimFilter.isLowerStrict(),
|
||||
upper,
|
||||
boundDimFilter.isUpperStrict()
|
||||
);
|
||||
// preserve sad backwards compatible behavior where bound filter matches 'null' if the lower bound is not set
|
||||
if (boundDimFilter.hasLowerBound() && !NullHandling.isNullOrEquivalent(boundDimFilter.getLower())) {
|
||||
return rangeBitmaps;
|
||||
} else {
|
||||
return wrapRangeIndexWithNullValueIndex(indexSupplier, rangeBitmaps);
|
||||
}
|
||||
}
|
||||
}
|
||||
// fall back to predicate based index if it is available
|
||||
return Filters.makePredicateIndex(boundDimFilter.getDimension(), selector, getPredicateFactory());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private BitmapColumnIndex wrapRangeIndexWithNullValueIndex(
|
||||
ColumnIndexSupplier indexSupplier,
|
||||
BitmapColumnIndex rangeIndex
|
||||
)
|
||||
{
|
||||
final NullValueIndex nulls = indexSupplier.as(NullValueIndex.class);
|
||||
if (nulls == null) {
|
||||
return null;
|
||||
|
@ -105,7 +140,7 @@ public class BoundFilter implements Filter
|
|||
@Override
|
||||
public ColumnIndexCapabilities getIndexCapabilities()
|
||||
{
|
||||
return rangeBitmaps.getIndexCapabilities().merge(nullBitmap.getIndexCapabilities());
|
||||
return rangeIndex.getIndexCapabilities().merge(nullBitmap.getIndexCapabilities());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -113,7 +148,7 @@ public class BoundFilter implements Filter
|
|||
{
|
||||
return Math.min(
|
||||
1.0,
|
||||
rangeBitmaps.estimateSelectivity(totalRows) + nullBitmap.estimateSelectivity(totalRows)
|
||||
rangeIndex.estimateSelectivity(totalRows) + nullBitmap.estimateSelectivity(totalRows)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -122,24 +157,26 @@ public class BoundFilter implements Filter
|
|||
{
|
||||
return bitmapResultFactory.union(
|
||||
ImmutableList.of(
|
||||
rangeBitmaps.computeBitmapResult(bitmapResultFactory),
|
||||
rangeIndex.computeBitmapResult(bitmapResultFactory),
|
||||
nullBitmap.computeBitmapResult(bitmapResultFactory)
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
} else {
|
||||
return Filters.makePredicateIndex(boundDimFilter.getDimension(), selector, getPredicateFactory());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean supportShortCircuit()
|
||||
private boolean supportStringShortCircuit()
|
||||
{
|
||||
// Optimization for lexicographic bounds with no extractionFn => binary search through the index
|
||||
return boundDimFilter.getOrdering().equals(StringComparators.LEXICOGRAPHIC) && extractionFn == null;
|
||||
}
|
||||
|
||||
private boolean supportNumericShortCircuit()
|
||||
{
|
||||
// Optimization for numeric bounds with no extractionFn => binary search through the index
|
||||
return boundDimFilter.getOrdering().equals(StringComparators.NUMERIC) && extractionFn == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueMatcher makeMatcher(ColumnSelectorFactory factory)
|
||||
{
|
||||
|
|
|
@ -35,23 +35,27 @@ import it.unimi.dsi.fastutil.longs.LongIterator;
|
|||
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||
import org.apache.druid.collections.bitmap.BitmapFactory;
|
||||
import org.apache.druid.collections.bitmap.ImmutableBitmap;
|
||||
import org.apache.druid.common.config.NullHandling;
|
||||
import org.apache.druid.common.guava.GuavaUtils;
|
||||
import org.apache.druid.query.BitmapResultFactory;
|
||||
import org.apache.druid.query.filter.DruidDoublePredicate;
|
||||
import org.apache.druid.query.filter.DruidLongPredicate;
|
||||
import org.apache.druid.query.filter.DruidPredicateFactory;
|
||||
import org.apache.druid.segment.IntListUtils;
|
||||
import org.apache.druid.segment.column.BitmapColumnIndex;
|
||||
import org.apache.druid.segment.column.ColumnIndexSupplier;
|
||||
import org.apache.druid.segment.column.ColumnType;
|
||||
import org.apache.druid.segment.column.DruidPredicateIndex;
|
||||
import org.apache.druid.segment.column.LexicographicalRangeIndex;
|
||||
import org.apache.druid.segment.column.NullValueIndex;
|
||||
import org.apache.druid.segment.column.NumericRangeIndex;
|
||||
import org.apache.druid.segment.column.SimpleBitmapColumnIndex;
|
||||
import org.apache.druid.segment.column.SimpleImmutableBitmapIndex;
|
||||
import org.apache.druid.segment.column.SimpleImmutableBitmapIterableIndex;
|
||||
import org.apache.druid.segment.column.StringValueSetIndex;
|
||||
import org.apache.druid.segment.data.FixedIndexed;
|
||||
import org.apache.druid.segment.data.GenericIndexed;
|
||||
import org.apache.druid.segment.data.Indexed;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Iterator;
|
||||
|
@ -120,6 +124,8 @@ public class NestedFieldLiteralColumnIndexSupplier implements ColumnIndexSupplie
|
|||
case LONG:
|
||||
if (clazz.equals(StringValueSetIndex.class)) {
|
||||
return (T) new NestedLongLiteralValueSetIndex();
|
||||
} else if (clazz.equals(NumericRangeIndex.class)) {
|
||||
return (T) new NestedLongLiteralNumericRangeIndex();
|
||||
} else if (clazz.equals(DruidPredicateIndex.class)) {
|
||||
return (T) new NestedLongLiteralPredicateIndex();
|
||||
}
|
||||
|
@ -127,6 +133,8 @@ public class NestedFieldLiteralColumnIndexSupplier implements ColumnIndexSupplie
|
|||
case DOUBLE:
|
||||
if (clazz.equals(StringValueSetIndex.class)) {
|
||||
return (T) new NestedDoubleLiteralValueSetIndex();
|
||||
} else if (clazz.equals(NumericRangeIndex.class)) {
|
||||
return (T) new NestedDoubleLiteralNumericRangeIndex();
|
||||
} else if (clazz.equals(DruidPredicateIndex.class)) {
|
||||
return (T) new NestedDoubleLiteralPredicateIndex();
|
||||
}
|
||||
|
@ -153,47 +161,106 @@ public class NestedFieldLiteralColumnIndexSupplier implements ColumnIndexSupplie
|
|||
return bitmap == null ? bitmapFactory.makeEmptyImmutableBitmap() : bitmap;
|
||||
}
|
||||
|
||||
private IntIntPair getGlobalRange(
|
||||
@Nullable String startValue,
|
||||
/**
|
||||
* Gets a value range from a global dictionary and maps it to a range on the local {@link #dictionary}.
|
||||
* The starting index of the resulting range is inclusive, while the endpoint is exclusive [start, end)
|
||||
*/
|
||||
private <T> IntIntPair getLocalRangeFromDictionary(
|
||||
@Nullable T startValue,
|
||||
boolean startStrict,
|
||||
@Nullable String endValue,
|
||||
@Nullable T endValue,
|
||||
boolean endStrict,
|
||||
int rangeStart,
|
||||
int rangeEnd,
|
||||
GlobalIndexGetFunction getFn
|
||||
Indexed<T> globalDictionary,
|
||||
int adjust
|
||||
)
|
||||
{
|
||||
int startIndex, endIndex;
|
||||
int globalStartIndex, globalEndIndex;
|
||||
int localStartIndex, localEndIndex;
|
||||
if (startValue == null) {
|
||||
startIndex = rangeStart;
|
||||
globalStartIndex = adjust == 0 ? 1 : adjust; // global index 0 is always the null value
|
||||
} else {
|
||||
final int found = getFn.indexOf(startValue);
|
||||
final int found = globalDictionary.indexOf(startValue);
|
||||
if (found >= 0) {
|
||||
startIndex = startStrict ? found + 1 : found;
|
||||
globalStartIndex = adjust + (startStrict ? found + 1 : found);
|
||||
} else {
|
||||
startIndex = -(found + 1);
|
||||
globalStartIndex = adjust + (-(found + 1));
|
||||
}
|
||||
}
|
||||
// with starting global index settled, now lets find starting local index
|
||||
int localFound = dictionary.indexOf(globalStartIndex);
|
||||
if (localFound < 0) {
|
||||
// the first valid global index is not within the local dictionary, so the insertion point is where we begin
|
||||
localStartIndex = -(localFound + 1);
|
||||
} else {
|
||||
// valid global index in local dictionary, start here
|
||||
localStartIndex = localFound;
|
||||
}
|
||||
|
||||
if (endValue == null) {
|
||||
endIndex = rangeEnd;
|
||||
globalEndIndex = globalDictionary.size() + adjust;
|
||||
} else {
|
||||
final int found = getFn.indexOf(endValue);
|
||||
final int found = globalDictionary.indexOf(endValue);
|
||||
if (found >= 0) {
|
||||
endIndex = endStrict ? found : found + 1;
|
||||
globalEndIndex = adjust + (endStrict ? found : found + 1);
|
||||
} else {
|
||||
endIndex = -(found + 1);
|
||||
globalEndIndex = adjust + (-(found + 1));
|
||||
}
|
||||
}
|
||||
globalEndIndex = Math.max(globalStartIndex, globalEndIndex);
|
||||
// end index is not inclusive, so we find the last value in the local dictionary that falls within the range
|
||||
int localEndFound = dictionary.indexOf(globalEndIndex - 1);
|
||||
if (localEndFound < 0) {
|
||||
localEndIndex = -localEndFound;
|
||||
} else {
|
||||
// add 1 because the last valid global end value is in the local dictionary, and end index is exclusive
|
||||
localEndIndex = localEndFound + 1;
|
||||
}
|
||||
|
||||
endIndex = Math.max(startIndex, endIndex);
|
||||
return new IntIntImmutablePair(startIndex, endIndex);
|
||||
return new IntIntImmutablePair(localStartIndex, Math.min(dictionary.size(), localEndIndex));
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
interface GlobalIndexGetFunction
|
||||
private <T> BitmapColumnIndex makeRangeIndex(
|
||||
@Nullable T startValue,
|
||||
boolean startStrict,
|
||||
@Nullable T endValue,
|
||||
boolean endStrict,
|
||||
Indexed<T> globalDictionary,
|
||||
int adjust
|
||||
)
|
||||
{
|
||||
int indexOf(String value);
|
||||
final IntIntPair localRange = getLocalRangeFromDictionary(
|
||||
startValue,
|
||||
startStrict,
|
||||
endValue,
|
||||
endStrict,
|
||||
globalDictionary,
|
||||
adjust
|
||||
);
|
||||
final int startIndex = localRange.leftInt();
|
||||
final int endIndex = localRange.rightInt();
|
||||
return new SimpleImmutableBitmapIterableIndex()
|
||||
{
|
||||
@Override
|
||||
public Iterable<ImmutableBitmap> getBitmapIterable()
|
||||
{
|
||||
return () -> new Iterator<ImmutableBitmap>()
|
||||
{
|
||||
final IntIterator rangeIterator = IntListUtils.fromTo(startIndex, endIndex).iterator();
|
||||
|
||||
@Override
|
||||
public boolean hasNext()
|
||||
{
|
||||
return rangeIterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableBitmap next()
|
||||
{
|
||||
return getBitmap(rangeIterator.nextInt());
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private class NestedStringLiteralValueSetIndex implements StringValueSetIndex
|
||||
|
@ -274,7 +341,6 @@ public class NestedFieldLiteralColumnIndexSupplier implements ColumnIndexSupplie
|
|||
|
||||
private class NestedStringLiteralLexicographicalRangeIndex implements LexicographicalRangeIndex
|
||||
{
|
||||
|
||||
@Override
|
||||
public BitmapColumnIndex forRange(
|
||||
@Nullable String startValue,
|
||||
|
@ -283,70 +349,14 @@ public class NestedFieldLiteralColumnIndexSupplier implements ColumnIndexSupplie
|
|||
boolean endStrict
|
||||
)
|
||||
{
|
||||
return new SimpleImmutableBitmapIterableIndex()
|
||||
{
|
||||
@Override
|
||||
public Iterable<ImmutableBitmap> getBitmapIterable()
|
||||
{
|
||||
final IntIntPair range = getGlobalRange(
|
||||
startValue,
|
||||
return makeRangeIndex(
|
||||
NullHandling.emptyToNullIfNeeded(startValue),
|
||||
startStrict,
|
||||
endValue,
|
||||
NullHandling.emptyToNullIfNeeded(endValue),
|
||||
endStrict,
|
||||
0,
|
||||
globalDictionary.size(),
|
||||
globalDictionary::indexOf
|
||||
globalDictionary,
|
||||
0
|
||||
);
|
||||
final int start = range.leftInt(), end = range.rightInt();
|
||||
// iterates over the range of values in the global dictionary, mapping to relevant range in the local
|
||||
// dictionary, skipping duplicates
|
||||
return () -> new Iterator<ImmutableBitmap>()
|
||||
{
|
||||
int currentGlobalIndex = start;
|
||||
// initialize to -1 because findNext uses this field to check for duplicates, and could legitimately find
|
||||
// 0 for the first candidate
|
||||
@SuppressWarnings("UnusedAssignment")
|
||||
int currentLocalIndex = -1;
|
||||
{
|
||||
currentLocalIndex = findNext();
|
||||
}
|
||||
|
||||
private int findNext()
|
||||
{
|
||||
int candidateLocalIndex = Math.abs(dictionary.indexOf(currentGlobalIndex));
|
||||
while (currentGlobalIndex < end && candidateLocalIndex == currentLocalIndex) {
|
||||
currentGlobalIndex++;
|
||||
candidateLocalIndex = Math.abs(dictionary.indexOf(currentGlobalIndex));
|
||||
}
|
||||
if (currentGlobalIndex < end) {
|
||||
currentGlobalIndex++;
|
||||
return candidateLocalIndex;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext()
|
||||
{
|
||||
return currentLocalIndex != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableBitmap next()
|
||||
{
|
||||
int cur = currentLocalIndex;
|
||||
|
||||
if (cur == -1) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
currentLocalIndex = findNext();
|
||||
return getBitmap(cur);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -363,67 +373,53 @@ public class NestedFieldLiteralColumnIndexSupplier implements ColumnIndexSupplie
|
|||
@Override
|
||||
public Iterable<ImmutableBitmap> getBitmapIterable()
|
||||
{
|
||||
final IntIntPair stringsRange = getGlobalRange(
|
||||
final IntIntPair range = getLocalRangeFromDictionary(
|
||||
startValue,
|
||||
startStrict,
|
||||
endValue,
|
||||
endStrict,
|
||||
0,
|
||||
globalDictionary.size(),
|
||||
globalDictionary::indexOf
|
||||
globalDictionary,
|
||||
0
|
||||
);
|
||||
// iterates over the range of values in the global dictionary, mapping to relevant range in the local
|
||||
// dictionary, skipping duplicates
|
||||
final int start = range.leftInt(), end = range.rightInt();
|
||||
return () -> new Iterator<ImmutableBitmap>()
|
||||
{
|
||||
int currentGlobalIndex = stringsRange.leftInt();
|
||||
final int end = stringsRange.rightInt();
|
||||
// initialize to -1 because findNext uses this field to check for duplicates, and could legitimately find
|
||||
// 0 for the first candidate
|
||||
@SuppressWarnings("UnusedAssignment")
|
||||
int currentLocalIndex = -1;
|
||||
int currIndex = start;
|
||||
int found;
|
||||
|
||||
{
|
||||
currentLocalIndex = findNext();
|
||||
found = findNext();
|
||||
}
|
||||
|
||||
private int findNext()
|
||||
{
|
||||
int candidateLocalIndex = Math.abs(dictionary.indexOf(currentGlobalIndex));
|
||||
while (currentGlobalIndex < end && shouldSkipGlobal(candidateLocalIndex)) {
|
||||
currentGlobalIndex++;
|
||||
candidateLocalIndex = Math.abs(dictionary.indexOf(currentGlobalIndex));
|
||||
while (currIndex < end && !matcher.apply(globalDictionary.get(dictionary.get(currIndex)))) {
|
||||
currIndex++;
|
||||
}
|
||||
|
||||
if (currentGlobalIndex < end) {
|
||||
currentGlobalIndex++;
|
||||
return candidateLocalIndex;
|
||||
if (currIndex < end) {
|
||||
return currIndex++;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldSkipGlobal(int candidate)
|
||||
{
|
||||
return currentLocalIndex == candidate || !matcher.apply(globalDictionary.get(currentGlobalIndex));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean hasNext()
|
||||
{
|
||||
return currentLocalIndex != -1;
|
||||
return found != -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableBitmap next()
|
||||
{
|
||||
int cur = currentLocalIndex;
|
||||
int cur = found;
|
||||
|
||||
if (cur == -1) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
currentLocalIndex = findNext();
|
||||
found = findNext();
|
||||
return getBitmap(cur);
|
||||
}
|
||||
};
|
||||
|
@ -492,10 +488,8 @@ public class NestedFieldLiteralColumnIndexSupplier implements ColumnIndexSupplie
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private class NestedLongLiteralValueSetIndex implements StringValueSetIndex
|
||||
{
|
||||
|
||||
@Override
|
||||
public BitmapColumnIndex forValue(@Nullable String value)
|
||||
{
|
||||
|
@ -592,6 +586,27 @@ public class NestedFieldLiteralColumnIndexSupplier implements ColumnIndexSupplie
|
|||
}
|
||||
}
|
||||
|
||||
private class NestedLongLiteralNumericRangeIndex implements NumericRangeIndex
|
||||
{
|
||||
@Override
|
||||
public BitmapColumnIndex forRange(
|
||||
@Nullable Number startValue,
|
||||
boolean startStrict,
|
||||
@Nullable Number endValue,
|
||||
boolean endStrict
|
||||
)
|
||||
{
|
||||
return makeRangeIndex(
|
||||
startValue != null ? startValue.longValue() : null,
|
||||
startStrict,
|
||||
endValue != null ? endValue.longValue() : null,
|
||||
endStrict,
|
||||
globalLongDictionary,
|
||||
adjustLongId
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private class NestedLongLiteralPredicateIndex implements DruidPredicateIndex
|
||||
{
|
||||
@Override
|
||||
|
@ -658,7 +673,6 @@ public class NestedFieldLiteralColumnIndexSupplier implements ColumnIndexSupplie
|
|||
|
||||
private class NestedDoubleLiteralValueSetIndex implements StringValueSetIndex
|
||||
{
|
||||
|
||||
@Override
|
||||
public BitmapColumnIndex forValue(@Nullable String value)
|
||||
{
|
||||
|
@ -755,6 +769,27 @@ public class NestedFieldLiteralColumnIndexSupplier implements ColumnIndexSupplie
|
|||
}
|
||||
}
|
||||
|
||||
private class NestedDoubleLiteralNumericRangeIndex implements NumericRangeIndex
|
||||
{
|
||||
@Override
|
||||
public BitmapColumnIndex forRange(
|
||||
@Nullable Number startValue,
|
||||
boolean startStrict,
|
||||
@Nullable Number endValue,
|
||||
boolean endStrict
|
||||
)
|
||||
{
|
||||
return makeRangeIndex(
|
||||
startValue != null ? startValue.doubleValue() : null,
|
||||
startStrict,
|
||||
endValue != null ? endValue.doubleValue() : null,
|
||||
endStrict,
|
||||
globalDoubleDictionary,
|
||||
adjustDoubleId
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private class NestedDoubleLiteralPredicateIndex implements DruidPredicateIndex
|
||||
{
|
||||
@Override
|
||||
|
@ -818,7 +853,7 @@ public class NestedFieldLiteralColumnIndexSupplier implements ColumnIndexSupplie
|
|||
}
|
||||
}
|
||||
|
||||
private abstract class NestedAnyLiteralIndex
|
||||
private abstract class NestedVariantLiteralIndex
|
||||
{
|
||||
IntList getIndexes(@Nullable String value)
|
||||
{
|
||||
|
@ -858,7 +893,7 @@ public class NestedFieldLiteralColumnIndexSupplier implements ColumnIndexSupplie
|
|||
/**
|
||||
* {@link StringValueSetIndex} but for variant typed nested literal columns
|
||||
*/
|
||||
private class NestedVariantLiteralValueSetIndex extends NestedAnyLiteralIndex implements StringValueSetIndex
|
||||
private class NestedVariantLiteralValueSetIndex extends NestedVariantLiteralIndex implements StringValueSetIndex
|
||||
{
|
||||
@Override
|
||||
public BitmapColumnIndex forValue(@Nullable String value)
|
||||
|
@ -937,9 +972,8 @@ public class NestedFieldLiteralColumnIndexSupplier implements ColumnIndexSupplie
|
|||
/**
|
||||
* {@link DruidPredicateIndex} but for variant typed nested literal columns
|
||||
*/
|
||||
private class NestedVariantLiteralPredicateIndex extends NestedAnyLiteralIndex implements DruidPredicateIndex
|
||||
private class NestedVariantLiteralPredicateIndex extends NestedVariantLiteralIndex implements DruidPredicateIndex
|
||||
{
|
||||
|
||||
@Override
|
||||
public BitmapColumnIndex forPredicate(DruidPredicateFactory matcherFactory)
|
||||
{
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -852,7 +852,6 @@ public class CalciteNestedDataQueryTest extends BaseCalciteQueryTest
|
|||
.build()
|
||||
),
|
||||
ImmutableList.of(
|
||||
new Object[]{NullHandling.defaultStringValue(), 4L},
|
||||
new Object[]{"100", 2L}
|
||||
)
|
||||
);
|
||||
|
@ -954,6 +953,7 @@ public class CalciteNestedDataQueryTest extends BaseCalciteQueryTest
|
|||
.build()
|
||||
),
|
||||
ImmutableList.of(
|
||||
new Object[]{NullHandling.defaultStringValue(), 4L},
|
||||
new Object[]{"100", 2L}
|
||||
)
|
||||
);
|
||||
|
@ -1052,7 +1052,6 @@ public class CalciteNestedDataQueryTest extends BaseCalciteQueryTest
|
|||
.build()
|
||||
),
|
||||
ImmutableList.of(
|
||||
new Object[]{NullHandling.defaultStringValue(), 4L},
|
||||
new Object[]{"2.02", 2L}
|
||||
)
|
||||
);
|
||||
|
@ -1154,6 +1153,7 @@ public class CalciteNestedDataQueryTest extends BaseCalciteQueryTest
|
|||
.build()
|
||||
),
|
||||
ImmutableList.of(
|
||||
new Object[]{NullHandling.defaultStringValue(), 4L},
|
||||
new Object[]{"2.02", 2L}
|
||||
)
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue