Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 3.5k
API, Core: Add geospatial predicates and bounding box literals#14101
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base:main
Are you sure you want to change the base?
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
0dcf7189b4fdcfd10d9d39ec3e0a622a1017f0c13f6a0570b8ac6dafcb412b01b7dc935bfa1dcc5ada664ee66e73785d5301964964532bceFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -18,8 +18,10 @@ | ||
| */ | ||
| package org.apache.iceberg.expressions; | ||
| import java.nio.ByteBuffer; | ||
| import java.util.stream.Stream; | ||
| import org.apache.iceberg.expressions.Expression.Operation; | ||
| import org.apache.iceberg.geospatial.BoundingBox; | ||
| import org.apache.iceberg.relocated.com.google.common.base.Preconditions; | ||
| import org.apache.iceberg.relocated.com.google.common.collect.Lists; | ||
| import org.apache.iceberg.transforms.Transform; | ||
| @@ -202,6 +204,14 @@ public static UnboundPredicate<String> notStartsWith(UnboundTerm<String> expr, S | ||
| return new UnboundPredicate<>(Expression.Operation.NOT_STARTS_WITH, expr, value); | ||
| } | ||
| public static UnboundPredicate<ByteBuffer> stIntersects(String name, BoundingBox value) { | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this a
| ||
| return geospatialPredicate(Operation.ST_INTERSECTS, name, value); | ||
| } | ||
| public static UnboundPredicate<ByteBuffer> stDisjoint(String name, BoundingBox value) { | ||
| return geospatialPredicate(Operation.ST_DISJOINT, name, value); | ||
| } | ||
| public static <T> UnboundPredicate<T> in(String name, T... values) { | ||
| return predicate(Operation.IN, name, Lists.newArrayList(values)); | ||
| } | ||
| @@ -280,6 +290,13 @@ public static <T> UnboundPredicate<T> predicate(Operation op, UnboundTerm<T> exp | ||
| return new UnboundPredicate<>(op, expr); | ||
| } | ||
| @SuppressWarnings("unchecked") | ||
| static UnboundPredicate<ByteBuffer> geospatialPredicate( | ||
| Operation op, String name, BoundingBox value) { | ||
| return new UnboundPredicate<ByteBuffer>( | ||
| op, ref(name), (Literal<ByteBuffer>) (Literal<?>) Literal.of(value)); | ||
| } | ||
| public static True alwaysTrue() { | ||
| return True.INSTANCE; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -33,6 +33,8 @@ | ||
| import java.util.Locale; | ||
| import java.util.Objects; | ||
| import java.util.UUID; | ||
| import org.apache.iceberg.geospatial.BoundingBox; | ||
| import org.apache.iceberg.geospatial.GeospatialBound; | ||
| import org.apache.iceberg.relocated.com.google.common.base.Preconditions; | ||
| import org.apache.iceberg.relocated.com.google.common.io.BaseEncoding; | ||
| import org.apache.iceberg.types.Comparators; | ||
| @@ -87,6 +89,8 @@ static <T> Literal<T> from(T value) { | ||
| return (Literal<T>) new Literals.DecimalLiteral((BigDecimal) value); | ||
| } else if (value instanceof Variant) { | ||
| return (Literal<T>) new Literals.VariantLiteral((Variant) value); | ||
| } else if (value instanceof BoundingBox) { | ||
| return (Literal<T>) new Literals.BoundingBoxLiteral((BoundingBox) value); | ||
| } | ||
| throw new IllegalArgumentException( | ||
| @@ -747,4 +751,96 @@ public String toString() { | ||
| return "X'" + BASE16_ENCODING.encode(bytes) + "'"; | ||
| } | ||
| } | ||
| static class BoundingBoxLiteral implements Literal<BoundingBox> { | ||
| private static final Comparator<BoundingBox> CMP = | ||
| Comparators.<BoundingBox>nullsFirst().thenComparing(BoundingBoxLiteral::compare); | ||
| private final BoundingBox value; | ||
| BoundingBoxLiteral(BoundingBox value) { | ||
| Preconditions.checkNotNull(value, "Bounding box value cannot be null"); | ||
| this.value = value; | ||
| } | ||
| @Override | ||
| public BoundingBox value() { | ||
| return value; | ||
| } | ||
| @Override | ||
| public ByteBuffer toByteBuffer() { | ||
| return value.toByteBuffer(); | ||
| } | ||
| @Override | ||
| @SuppressWarnings("unchecked") | ||
| public <T> Literal<T> to(Type type) { | ||
| if (type.typeId() != Type.TypeID.GEOMETRY && type.typeId() != Type.TypeID.GEOGRAPHY) { | ||
| return null; | ||
| } | ||
| return (Literal<T>) this; | ||
| } | ||
| @Override | ||
| public Comparator<BoundingBox> comparator() { | ||
| return CMP; | ||
| } | ||
| Object writeReplace() throws ObjectStreamException { | ||
| return new SerializationProxies.BoundingBoxLiteralProxy(toByteBuffer()); | ||
| } | ||
| @Override | ||
| public String toString() { | ||
| return value().toString(); | ||
| } | ||
| @Override | ||
| public boolean equals(Object other) { | ||
| if (this == other) { | ||
| return true; | ||
| } | ||
| if (!(other instanceof BoundingBoxLiteral)) { | ||
| return false; | ||
| } | ||
| BoundingBoxLiteral that = (BoundingBoxLiteral) other; | ||
| return comparator().compare(value(), that.value()) == 0; | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this works, then the comparator is incorrect for values. This is comparing serialized bounding boxes. | ||
| } | ||
| @Override | ||
| public int hashCode() { | ||
| return Objects.hashCode(value()); | ||
| } | ||
| private static int compare(BoundingBox left, BoundingBox right) { | ||
| int cmp = compare(left.min(), right.min()); | ||
| if (cmp != 0) { | ||
| return cmp; | ||
| } | ||
| return compare(left.max(), right.max()); | ||
| } | ||
| private static int compare(GeospatialBound left, GeospatialBound right) { | ||
| int cmp = Double.compare(left.x(), right.x()); | ||
| if (cmp != 0) { | ||
| return cmp; | ||
| } | ||
| cmp = Double.compare(left.y(), right.y()); | ||
| if (cmp != 0) { | ||
| return cmp; | ||
| } | ||
| cmp = Double.compare(left.z(), right.z()); | ||
| if (cmp != 0) { | ||
| return cmp; | ||
| } | ||
| return Double.compare(left.m(), right.m()); | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.