| /* |
| * 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.parquet.filter2.predicate; |
| |
| import java.io.Serializable; |
| import java.util.Locale; |
| |
| import org.apache.parquet.hadoop.metadata.ColumnPath; |
| import org.apache.parquet.io.api.Binary; |
| |
| import static org.apache.parquet.Preconditions.checkNotNull; |
| |
| /** |
| * These are the operators in a filter predicate expression tree. |
| * They are constructed by using the methods in {@link FilterApi} |
| */ |
| public final class Operators { |
| private Operators() { } |
| |
| public static abstract class Column<T extends Comparable<T>> implements Serializable { |
| private final ColumnPath columnPath; |
| private final Class<T> columnType; |
| |
| protected Column(ColumnPath columnPath, Class<T> columnType) { |
| checkNotNull(columnPath, "columnPath"); |
| checkNotNull(columnType, "columnType"); |
| this.columnPath = columnPath; |
| this.columnType = columnType; |
| } |
| |
| public Class<T> getColumnType() { |
| return columnType; |
| } |
| |
| public ColumnPath getColumnPath() { |
| return columnPath; |
| } |
| |
| @Override |
| public String toString() { |
| return "column(" + columnPath.toDotString() + ")"; |
| } |
| |
| @Override |
| public boolean equals(Object o) { |
| if (this == o) return true; |
| if (o == null || getClass() != o.getClass()) return false; |
| |
| Column column = (Column) o; |
| |
| if (!columnType.equals(column.columnType)) return false; |
| if (!columnPath.equals(column.columnPath)) return false; |
| |
| return true; |
| } |
| |
| @Override |
| public int hashCode() { |
| int result = columnPath.hashCode(); |
| result = 31 * result + columnType.hashCode(); |
| return result; |
| } |
| } |
| |
| public static interface SupportsEqNotEq { } // marker for columns that can be used with eq() and notEq() |
| public static interface SupportsLtGt extends SupportsEqNotEq { } // marker for columns that can be used with lt(), ltEq(), gt(), gtEq() |
| |
| public static final class IntColumn extends Column<Integer> implements SupportsLtGt { |
| IntColumn(ColumnPath columnPath) { |
| super(columnPath, Integer.class); |
| } |
| } |
| |
| public static final class LongColumn extends Column<Long> implements SupportsLtGt { |
| LongColumn(ColumnPath columnPath) { |
| super(columnPath, Long.class); |
| } |
| } |
| |
| public static final class DoubleColumn extends Column<Double> implements SupportsLtGt { |
| DoubleColumn(ColumnPath columnPath) { |
| super(columnPath, Double.class); |
| } |
| } |
| |
| public static final class FloatColumn extends Column<Float> implements SupportsLtGt { |
| FloatColumn(ColumnPath columnPath) { |
| super(columnPath, Float.class); |
| } |
| } |
| |
| public static final class BooleanColumn extends Column<Boolean> implements SupportsEqNotEq { |
| BooleanColumn(ColumnPath columnPath) { |
| super(columnPath, Boolean.class); |
| } |
| } |
| |
| public static final class BinaryColumn extends Column<Binary> implements SupportsLtGt { |
| BinaryColumn(ColumnPath columnPath) { |
| super(columnPath, Binary.class); |
| } |
| } |
| |
| // base class for Eq, NotEq, Lt, Gt, LtEq, GtEq |
| static abstract class ColumnFilterPredicate<T extends Comparable<T>> implements FilterPredicate, Serializable { |
| private final Column<T> column; |
| private final T value; |
| private final String toString; |
| |
| protected ColumnFilterPredicate(Column<T> column, T value) { |
| this.column = checkNotNull(column, "column"); |
| |
| // Eq and NotEq allow value to be null, Lt, Gt, LtEq, GtEq however do not, so they guard against |
| // null in their own constructors. |
| this.value = value; |
| |
| String name = getClass().getSimpleName().toLowerCase(Locale.ENGLISH); |
| this.toString = name + "(" + column.getColumnPath().toDotString() + ", " + value + ")"; |
| } |
| |
| public Column<T> getColumn() { |
| return column; |
| } |
| |
| public T getValue() { |
| return value; |
| } |
| |
| @Override |
| public String toString() { |
| return toString; |
| } |
| |
| @Override |
| public boolean equals(Object o) { |
| if (this == o) return true; |
| if (o == null || getClass() != o.getClass()) return false; |
| |
| ColumnFilterPredicate that = (ColumnFilterPredicate) o; |
| |
| if (!column.equals(that.column)) return false; |
| if (value != null ? !value.equals(that.value) : that.value != null) return false; |
| |
| return true; |
| } |
| |
| @Override |
| public int hashCode() { |
| int result = column.hashCode(); |
| result = 31 * result + (value != null ? value.hashCode() : 0); |
| result = 31 * result + getClass().hashCode(); |
| return result; |
| } |
| } |
| |
| public static final class Eq<T extends Comparable<T>> extends ColumnFilterPredicate<T> { |
| |
| // value can be null |
| Eq(Column<T> column, T value) { |
| super(column, value); |
| } |
| |
| @Override |
| public <R> R accept(Visitor<R> visitor) { |
| return visitor.visit(this); |
| } |
| |
| } |
| |
| public static final class NotEq<T extends Comparable<T>> extends ColumnFilterPredicate<T> { |
| |
| // value can be null |
| NotEq(Column<T> column, T value) { |
| super(column, value); |
| } |
| |
| @Override |
| public <R> R accept(Visitor<R> visitor) { |
| return visitor.visit(this); |
| } |
| } |
| |
| |
| public static final class Lt<T extends Comparable<T>> extends ColumnFilterPredicate<T> { |
| |
| // value cannot be null |
| Lt(Column<T> column, T value) { |
| super(column, checkNotNull(value, "value")); |
| } |
| |
| @Override |
| public <R> R accept(Visitor<R> visitor) { |
| return visitor.visit(this); |
| } |
| } |
| |
| public static final class LtEq<T extends Comparable<T>> extends ColumnFilterPredicate<T> { |
| |
| // value cannot be null |
| LtEq(Column<T> column, T value) { |
| super(column, checkNotNull(value, "value")); |
| } |
| |
| @Override |
| public <R> R accept(Visitor<R> visitor) { |
| return visitor.visit(this); |
| } |
| } |
| |
| |
| public static final class Gt<T extends Comparable<T>> extends ColumnFilterPredicate<T> { |
| |
| // value cannot be null |
| Gt(Column<T> column, T value) { |
| super(column, checkNotNull(value, "value")); |
| } |
| |
| @Override |
| public <R> R accept(Visitor<R> visitor) { |
| return visitor.visit(this); |
| } |
| } |
| |
| public static final class GtEq<T extends Comparable<T>> extends ColumnFilterPredicate<T> { |
| |
| // value cannot be null |
| GtEq(Column<T> column, T value) { |
| super(column, checkNotNull(value, "value")); |
| } |
| |
| @Override |
| public <R> R accept(Visitor<R> visitor) { |
| return visitor.visit(this); |
| } |
| } |
| |
| // base class for And, Or |
| private static abstract class BinaryLogicalFilterPredicate implements FilterPredicate, Serializable { |
| private final FilterPredicate left; |
| private final FilterPredicate right; |
| private final String toString; |
| |
| protected BinaryLogicalFilterPredicate(FilterPredicate left, FilterPredicate right) { |
| this.left = checkNotNull(left, "left"); |
| this.right = checkNotNull(right, "right"); |
| String name = getClass().getSimpleName().toLowerCase(Locale.ENGLISH); |
| this.toString = name + "(" + left + ", " + right + ")"; |
| } |
| |
| public FilterPredicate getLeft() { |
| return left; |
| } |
| |
| public FilterPredicate getRight() { |
| return right; |
| } |
| |
| @Override |
| public String toString() { |
| return toString; |
| } |
| |
| @Override |
| public boolean equals(Object o) { |
| if (this == o) return true; |
| if (o == null || getClass() != o.getClass()) return false; |
| |
| BinaryLogicalFilterPredicate that = (BinaryLogicalFilterPredicate) o; |
| |
| if (!left.equals(that.left)) return false; |
| if (!right.equals(that.right)) return false; |
| |
| return true; |
| } |
| |
| @Override |
| public int hashCode() { |
| int result = left.hashCode(); |
| result = 31 * result + right.hashCode(); |
| result = 31 * result + getClass().hashCode(); |
| return result; |
| } |
| } |
| |
| public static final class And extends BinaryLogicalFilterPredicate { |
| |
| And(FilterPredicate left, FilterPredicate right) { |
| super(left, right); |
| } |
| |
| @Override |
| public <R> R accept(Visitor<R> visitor) { |
| return visitor.visit(this); |
| } |
| } |
| |
| public static final class Or extends BinaryLogicalFilterPredicate { |
| |
| Or(FilterPredicate left, FilterPredicate right) { |
| super(left, right); |
| } |
| |
| @Override |
| public <R> R accept(Visitor<R> visitor) { |
| return visitor.visit(this); |
| } |
| } |
| |
| public static class Not implements FilterPredicate, Serializable { |
| private final FilterPredicate predicate; |
| private final String toString; |
| |
| Not(FilterPredicate predicate) { |
| this.predicate = checkNotNull(predicate, "predicate"); |
| this.toString = "not(" + predicate + ")"; |
| } |
| |
| public FilterPredicate getPredicate() { |
| return predicate; |
| } |
| |
| @Override |
| public String toString() { |
| return toString; |
| } |
| |
| @Override |
| public <R> R accept(Visitor<R> visitor) { |
| return visitor.visit(this); |
| } |
| |
| @Override |
| public boolean equals(Object o) { |
| if (this == o) return true; |
| if (o == null || getClass() != o.getClass()) return false; |
| Not not = (Not) o; |
| return predicate.equals(not.predicate); |
| } |
| |
| @Override |
| public int hashCode() { |
| return predicate.hashCode() * 31 + getClass().hashCode(); |
| } |
| } |
| |
| public static abstract class UserDefined<T extends Comparable<T>, U extends UserDefinedPredicate<T>> implements FilterPredicate, Serializable { |
| protected final Column<T> column; |
| |
| UserDefined(Column<T> column) { |
| this.column = checkNotNull(column, "column"); |
| } |
| |
| public Column<T> getColumn() { |
| return column; |
| } |
| |
| public abstract U getUserDefinedPredicate(); |
| |
| @Override |
| public <R> R accept(Visitor<R> visitor) { |
| return visitor.visit(this); |
| } |
| } |
| |
| public static final class UserDefinedByClass<T extends Comparable<T>, U extends UserDefinedPredicate<T>> extends UserDefined<T, U> { |
| private final Class<U> udpClass; |
| private final String toString; |
| private static final String INSTANTIATION_ERROR_MESSAGE = |
| "Could not instantiate custom filter: %s. User defined predicates must be static classes with a default constructor."; |
| |
| UserDefinedByClass(Column<T> column, Class<U> udpClass) { |
| super(column); |
| this.udpClass = checkNotNull(udpClass, "udpClass"); |
| String name = getClass().getSimpleName().toLowerCase(Locale.ENGLISH); |
| this.toString = name + "(" + column.getColumnPath().toDotString() + ", " + udpClass.getName() + ")"; |
| |
| // defensively try to instantiate the class early to make sure that it's possible |
| getUserDefinedPredicate(); |
| } |
| |
| public Class<U> getUserDefinedPredicateClass() { |
| return udpClass; |
| } |
| |
| @Override |
| public U getUserDefinedPredicate() { |
| try { |
| return udpClass.newInstance(); |
| } catch (InstantiationException | IllegalAccessException e) { |
| throw new RuntimeException(String.format(INSTANTIATION_ERROR_MESSAGE, udpClass), e); |
| } |
| } |
| |
| @Override |
| public String toString() { |
| return toString; |
| } |
| |
| @Override |
| public boolean equals(Object o) { |
| if (this == o) return true; |
| if (o == null || getClass() != o.getClass()) return false; |
| |
| UserDefinedByClass that = (UserDefinedByClass) o; |
| |
| if (!column.equals(that.column)) return false; |
| if (!udpClass.equals(that.udpClass)) return false; |
| |
| return true; |
| } |
| |
| @Override |
| public int hashCode() { |
| int result = column.hashCode(); |
| result = 31 * result + udpClass.hashCode(); |
| result = result * 31 + getClass().hashCode(); |
| return result; |
| } |
| } |
| |
| public static final class UserDefinedByInstance<T extends Comparable<T>, U extends UserDefinedPredicate<T> & Serializable> extends UserDefined<T, U> { |
| private final String toString; |
| private final U udpInstance; |
| |
| UserDefinedByInstance(Column<T> column, U udpInstance) { |
| super(column); |
| this.udpInstance = checkNotNull(udpInstance, "udpInstance"); |
| String name = getClass().getSimpleName().toLowerCase(Locale.ENGLISH); |
| this.toString = name + "(" + column.getColumnPath().toDotString() + ", " + udpInstance + ")"; |
| } |
| |
| @Override |
| public U getUserDefinedPredicate() { |
| return udpInstance; |
| } |
| |
| @Override |
| public String toString() { |
| return toString; |
| } |
| |
| @Override |
| public boolean equals(Object o) { |
| if (this == o) return true; |
| if (o == null || getClass() != o.getClass()) return false; |
| |
| UserDefinedByInstance that = (UserDefinedByInstance) o; |
| |
| if (!column.equals(that.column)) return false; |
| if (!udpInstance.equals(that.udpInstance)) return false; |
| |
| return true; |
| } |
| |
| @Override |
| public int hashCode() { |
| int result = column.hashCode(); |
| result = 31 * result + udpInstance.hashCode(); |
| result = result * 31 + getClass().hashCode(); |
| return result; |
| } |
| } |
| |
| // Represents the inverse of a UserDefined. It is equivalent to not(userDefined), without the use |
| // of the not() operator |
| public static final class LogicalNotUserDefined <T extends Comparable<T>, U extends UserDefinedPredicate<T>> implements FilterPredicate, Serializable { |
| private final UserDefined<T, U> udp; |
| private final String toString; |
| |
| LogicalNotUserDefined(UserDefined<T, U> userDefined) { |
| this.udp = checkNotNull(userDefined, "userDefined"); |
| this.toString = "inverted(" + udp + ")"; |
| } |
| |
| public UserDefined<T, U> getUserDefined() { |
| return udp; |
| } |
| |
| @Override |
| public <R> R accept(Visitor<R> visitor) { |
| return visitor.visit(this); |
| } |
| |
| @Override |
| public String toString() { |
| return toString; |
| } |
| |
| @Override |
| public boolean equals(Object o) { |
| if (this == o) return true; |
| if (o == null || getClass() != o.getClass()) return false; |
| |
| LogicalNotUserDefined that = (LogicalNotUserDefined) o; |
| |
| if (!udp.equals(that.udp)) return false; |
| |
| return true; |
| } |
| |
| @Override |
| public int hashCode() { |
| int result = udp.hashCode(); |
| result = result * 31 + getClass().hashCode(); |
| return result; |
| } |
| } |
| |
| } |