com.facebook.presto.orc.TupleDomainOrcPredicate Maven / Gradle / Ivy
/*
* Licensed 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 com.facebook.presto.orc;
import com.facebook.presto.orc.metadata.BooleanStatistics;
import com.facebook.presto.orc.metadata.ColumnStatistics;
import com.facebook.presto.orc.metadata.RangeStatistics;
import com.facebook.presto.spi.predicate.Domain;
import com.facebook.presto.spi.predicate.Range;
import com.facebook.presto.spi.predicate.TupleDomain;
import com.facebook.presto.spi.predicate.ValueSet;
import com.facebook.presto.spi.type.StandardTypes;
import com.facebook.presto.spi.type.Type;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import io.airlift.slice.Slice;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import static com.facebook.presto.spi.type.BooleanType.BOOLEAN;
import static com.facebook.presto.spi.type.Decimals.encodeUnscaledValue;
import static com.facebook.presto.spi.type.Decimals.isLongDecimal;
import static com.facebook.presto.spi.type.Decimals.isShortDecimal;
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
public class TupleDomainOrcPredicate
implements OrcPredicate
{
private final TupleDomain effectivePredicate;
private final List> columnReferences;
public TupleDomainOrcPredicate(TupleDomain effectivePredicate, List> columnReferences)
{
this.effectivePredicate = requireNonNull(effectivePredicate, "effectivePredicate is null");
this.columnReferences = ImmutableList.copyOf(requireNonNull(columnReferences, "columnReferences is null"));
}
@Override
public boolean matches(long numberOfRows, Map statisticsByColumnIndex)
{
ImmutableMap.Builder domains = ImmutableMap.builder();
for (ColumnReference columnReference : columnReferences) {
ColumnStatistics columnStatistics = statisticsByColumnIndex.get(columnReference.getOrdinal());
Domain domain;
if (columnStatistics == null) {
// no stats for column
domain = Domain.all(columnReference.getType());
}
else {
domain = getDomain(columnReference.getType(), numberOfRows, columnStatistics);
}
domains.put(columnReference.getColumn(), domain);
}
TupleDomain stripeDomain = TupleDomain.withColumnDomains(domains.build());
return effectivePredicate.overlaps(stripeDomain);
}
@VisibleForTesting
public static Domain getDomain(Type type, long rowCount, ColumnStatistics columnStatistics)
{
if (rowCount == 0) {
return Domain.none(type);
}
if (columnStatistics == null) {
return Domain.all(type);
}
if (columnStatistics.hasNumberOfValues() && columnStatistics.getNumberOfValues() == 0) {
return Domain.onlyNull(type);
}
boolean hasNullValue = columnStatistics.getNumberOfValues() != rowCount;
if (type.getJavaType() == boolean.class && columnStatistics.getBooleanStatistics() != null) {
BooleanStatistics booleanStatistics = columnStatistics.getBooleanStatistics();
boolean hasTrueValues = (booleanStatistics.getTrueValueCount() != 0);
boolean hasFalseValues = (columnStatistics.getNumberOfValues() != booleanStatistics.getTrueValueCount());
if (hasTrueValues && hasFalseValues) {
return Domain.all(BOOLEAN);
}
if (hasTrueValues) {
return Domain.create(ValueSet.of(BOOLEAN, true), hasNullValue);
}
if (hasFalseValues) {
return Domain.create(ValueSet.of(BOOLEAN, false), hasNullValue);
}
}
else if (isShortDecimal(type)) {
return createDomain(type, hasNullValue, columnStatistics.getDecimalStatistics(), value -> value.unscaledValue().longValue());
}
else if (isLongDecimal(type)) {
return createDomain(type, hasNullValue, columnStatistics.getDecimalStatistics(), value -> encodeUnscaledValue(value.unscaledValue()));
}
else if (type.getTypeSignature().getBase().equals(StandardTypes.DATE) && columnStatistics.getDateStatistics() != null) {
return createDomain(type, hasNullValue, columnStatistics.getDateStatistics(), value -> (long) value);
}
else if (type.getJavaType() == long.class && columnStatistics.getIntegerStatistics() != null) {
return createDomain(type, hasNullValue, columnStatistics.getIntegerStatistics());
}
else if (type.getJavaType() == double.class && columnStatistics.getDoubleStatistics() != null) {
return createDomain(type, hasNullValue, columnStatistics.getDoubleStatistics());
}
else if (type.getJavaType() == Slice.class && columnStatistics.getStringStatistics() != null) {
return createDomain(type, hasNullValue, columnStatistics.getStringStatistics());
}
return Domain.create(ValueSet.all(type), hasNullValue);
}
private static > Domain createDomain(Type type, boolean hasNullValue, RangeStatistics rangeStatistics)
{
return createDomain(type, hasNullValue, rangeStatistics, value -> value);
}
private static > Domain createDomain(Type type, boolean hasNullValue, RangeStatistics rangeStatistics, Function function)
{
F min = rangeStatistics.getMin();
F max = rangeStatistics.getMax();
if (min != null && max != null) {
return Domain.create(ValueSet.ofRanges(Range.range(type, function.apply(min), true, function.apply(max), true)), hasNullValue);
}
if (max != null) {
return Domain.create(ValueSet.ofRanges(Range.lessThanOrEqual(type, function.apply(max))), hasNullValue);
}
if (min != null) {
return Domain.create(ValueSet.ofRanges(Range.greaterThanOrEqual(type, function.apply(min))), hasNullValue);
}
return Domain.create(ValueSet.all(type), hasNullValue);
}
public static class ColumnReference
{
private final C column;
private final int ordinal;
private final Type type;
public ColumnReference(C column, int ordinal, Type type)
{
this.column = requireNonNull(column, "column is null");
checkArgument(ordinal >= 0, "ordinal is negative");
this.ordinal = ordinal;
this.type = requireNonNull(type, "type is null");
}
public C getColumn()
{
return column;
}
public int getOrdinal()
{
return ordinal;
}
public Type getType()
{
return type;
}
@Override
public String toString()
{
return MoreObjects.toStringHelper(this)
.add("column", column)
.add("ordinal", ordinal)
.add("type", type)
.toString();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy