use of io.trino.spi.predicate.Range in project trino by trinodb.
the class TestOrcBloomFilters method testMatchesNonExpandedRange.
@Test
public void testMatchesNonExpandedRange() {
ColumnMetadata<ColumnStatistics> matchingStatisticsByColumnIndex = new ColumnMetadata<>(ImmutableList.of(new ColumnStatistics(null, 0, null, new IntegerStatistics(10L, 2000L, null), null, null, null, null, null, null, new Utf8BloomFilterBuilder(1000, 0.01).addLong(1500L).buildBloomFilter())));
Range range = Range.range(BIGINT, 1233L, true, 1235L, true);
TupleDomainOrcPredicate.TupleDomainOrcPredicateBuilder builder = TupleDomainOrcPredicate.builder().setBloomFiltersEnabled(true).addColumn(ROOT_COLUMN, Domain.create(ValueSet.ofRanges(range), false));
// Domain expansion doesn't take place -> no bloom filtering -> ranges overlap
assertTrue(builder.setDomainCompactionThreshold(1).build().matches(1L, matchingStatisticsByColumnIndex));
assertFalse(builder.setDomainCompactionThreshold(100).build().matches(1L, matchingStatisticsByColumnIndex));
}
use of io.trino.spi.predicate.Range in project trino by trinodb.
the class ElasticsearchQueryBuilder method buildTermQuery.
private static QueryBuilder buildTermQuery(BoolQueryBuilder queryBuilder, String columnName, Domain domain, Type type) {
for (Range range : domain.getValues().getRanges().getOrderedRanges()) {
BoolQueryBuilder rangeQueryBuilder = new BoolQueryBuilder();
Set<Object> valuesToInclude = new HashSet<>();
checkState(!range.isAll(), "Invalid range for column: %s", columnName);
if (range.isSingleValue()) {
valuesToInclude.add(range.getSingleValue());
} else {
if (!range.isLowUnbounded()) {
Object lowBound = getValue(type, range.getLowBoundedValue());
if (range.isLowInclusive()) {
rangeQueryBuilder.filter(new RangeQueryBuilder(columnName).gte(lowBound));
} else {
rangeQueryBuilder.filter(new RangeQueryBuilder(columnName).gt(lowBound));
}
}
if (!range.isHighUnbounded()) {
Object highBound = getValue(type, range.getHighBoundedValue());
if (range.isHighInclusive()) {
rangeQueryBuilder.filter(new RangeQueryBuilder(columnName).lte(highBound));
} else {
rangeQueryBuilder.filter(new RangeQueryBuilder(columnName).lt(highBound));
}
}
}
if (valuesToInclude.size() == 1) {
rangeQueryBuilder.filter(new TermQueryBuilder(columnName, getValue(type, getOnlyElement(valuesToInclude))));
}
queryBuilder.should(rangeQueryBuilder);
}
if (domain.isNullAllowed()) {
queryBuilder.should(new BoolQueryBuilder().mustNot(new ExistsQueryBuilder(columnName)));
}
return queryBuilder;
}
use of io.trino.spi.predicate.Range in project trino by trinodb.
the class TestPrometheusSplit method testPredicatePushDownSetsUpperBoundOnly.
@Test
public void testPredicatePushDownSetsUpperBoundOnly() {
long predicateHighValue = 1568638171999L;
Range highRange = Range.lessThanOrEqual(TIMESTAMP_COLUMN_TYPE, packDateTimeWithZone(predicateHighValue, UTC_KEY));
ValueSet valueSet = ValueSet.ofRanges(highRange);
Domain testDomain = Domain.create(valueSet, false);
TupleDomain<ColumnHandle> testTupleDomain = TupleDomain.withColumnDomains(ImmutableMap.of(new PrometheusColumnHandle("timestamp", TIMESTAMP_COLUMN_TYPE, 2), testDomain));
PrometheusTableHandle prometheusTableHandle = new PrometheusTableHandle("schemaName", "tableName").withPredicate(testTupleDomain);
io.airlift.units.Duration maxQueryRangeDuration = new io.airlift.units.Duration(120, TimeUnit.SECONDS);
io.airlift.units.Duration queryChunkSizeDuration = new io.airlift.units.Duration(30, TimeUnit.SECONDS);
Instant now = ofEpochMilli(1568638171999L + 600000L);
List<String> splitTimes = PrometheusSplitManager.generateTimesForSplits(now, maxQueryRangeDuration, queryChunkSizeDuration, prometheusTableHandle);
TemporalAmount expectedMaxQueryAsTime = java.time.Duration.ofMillis(maxQueryRangeDuration.toMillis() + ((splitTimes.size() - 1) * OFFSET_MILLIS));
String lastSplit = splitTimes.get(splitTimes.size() - 1);
Instant lastSplitAsTime = ofEpochMilli(longFromDecimalSecondString(lastSplit));
String earliestSplit = splitTimes.get(0);
Instant earliestSplitAsTime = ofEpochMilli(longFromDecimalSecondString(earliestSplit));
TemporalAmount queryChunkAsTime = java.time.Duration.ofMillis(queryChunkSizeDuration.toMillis());
java.time.Duration actualMaxDuration = Duration.between(earliestSplitAsTime.minus(queryChunkAsTime), lastSplitAsTime);
assertEquals(lastSplitAsTime.toEpochMilli(), 1568638171999L);
assertEquals(actualMaxDuration, expectedMaxQueryAsTime);
}
use of io.trino.spi.predicate.Range in project trino by trinodb.
the class PreparedStatementBuilder method toPredicate.
private static String toPredicate(int columnIndex, String columnName, Type type, Domain domain, Set<Integer> uuidColumnIndexes, List<ValueBuffer> bindValues) {
if (domain.getValues().isAll()) {
return domain.isNullAllowed() ? "TRUE" : columnName + " IS NOT NULL";
}
if (domain.getValues().isNone()) {
return domain.isNullAllowed() ? columnName + " IS NULL" : "FALSE";
}
return domain.getValues().getValuesProcessor().transform(ranges -> {
// Add disjuncts for ranges
List<String> disjuncts = new ArrayList<>();
List<Object> singleValues = new ArrayList<>();
// Add disjuncts for ranges
for (Range range : ranges.getOrderedRanges()) {
// Already checked
checkState(!range.isAll());
if (range.isSingleValue()) {
singleValues.add(range.getSingleValue());
} else {
List<String> rangeConjuncts = new ArrayList<>();
if (!range.isLowUnbounded()) {
Object bindValue = getBindValue(columnIndex, uuidColumnIndexes, range.getLowBoundedValue());
rangeConjuncts.add(toBindPredicate(columnName, range.isLowInclusive() ? ">=" : ">"));
bindValues.add(ValueBuffer.create(columnIndex, type, bindValue));
}
if (!range.isHighUnbounded()) {
Object bindValue = getBindValue(columnIndex, uuidColumnIndexes, range.getHighBoundedValue());
rangeConjuncts.add(toBindPredicate(columnName, range.isHighInclusive() ? "<=" : "<"));
bindValues.add(ValueBuffer.create(columnIndex, type, bindValue));
}
// If rangeConjuncts is null, then the range was ALL, which should already have been checked for
checkState(!rangeConjuncts.isEmpty());
disjuncts.add("(" + Joiner.on(" AND ").join(rangeConjuncts) + ")");
}
}
// Add back all of the possible single values either as an equality or an IN predicate
if (singleValues.size() == 1) {
disjuncts.add(toBindPredicate(columnName, "="));
bindValues.add(ValueBuffer.create(columnIndex, type, getBindValue(columnIndex, uuidColumnIndexes, getOnlyElement(singleValues))));
} else if (singleValues.size() > 1) {
disjuncts.add(columnName + " IN (" + Joiner.on(",").join(nCopies(singleValues.size(), "?")) + ")");
for (Object singleValue : singleValues) {
bindValues.add(ValueBuffer.create(columnIndex, type, getBindValue(columnIndex, uuidColumnIndexes, singleValue)));
}
}
// Add nullability disjuncts
checkState(!disjuncts.isEmpty());
if (domain.isNullAllowed()) {
disjuncts.add(columnName + " IS NULL");
}
return "(" + Joiner.on(" OR ").join(disjuncts) + ")";
}, discreteValues -> {
String values = Joiner.on(",").join(nCopies(discreteValues.getValues().size(), "?"));
String predicate = columnName + (discreteValues.isInclusive() ? "" : " NOT") + " IN (" + values + ")";
for (Object value : discreteValues.getValues()) {
bindValues.add(ValueBuffer.create(columnIndex, type, getBindValue(columnIndex, uuidColumnIndexes, value)));
}
if (domain.isNullAllowed()) {
predicate = "(" + predicate + " OR " + columnName + " IS NULL)";
}
return predicate;
}, allOrNone -> {
throw new IllegalStateException("Case should not be reachable");
});
}
use of io.trino.spi.predicate.Range in project trino by trinodb.
the class ExpressionConverter method toIcebergExpression.
private static Expression toIcebergExpression(String columnName, Type type, Domain domain) {
if (domain.isAll()) {
return alwaysTrue();
}
if (domain.getValues().isNone()) {
return domain.isNullAllowed() ? isNull(columnName) : alwaysFalse();
}
if (domain.getValues().isAll()) {
return domain.isNullAllowed() ? alwaysTrue() : not(isNull(columnName));
}
// Skip structural types. TODO (https://github.com/trinodb/trino/issues/8759) Evaluate Apache Iceberg's support for predicate on structural types
if (type instanceof ArrayType || type instanceof MapType || type instanceof RowType) {
// Fail fast. Ignoring expression could lead to data loss in case of deletions.
throw new UnsupportedOperationException("Unsupported type for expression: " + type);
}
if (type.isOrderable()) {
List<Range> orderedRanges = domain.getValues().getRanges().getOrderedRanges();
List<Object> icebergValues = new ArrayList<>();
List<Expression> rangeExpressions = new ArrayList<>();
for (Range range : orderedRanges) {
if (range.isSingleValue()) {
icebergValues.add(getIcebergLiteralValue(type, range.getLowBoundedValue()));
} else {
rangeExpressions.add(toIcebergExpression(columnName, range));
}
}
Expression ranges = or(rangeExpressions);
Expression values = icebergValues.isEmpty() ? alwaysFalse() : in(columnName, icebergValues);
Expression nullExpression = domain.isNullAllowed() ? isNull(columnName) : alwaysFalse();
return or(nullExpression, or(values, ranges));
}
throw new VerifyException(format("Unsupported type %s with domain values %s", type, domain));
}
Aggregations