You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/api/sql/Optimizer.md
+12-12Lines changed: 12 additions & 12 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -437,52 +437,52 @@ Spatial predicate push-down to GeoParquet is enabled by default. Users can manua
437
437
438
438
## Box2D filter pushdown
439
439
440
-
When a query filters on a `Box2D`-typed column (see [Box2D Functions](box2d/Box2D-Functions.md)) using `ST_BoxIntersects` or `ST_BoxContains` against a literal `Box2D`, Sedona translates the predicate into Parquet row-group inequalities on the column's underlying `xmin` / `ymin` / `xmax` / `ymax` leaves and pushes them down via `ParquetInputFormat.setFilterPredicate`. Parquet's row-group statistics machinery then skips row groups whose recorded min/max disprove the predicate — no file metadata scan is required.
440
+
When a query filters on a `Box2D`-typed column (see [Box2D Functions](box2d/Box2D-Functions.md)) using [ST_Intersects](Predicates/ST_Intersects.md) or [ST_Contains](Predicates/ST_Contains.md) against a literal `Box2D`, Sedona translates the predicate into Parquet row-group inequalities on the column's underlying `xmin` / `ymin` / `xmax` / `ymax` leaves and pushes them down via `ParquetInputFormat.setFilterPredicate`. Parquet's row-group statistics machinery then skips row groups whose recorded min/max disprove the predicate — no file metadata scan is required.
441
441
442
-
The pushdown applies whenever the column's Spark `dataType` is`Box2DUDT`. The simplest way to get one is to materialise the column with `ST_Box2D(geom)` before writing the dataset, or to use the SQL cast `CAST(geom AS box2d)`. Sedona's auto-generated `<geom>_bbox` covering column is written as a plain `struct<xmin, ymin, xmax, ymax>` — it satisfies the GeoParquet 1.1 covering-bbox contract but is not a `Box2D`, so `ST_BoxIntersects` / `ST_BoxContains` do not target it directly. Use it through [Push spatial predicates to GeoParquet](#push-spatial-predicates-to-geoparquet) (which prunes via the file-level bbox metadata), or write the column explicitly as `ST_Box2D(geom)` if you want row-group-level pruning through Box2D predicates.
442
+
The pushdown applies whenever both arguments resolve to Spark`Box2DUDT`. The simplest way to get a Box2D column is to materialise it with `ST_Box2D(geom)` before writing the dataset, or to use the SQL cast `CAST(geom AS box2d)`. Sedona's auto-generated `<geom>_bbox` covering column is written as a plain `struct<xmin, ymin, xmax, ymax>` — it satisfies the GeoParquet 1.1 covering-bbox contract but is not a `Box2D`, so the Box2D pushdown does not target it directly. Use it through [Push spatial predicates to GeoParquet](#push-spatial-predicates-to-geoparquet) (which prunes via the file-level bbox metadata), or write the column explicitly as `ST_Box2D(geom)` if you want row-group-level pruning.
|`ST_BoxIntersects(box_col, lit)`|`box.xmax >= lit.xmin AND box.xmin <= lit.xmax AND box.ymax >= lit.ymin AND box.ymin <= lit.ymax` (symmetric — reverse arg order is identical) |
459
-
|`ST_BoxContains(box_col, lit)`|`box.xmin <= lit.xmin AND box.xmax >= lit.xmax AND box.ymin <= lit.ymin AND box.ymax >= lit.ymax`|
460
-
|`ST_BoxContains(lit, box_col)`|`box.xmin >= lit.xmin AND box.xmax <= lit.xmax AND box.ymin >= lit.ymin AND box.ymax <= lit.ymax`|
|`ST_Intersects(box_col, lit)`|`box.xmax >= lit.xmin AND box.xmin <= lit.xmax AND box.ymax >= lit.ymin AND box.ymin <= lit.ymax` (symmetric — reverse arg order is identical) |
459
+
|`ST_Contains(box_col, lit)`|`box.xmin <= lit.xmin AND box.xmax >= lit.xmax AND box.ymin <= lit.ymin AND box.ymax >= lit.ymax`|
460
+
|`ST_Contains(lit, box_col)`|`box.xmin >= lit.xmin AND box.xmax <= lit.xmax AND box.ymin >= lit.ymin AND box.ymax <= lit.ymax`|
461
461
462
462
Pushdown is enabled by default and is gated by two flags. The optimizer rule that attaches the Box2D spatial filter is controlled by `spark.sedona.geoparquet.spatialFilterPushDown` (Sedona's master spatial-pushdown toggle, default `true`); the actual injection into the Parquet read path is then additionally gated by Spark's `spark.sql.parquet.filterPushdown` (default `true`). Disabling either disables Box2D pushdown.
463
463
464
464
Inverted-bound literals (`xmin > xmax` / `ymin > ymax`) are not pushed down — the predicate falls back to per-row evaluation so callers see the expected `IllegalArgumentException` from the scalar contract.
465
465
466
466
## Box2D spatial join
467
467
468
-
`ST_BoxIntersects` and `ST_BoxContains` between two `Box2D` columns route through the same physical operators as their `Geometry` counterparts (`ST_Intersects` / `ST_Covers`). At the executor boundary, each `Box2D` row is materialised into the implied rectangular polygon, after which the partitioner, R-tree index, and refine evaluator run unchanged. JTS short-circuits axis-aligned rectangle predicates via `RectangleIntersects` / `RectangleContains`, so the refine step pays only the four-double envelope comparison.
468
+
`ST_Intersects` and `ST_Contains` between two `Box2D` columns route through the same physical operators as their `Geometry` counterparts (`ST_Intersects` / `ST_Covers`). The planner picks the bbox path when both children resolve to `Box2DUDT`. At the executor boundary each `Box2D` row is materialised into the implied rectangular polygon, after which the partitioner, R-tree index, and refine evaluator run unchanged. JTS short-circuits axis-aligned rectangle predicates via `RectangleIntersects` / `RectangleContains`, so the refine step pays only the four-double envelope comparison.
469
469
470
-
`ST_BoxContains`uses `SpatialPredicate.COVERS` semantics at the join layer — JTS `covers` matches `ST_BoxContains`'s closed-interval contract (JTS `contains`, strict-interior, would reject edge-sharing pairs).
470
+
`ST_Contains` between two Box2D columns uses `SpatialPredicate.COVERS` semantics at the join layer — JTS `covers` matches the closed-interval contract (JTS `contains`, strict-interior, would reject edge-sharing pairs).
471
471
472
472
SQL Example — range join:
473
473
474
474
```sql
475
475
SELECT*
476
476
FROM left_boxes L, right_boxes R
477
-
WHEREST_BoxIntersects(L.box, R.box)
477
+
WHEREST_Intersects(L.box, R.box)
478
478
```
479
479
480
480
SQL Example — broadcast index join:
481
481
482
482
```sql
483
483
SELECT/*+ BROADCAST(R) */*
484
484
FROM left_boxes L, right_boxes R
485
-
WHEREST_BoxIntersects(L.box, R.box)
485
+
WHEREST_Intersects(L.box, R.box)
486
486
```
487
487
488
488
Inverted-bound input on either side raises `IllegalArgumentException` from the join-side validation path, matching the scalar predicate contract.
`ST_Contains(box_col, lit_box)` over a `Box2D` column and a literal `Box2D` (and the reversed form) is recognised by Sedona's spatial optimizer:
72
+
73
+
-**Filter pushdown.** When the column is a `Box2D` stored in GeoParquet, the predicate translates to Parquet row-group inequalities on the `xmin` / `ymin` / `xmax` / `ymax` leaves. See [Box2D filter pushdown](../Optimizer.md#box2d-filter-pushdown).
74
+
-**Spatial join.**`ST_Contains(a, b)` between two `Box2D` columns is planned as a range or broadcast-index join with `SpatialPredicate.COVERS` semantics (closed-interval containment — JTS `contains`, strict-interior, would reject edge-sharing pairs). See [Box2D spatial join](../Optimizer.md#box2d-spatial-join).
Copy file name to clipboardExpand all lines: docs/api/sql/Predicates/ST_Intersects.md
+33-2Lines changed: 33 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -19,12 +19,22 @@
19
19
20
20
# ST_Intersects
21
21
22
-
Introduction: Return true if A intersects B
22
+
Introduction: Return true if A intersects B. Polymorphic over input type:
23
+
24
+
-`(Geometry, Geometry)` — topological intersection via JTS.
25
+
-`(Geography, Geography)` — topological intersection via S2.
26
+
-`(Box2D, Box2D)` — closed-interval bbox intersection on both axes. Matches PostGIS `&&` on `box2d`. Edge- and corner-touching boxes count as intersecting. Throws `IllegalArgumentException` on inverted bounds.
27
+
-`(Box3D, Box3D)` — closed-interval bbox intersection on all three axes. Matches PostGIS `&&&` on `box3d`. Edge-, face-, and corner-touching boxes count as intersecting. Throws on inverted bounds on any axis.
`ST_Intersects(box_col, lit_box)` over a `Box2D` column and a literal `Box2D` is recognised by Sedona's spatial optimizer:
72
+
73
+
-**Filter pushdown.** When the column is a `Box2D` stored in GeoParquet, the predicate translates to Parquet row-group inequalities on the `xmin` / `ymin` / `xmax` / `ymax` leaves. See [Box2D filter pushdown](../Optimizer.md#box2d-filter-pushdown).
74
+
-**Spatial join.**`ST_Intersects(a, b)` between two `Box2D` columns is planned as a range or broadcast-index join. See [Box2D spatial join](../Optimizer.md#box2d-spatial-join).
Copy file name to clipboardExpand all lines: docs/api/sql/box2d/Box2D-Functions.md
+7-5Lines changed: 7 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -25,7 +25,7 @@ The `Box2D` type in Sedona represents a planar axis-aligned bounding box — a r
25
25
26
26
## Semantic notes
27
27
28
-
-`Box2D` values use closed-interval semantics: edge-touching boxes are considered intersecting and (per [ST_BoxContains](Box2D-Predicates/ST_BoxContains.md)) contained.
28
+
-`Box2D` values use closed-interval semantics: edge-touching boxes are considered intersecting and (per [ST_Contains](../Predicates/ST_Contains.md)) contained.
29
29
- Absence is represented by SQL `NULL` rather than an in-band sentinel.
30
30
- Bounds are required to be ordered (`xmin <= xmax`, `ymin <= ymax`). Inverted-bound values are reserved for a future antimeridian-wraparound semantics on geography bboxes; predicates and join planning throw `IllegalArgumentException` on inverted input today.
31
31
- Unlike [ST_Envelope](../Bounding-Box-Functions/ST_Envelope.md), which returns the envelope as a `Geometry` (typically a polygon, but JTS may return a `Point` or `LineString` for degenerate inputs), [ST_Box2D](Box2D-Constructors/ST_Box2D.md) always returns a typed `Box2D` value. Prefer the typed form when downstream code only needs the four bounds, and prefer the geometry form when downstream code expects a `Geometry`.
@@ -51,10 +51,12 @@ The same `ST_XMin` / `ST_YMin` / `ST_XMax` / `ST_YMax` functions also accept `Ge
51
51
52
52
## Box2D Predicates
53
53
54
+
`Box2D` inputs are accepted by the existing `ST_Intersects` / `ST_Contains` / `ST_DWithin` predicates as type-dispatched overloads — there are no separate `ST_Box*` functions.
55
+
54
56
| Function | Return type | Description | Since |
55
57
| :--- | :--- | :--- | :--- |
56
-
|[ST_BoxIntersects](Box2D-Predicates/ST_BoxIntersects.md)| Boolean | Closed-interval bbox intersection over two Box2D arguments. Matches PostGIS `&&` on `box2d`. | v1.9.1 |
57
-
|[ST_BoxContains](Box2D-Predicates/ST_BoxContains.md)| Boolean | Closed-interval bbox containment over two Box2D arguments. Matches PostGIS `~` on `box2d`. | v1.9.1 |
58
+
|[ST_Intersects](../Predicates/ST_Intersects.md)| Boolean | Closed-interval bbox intersection on both axes when both arguments are `Box2D`. Matches PostGIS `&&` on `box2d`. | v1.9.1 |
59
+
|[ST_Contains](../Predicates/ST_Contains.md)| Boolean | Closed-interval bbox containment on both axes when both arguments are `Box2D`. Matches PostGIS `~` on `box2d`. | v1.9.1 |
58
60
|[ST_DWithin](Box2D-Predicates/ST_DWithin.md)| Boolean | Closed-interval planar distance test between two Box2D rectangles. | v1.9.1 |
59
61
60
62
## Box2D Functions
@@ -85,5 +87,5 @@ The cast forms require the Sedona SQL parser extension (`spark.sql.extensions=or
85
87
86
88
Box2D-typed columns are first-class participants in Sedona's spatial optimizer:
87
89
88
-
-**Filter pushdown.**`ST_BoxIntersects` / `ST_BoxContains` predicates over a Box2D column and a literal Box2D push down to Parquet row-group statistics on the column's underlying `xmin` / `ymin` / `xmax` / `ymax` leaves. See [Query optimization → Box2D filter pushdown](../Optimizer.md#box2d-filter-pushdown).
89
-
-**Spatial joins.**`ST_BoxIntersects` and `ST_BoxContains`route through the same physical operators (`RangeJoinExec`, `BroadcastIndexJoinExec`) used for `ST_Intersects` / `ST_Covers`. See [Query optimization → Range join](../Optimizer.md#range-join) and [Broadcast index join](../Optimizer.md#broadcast-index-join).
90
+
-**Filter pushdown.**`ST_Intersects` / `ST_Contains`over a `Box2D` column and a literal `Box2D` push down to Parquet row-group statistics on the column's underlying `xmin` / `ymin` / `xmax` / `ymax` leaves. See [Query optimization → Box2D filter pushdown](../Optimizer.md#box2d-filter-pushdown).
91
+
-**Spatial joins.**`ST_Intersects` and `ST_Contains` between two `Box2D` columns route through the same physical operators (`RangeJoinExec`, `BroadcastIndexJoinExec`) used for the Geometry-typed forms — the dataType-aware planner picks the bbox path when both children are `Box2DUDT`. See [Query optimization → Range join](../Optimizer.md#range-join) and [Broadcast index join](../Optimizer.md#broadcast-index-join).
0 commit comments