use of org.apache.druid.query.filter.ValueMatcher in project druid by druid-io.
the class ValueMatchers method makeStringValueMatcher.
/**
* Creates a predicate-based {@link ValueMatcher} for a string-typed selector.
*
* @param selector column selector
* @param predicateFactory predicate to match
* @param hasMultipleValues whether the column selector *might* have multiple values
*/
public static ValueMatcher makeStringValueMatcher(final DimensionSelector selector, final DruidPredicateFactory predicateFactory, final boolean hasMultipleValues) {
final Predicate<String> predicate = predicateFactory.makeStringPredicate();
final ValueMatcher booleanMatcher = toBooleanMatcherIfPossible(selector, hasMultipleValues, predicate);
if (booleanMatcher != null) {
return booleanMatcher;
} else {
return selector.makeValueMatcher(predicate);
}
}
use of org.apache.druid.query.filter.ValueMatcher in project druid by druid-io.
the class OrFilter method makeMatcher.
private static ValueMatcher makeMatcher(final ValueMatcher[] baseMatchers) {
Preconditions.checkState(baseMatchers.length > 0);
if (baseMatchers.length == 1) {
return baseMatchers[0];
}
return new ValueMatcher() {
@Override
public boolean matches() {
for (ValueMatcher matcher : baseMatchers) {
if (matcher.matches()) {
return true;
}
}
return false;
}
@Override
public void inspectRuntimeShape(RuntimeShapeInspector inspector) {
inspector.visit("firstBaseMatcher", baseMatchers[0]);
inspector.visit("secondBaseMatcher", baseMatchers[1]);
// Don't inspect the 3rd and all consequent baseMatchers, cut runtime shape combinations at this point.
// Anyway if the filter is so complex, Hotspot won't inline all calls because of the inline limit.
}
};
}
use of org.apache.druid.query.filter.ValueMatcher in project druid by druid-io.
the class OrFilter method makeMatcher.
@Override
public ValueMatcher makeMatcher(ColumnSelectorFactory factory) {
final ValueMatcher[] matchers = new ValueMatcher[filters.size()];
int i = 0;
for (Filter filter : filters) {
matchers[i++] = filter.makeMatcher(factory);
}
return makeMatcher(matchers);
}
use of org.apache.druid.query.filter.ValueMatcher in project druid by druid-io.
the class RowBasedColumnSelectorFactory method makeDimensionSelectorUndecorated.
private DimensionSelector makeDimensionSelectorUndecorated(DimensionSpec dimensionSpec) {
final String dimension = dimensionSpec.getDimension();
final ExtractionFn extractionFn = dimensionSpec.getExtractionFn();
if (ColumnHolder.TIME_COLUMN_NAME.equals(dimensionSpec.getDimension())) {
if (extractionFn == null) {
throw new UnsupportedOperationException("time dimension must provide an extraction function");
}
final ToLongFunction<T> timestampFunction = adapter.timestampFunction();
return new BaseSingleValueDimensionSelector() {
private long currentId = NO_ID;
private String currentValue;
@Override
protected String getValue() {
updateCurrentValue();
return currentValue;
}
@Override
public void inspectRuntimeShape(RuntimeShapeInspector inspector) {
inspector.visit("row", rowSupplier);
inspector.visit("extractionFn", extractionFn);
}
private void updateCurrentValue() {
if (rowIdSupplier == null || rowIdSupplier.getAsLong() != currentId) {
currentValue = extractionFn.apply(timestampFunction.applyAsLong(rowSupplier.get()));
if (rowIdSupplier != null) {
currentId = rowIdSupplier.getAsLong();
}
}
}
};
} else {
final Function<T, Object> dimFunction = adapter.columnFunction(dimension);
return new DimensionSelector() {
private long currentId = NO_ID;
private List<String> dimensionValues;
private final RangeIndexedInts indexedInts = new RangeIndexedInts();
@Override
public IndexedInts getRow() {
updateCurrentValues();
indexedInts.setSize(dimensionValues.size());
return indexedInts;
}
@Override
public ValueMatcher makeValueMatcher(@Nullable final String value) {
return new ValueMatcher() {
@Override
public boolean matches() {
updateCurrentValues();
if (dimensionValues.isEmpty()) {
return value == null;
}
for (String dimensionValue : dimensionValues) {
if (Objects.equals(NullHandling.emptyToNullIfNeeded(dimensionValue), value)) {
return true;
}
}
return false;
}
@Override
public void inspectRuntimeShape(RuntimeShapeInspector inspector) {
inspector.visit("row", rowSupplier);
inspector.visit("extractionFn", extractionFn);
}
};
}
@Override
public ValueMatcher makeValueMatcher(final Predicate<String> predicate) {
final boolean matchNull = predicate.apply(null);
return new ValueMatcher() {
@Override
public boolean matches() {
updateCurrentValues();
if (dimensionValues.isEmpty()) {
return matchNull;
}
for (String dimensionValue : dimensionValues) {
if (predicate.apply(NullHandling.emptyToNullIfNeeded(dimensionValue))) {
return true;
}
}
return false;
}
@Override
public void inspectRuntimeShape(RuntimeShapeInspector inspector) {
inspector.visit("row", rowSupplier);
inspector.visit("predicate", predicate);
inspector.visit("extractionFn", extractionFn);
}
};
}
@Override
public int getValueCardinality() {
return DimensionDictionarySelector.CARDINALITY_UNKNOWN;
}
@Override
public String lookupName(int id) {
updateCurrentValues();
return NullHandling.emptyToNullIfNeeded(dimensionValues.get(id));
}
@Override
public boolean nameLookupPossibleInAdvance() {
return false;
}
@Nullable
@Override
public IdLookup idLookup() {
return null;
}
@Nullable
@Override
public Object getObject() {
updateCurrentValues();
if (dimensionValues.size() == 1) {
return dimensionValues.get(0);
}
return dimensionValues;
}
@Override
public Class classOfObject() {
return Object.class;
}
@Override
public void inspectRuntimeShape(RuntimeShapeInspector inspector) {
inspector.visit("row", rowSupplier);
inspector.visit("extractionFn", extractionFn);
}
private void updateCurrentValues() {
if (rowIdSupplier == null || rowIdSupplier.getAsLong() != currentId) {
try {
final Object rawValue = dimFunction.apply(rowSupplier.get());
if (rawValue == null || rawValue instanceof String) {
final String s = NullHandling.emptyToNullIfNeeded((String) rawValue);
if (extractionFn == null) {
dimensionValues = Collections.singletonList(s);
} else {
dimensionValues = Collections.singletonList(extractionFn.apply(s));
}
} else if (rawValue instanceof List) {
// Consistent behavior with Rows.objectToStrings, but applies extractionFn too.
// noinspection rawtypes
final List<String> values = new ArrayList<>(((List) rawValue).size());
// noinspection rawtypes
for (final Object item : ((List) rawValue)) {
// commonly used when retrieving strings from input-row-like objects.
if (extractionFn == null) {
values.add(String.valueOf(item));
} else {
values.add(extractionFn.apply(String.valueOf(item)));
}
}
dimensionValues = values;
} else {
final List<String> nonExtractedValues = Rows.objectToStrings(rawValue);
dimensionValues = new ArrayList<>(nonExtractedValues.size());
for (final String value : nonExtractedValues) {
final String s = NullHandling.emptyToNullIfNeeded(value);
if (extractionFn == null) {
dimensionValues.add(s);
} else {
dimensionValues.add(extractionFn.apply(s));
}
}
}
} catch (Throwable e) {
currentId = NO_ID;
throw e;
}
if (rowIdSupplier != null) {
currentId = rowIdSupplier.getAsLong();
}
}
}
};
}
}
use of org.apache.druid.query.filter.ValueMatcher in project druid by druid-io.
the class StringDictionaryEncodedColumn method makeDimensionSelector.
@Override
public HistoricalDimensionSelector makeDimensionSelector(final ReadableOffset offset, @Nullable final ExtractionFn extractionFn) {
abstract class QueryableDimensionSelector extends AbstractDimensionSelector implements HistoricalDimensionSelector, IdLookup {
@Override
public int getValueCardinality() {
/*
This is technically wrong if
extractionFn != null && (extractionFn.getExtractionType() != ExtractionFn.ExtractionType.ONE_TO_ONE ||
!extractionFn.preservesOrdering())
However current behavior allows some GroupBy-V1 queries to work that wouldn't work otherwise and doesn't
cause any problems due to special handling of extractionFn everywhere.
See https://github.com/apache/druid/pull/8433
*/
return getCardinality();
}
@Override
public String lookupName(int id) {
final String value = StringDictionaryEncodedColumn.this.lookupName(id);
return extractionFn == null ? value : extractionFn.apply(value);
}
@Nullable
@Override
public ByteBuffer lookupNameUtf8(int id) {
return StringDictionaryEncodedColumn.this.lookupNameUtf8(id);
}
@Override
public boolean supportsLookupNameUtf8() {
return true;
}
@Override
public boolean nameLookupPossibleInAdvance() {
return true;
}
@Nullable
@Override
public IdLookup idLookup() {
return extractionFn == null ? this : null;
}
@Override
public int lookupId(String name) {
if (extractionFn != null) {
throw new UnsupportedOperationException("cannot perform lookup when applying an extraction function");
}
return StringDictionaryEncodedColumn.this.lookupId(name);
}
}
if (hasMultipleValues()) {
class MultiValueDimensionSelector extends QueryableDimensionSelector {
@Override
public IndexedInts getRow() {
return multiValueColumn.get(offset.getOffset());
}
@Override
public IndexedInts getRow(int offset) {
return multiValueColumn.get(offset);
}
@Override
public ValueMatcher makeValueMatcher(@Nullable String value) {
return DimensionSelectorUtils.makeValueMatcherGeneric(this, value);
}
@Override
public ValueMatcher makeValueMatcher(Predicate<String> predicate) {
return DimensionSelectorUtils.makeValueMatcherGeneric(this, predicate);
}
@Nullable
@Override
public Object getObject() {
return defaultGetObject();
}
@Override
public Class classOfObject() {
return Object.class;
}
@Override
public void inspectRuntimeShape(RuntimeShapeInspector inspector) {
inspector.visit("multiValueColumn", multiValueColumn);
inspector.visit("offset", offset);
inspector.visit("extractionFn", extractionFn);
}
}
return new MultiValueDimensionSelector();
} else {
class SingleValueQueryableDimensionSelector extends QueryableDimensionSelector implements SingleValueHistoricalDimensionSelector {
private final SingleIndexedInt row = new SingleIndexedInt();
@Override
public IndexedInts getRow() {
row.setValue(getRowValue());
return row;
}
public int getRowValue() {
return column.get(offset.getOffset());
}
@Override
public IndexedInts getRow(int offset) {
row.setValue(getRowValue(offset));
return row;
}
@Override
public int getRowValue(int offset) {
return column.get(offset);
}
@Override
public ValueMatcher makeValueMatcher(@Nullable final String value) {
if (extractionFn == null) {
final int valueId = lookupId(value);
if (valueId >= 0) {
return new ValueMatcher() {
@Override
public boolean matches() {
return getRowValue() == valueId;
}
@Override
public void inspectRuntimeShape(RuntimeShapeInspector inspector) {
inspector.visit("column", StringDictionaryEncodedColumn.this);
}
};
} else {
return BooleanValueMatcher.of(false);
}
} else {
// Employ caching BitSet optimization
return makeValueMatcher(Predicates.equalTo(value));
}
}
@Override
public ValueMatcher makeValueMatcher(final Predicate<String> predicate) {
final BitSet checkedIds = new BitSet(getCardinality());
final BitSet matchingIds = new BitSet(getCardinality());
// Lazy matcher; only check an id if matches() is called.
return new ValueMatcher() {
@Override
public boolean matches() {
final int id = getRowValue();
if (checkedIds.get(id)) {
return matchingIds.get(id);
} else {
final boolean matches = predicate.apply(lookupName(id));
checkedIds.set(id);
if (matches) {
matchingIds.set(id);
}
return matches;
}
}
@Override
public void inspectRuntimeShape(RuntimeShapeInspector inspector) {
inspector.visit("column", StringDictionaryEncodedColumn.this);
}
};
}
@Override
public Object getObject() {
return lookupName(getRowValue());
}
@Override
public Class classOfObject() {
return String.class;
}
@Override
public void inspectRuntimeShape(RuntimeShapeInspector inspector) {
inspector.visit("column", column);
inspector.visit("offset", offset);
inspector.visit("extractionFn", extractionFn);
}
}
return new SingleValueQueryableDimensionSelector();
}
}
Aggregations