|
19 | 19 |
|
20 | 20 | package org.apache.iceberg.expressions; |
21 | 21 |
|
22 | | -import com.google.common.collect.Iterables; |
23 | | -import com.google.common.collect.Lists; |
24 | 22 | import java.io.Serializable; |
25 | 23 | import java.util.Comparator; |
26 | 24 | import java.util.List; |
27 | | -import java.util.Objects; |
28 | 25 | import org.apache.iceberg.PartitionField; |
29 | 26 | import org.apache.iceberg.PartitionSpec; |
30 | 27 | import org.apache.iceberg.StructLike; |
@@ -200,42 +197,66 @@ public <T> Expression notEq(BoundReference<T> ref, Literal<T> lit) { |
200 | 197 | @Override |
201 | 198 | @SuppressWarnings("unchecked") |
202 | 199 | public <T> Expression predicate(BoundPredicate<T> pred) { |
203 | | - // Get the strict projection of this predicate in partition data, then use it to determine |
204 | | - // whether to return the original predicate. The strict projection returns true iff the |
205 | | - // original predicate would have returned true, so the predicate can be eliminated if the |
206 | | - // strict projection evaluates to true. |
| 200 | + /** |
| 201 | + * Get the strict projection and inclusive projection of this predicate in partition data, |
| 202 | + * then use them to determine whether to return the original predicate. The strict projection |
| 203 | + * returns true iff the original predicate would have returned true, so the predicate can be |
| 204 | + * eliminated if the strict projection evaluates to true. Similarly the inclusive projection |
| 205 | + * returns false iff the original predicate would have returned false, so the predicate can |
| 206 | + * also be eliminated if the inclusive projection evaluates to false. |
| 207 | + */ |
| 208 | + |
207 | 209 | // |
208 | 210 | // If there is no strict projection or if it evaluates to false, then return the predicate. |
209 | 211 | List<PartitionField> parts = spec.getFieldsBySourceId(pred.ref().fieldId()); |
210 | 212 | if (parts == null) { |
211 | 213 | return pred; // not associated inclusive a partition field, can't be evaluated |
212 | 214 | } |
213 | 215 |
|
214 | | - List<UnboundPredicate<?>> strictProjections = Lists.transform(parts, |
215 | | - part -> ((Transform<T, ?>) part.transform()).projectStrict(part.name(), pred)); |
| 216 | + for (PartitionField part : parts) { |
216 | 217 |
|
217 | | - if (Iterables.all(strictProjections, Objects::isNull)) { |
218 | | - // if there are no strict projections, the predicate must be in the residual |
219 | | - return pred; |
220 | | - } |
| 218 | + // checking the strict projection |
| 219 | + UnboundPredicate<?> strictProjection = ((Transform<T, ?>) part.transform()).projectStrict(part.name(), pred); |
| 220 | + Expression strictResult = null; |
| 221 | + |
| 222 | + if (strictProjection != null) { |
| 223 | + Expression bound = strictProjection.bind(spec.partitionType(), caseSensitive); |
| 224 | + if (bound instanceof BoundPredicate) { |
| 225 | + strictResult = super.predicate((BoundPredicate<?>) bound); |
| 226 | + } else { |
| 227 | + // if the result is not a predicate, then it must be a constant like alwaysTrue or alwaysFalse |
| 228 | + strictResult = bound; |
| 229 | + } |
| 230 | + } |
221 | 231 |
|
222 | | - Expression result = Expressions.alwaysFalse(); |
223 | | - for (UnboundPredicate<?> strictProjection : strictProjections) { |
224 | | - if (strictProjection == null) { |
225 | | - continue; |
| 232 | + if (strictResult != null && strictResult.op() == Expression.Operation.TRUE) { |
| 233 | + // If strict is true, returning true |
| 234 | + return Expressions.alwaysTrue(); |
226 | 235 | } |
227 | 236 |
|
228 | | - Expression bound = strictProjection.bind(spec.partitionType(), caseSensitive); |
229 | | - if (bound instanceof BoundPredicate) { |
230 | | - // evaluate the bound predicate, which will return alwaysTrue or alwaysFalse |
231 | | - result = Expressions.or(result, super.predicate((BoundPredicate<?>) bound)); |
232 | | - } else { |
233 | | - // update the result expression with the non-predicate residual (e.g. alwaysTrue) |
234 | | - result = Expressions.or(result, bound); |
| 237 | + // checking the inclusive projection |
| 238 | + UnboundPredicate<?> inclusiveProjection = ((Transform<T, ?>) part.transform()).project(part.name(), pred); |
| 239 | + Expression inclusiveResult = null; |
| 240 | + if (inclusiveProjection != null) { |
| 241 | + Expression boundInclusive = inclusiveProjection.bind(spec.partitionType(), caseSensitive); |
| 242 | + if (boundInclusive instanceof BoundPredicate) { |
| 243 | + // using predicate method specific to inclusive |
| 244 | + inclusiveResult = super.predicate((BoundPredicate<?>) boundInclusive); |
| 245 | + } else { |
| 246 | + // if the result is not a predicate, then it must be a constant like alwaysTrue or alwaysFalse |
| 247 | + inclusiveResult = boundInclusive; |
| 248 | + } |
235 | 249 | } |
| 250 | + |
| 251 | + if (inclusiveResult != null && inclusiveResult.op() == Expression.Operation.FALSE) { |
| 252 | + // If inclusive is false, returning false |
| 253 | + return Expressions.alwaysFalse(); |
| 254 | + } |
| 255 | + |
236 | 256 | } |
237 | 257 |
|
238 | | - return result; |
| 258 | + // neither strict not inclusive predicate was conclusive, returning the original pred |
| 259 | + return pred; |
239 | 260 | } |
240 | 261 |
|
241 | 262 | @Override |
|
0 commit comments