Skip to content

ST_Intersects pushdown: vortex.geo.intersects kernel, DuckDB lowering, spatial function overrides#8704

Merged
HarukiMoriarty merged 11 commits into
developfrom
nemo/geo-intersects
Jul 13, 2026
Merged

ST_Intersects pushdown: vortex.geo.intersects kernel, DuckDB lowering, spatial function overrides#8704
HarukiMoriarty merged 11 commits into
developfrom
nemo/geo-intersects

Conversation

@HarukiMoriarty

Copy link
Copy Markdown
Contributor

Rationale for this change

ST_Intersects over native geometry columns currently evaluates inside DuckDB, exporting every row as GEOMETRY just to be tested. This adds a native vortex.geo.intersects kernel and pushes the filter into the scan: on SpatialBench SF1 (6M points vs a literal polygon), 406ms (DuckDB filter) / 36.6ms (SPATIAL_JOIN) -> 12.4ms pushed. Part of the native geospatial lane, following the ST_Distance/ST_DWithin pushdown.

What changes are included in this PR?

  • vortex-geo: GeoIntersects kernel.
  • vortex-duckdb: lower st_intersects(native column, GEOMETRY literal) like st_distance.
  • vortex-duckdb: shadow spatial's ST_Intersects with a non-fallible copy — DuckDB won't push can-throw filters through the projection every view-registered table has. The ST_DWithin override generalizes into a table-driven registry (spatial_overrides.hpp) shared by registration and the join-condition restore pass.

Note: drop GeoDistance's columnar point fast paths. geo is row-oriented, so kernels materialize rows regardless; hand-rolled columnar paths belong in a future columnar geometry compute library (pushed Q1: 5.4ms -> 12.6ms, still far ahead of unpushed).

@codspeed-hq

codspeed-hq Bot commented Jul 9, 2026

Copy link
Copy Markdown

Merging this PR will improve performance by 18.1%

⚡ 3 improved benchmarks
❌ 1 regressed benchmark
✅ 1660 untouched benchmarks
⏩ 42 skipped benchmarks1

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation chunked_varbinview_into_canonical[(100, 100)] 271.5 µs 306.7 µs -11.49%
Simulation chunked_bool_canonical_into[(1000, 10)] 26.7 µs 16.4 µs +62.94%
Simulation chunked_varbinview_into_canonical[(1000, 10)] 205.9 µs 169.6 µs +21.41%
Simulation eq_i64_constant 298.5 µs 268.7 µs +11.1%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing nemo/geo-intersects (1005fc5) with develop (443b79b)2

Open in CodSpeed

Footnotes

  1. 42 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. No successful run was found on develop (3d78175) during the generation of this report, so 443b79b was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

Comment thread vortex-duckdb/cpp/scalar_fn_pushdown.cpp Outdated
Comment thread vortex-duckdb/cpp/expr.cpp Outdated
@myrrc

myrrc commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Let's add a sqllogictest which checks our queries don't break if we override the functions

…, spatial overrides

vortex-geo gains a GeoIntersects kernel (OGC semantics: not disjoint,
boundary contact counts; the function id is kept stable so a future
stats-pruning rewrite can key on it). Kernels stay thin
materialize-and-delegate wrappers over geo: GeoDistance's columnar point
fast paths are removed as well, since geo computes row by row and
hand-rolled columnar paths belong in a future columnar geometry compute
library (noted in scalar_fn/mod.rs).

vortex-duckdb lowers two-argument st_intersects like st_distance, and
shadows the spatial functions whose registrations block filter pushdown:
st_intersects is marked fallible, which DuckDB will not push through a
view's projection, and st_dwithin folds its radius into bind data. The
overrides live in their own translation unit
(cpp/spatial_overrides.{hpp,cpp}) as a (name, arity, tweak) table shared
by registration and the join-condition restore pass, keeping
scalar_fn_pushdown.* free of spatial code. e2e tests cover every lowered
geo filter on a direct file scan and through a view.

Signed-off-by: Nemo Yu <zyu379@wisc.edu>
@HarukiMoriarty HarukiMoriarty requested a review from myrrc July 10, 2026 14:56

@myrrc myrrc left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Comment thread vortex-duckdb/cpp/include/expr.h Outdated
Comment thread vortex-duckdb/cpp/spatial_overrides.cpp Outdated
HarukiMoriarty and others added 2 commits July 10, 2026 11:58
The C declaration moves to spatial_overrides.h, which bindgen consumes
alongside the other C API headers, and SpatialOverrideRestore is declared
in spatial_overrides.hpp with its methods implemented in the .cpp,
matching scalar_fn_pushdown's layout.

Signed-off-by: Nemo Yu <zyu379@wisc.edu>
Comment thread vortex-geo/src/scalar_fn/intersects.rs Outdated
Comment thread vortex-geo/src/scalar_fn/intersects.rs Outdated
HarukiMoriarty and others added 2 commits July 10, 2026 13:37
Geometry arrays are never nullable, so GeoIntersects and GeoDistance
validate their operand dtypes in return_dtype, and the DuckDB lowering
no longer pushes nullable native geometry columns. The column length
checks use vortex_ensure_eq.

Signed-off-by: Nemo Yu <zyu379@wisc.edu>
@HarukiMoriarty HarukiMoriarty enabled auto-merge (squash) July 13, 2026 14:15
Comment thread vortex-geo/src/scalar_fn/distance.rs Outdated
Comment thread vortex-geo/src/scalar_fn/intersects.rs Outdated
`return_dtype` for GeoDistance and GeoIntersects only rejected nullable
operands, so a non-geometry column (e.g. i32) passed planning and failed
later inside the kernel. Extract a shared `validate_geometry_operands`
helper in the extension module that checks each operand is a native
geometry type and non-nullable, and call it from both `return_dtype`s.

Addresses review feedback on PR #8704.

Signed-off-by: Nemo Yu <zyu379@wisc.edu>
# Conflicts:
#	vortex-geo/src/extension/mod.rs
HarukiMoriarty added a commit that referenced this pull request Jul 13, 2026
…wering (#8720)

## Rationale for this change

<!--
Why are you proposing this change, and what is its impact? 
Is it part of a long term effort, or a bigger change?

If this PR is related to a tracked effort or an open issue, please link
to the relevant issue.
-->

Adds the third geo predicate kernel: OGC `ST_Contains`, following the
`GeoDistance`/`GeoIntersects` pattern from #8704. One kernel serves both
SQL spellings, since `ST_Within(a, b)` is `ST_Contains(b, a)`.

## What changes are included in this PR?

- `vortex-geo`: `GeoContains` kernel (`vortex.geo.contains`): OGC
containment, boundary excluded, delegating to `geo::Contains`.
Containment is asymmetric, so the operand roles are kept in separate
helpers and pinned by a test. Nullable operands are rejected like the
other kernels.
- `vortex-duckdb`: `st_contains` and `st_within` both lower to the
kernel — within is contains with the operands swapped. Both get spatial
override rows so their filters push through views.

Signed-off-by: Nemo Yu <zyu379@wisc.edu>
…wering (#8720)

## Rationale for this change

<!--
Why are you proposing this change, and what is its impact?
Is it part of a long term effort, or a bigger change?

If this PR is related to a tracked effort or an open issue, please link
to the relevant issue.
-->

Adds the third geo predicate kernel: OGC `ST_Contains`, following the
`GeoDistance`/`GeoIntersects` pattern from #8704. One kernel serves both
SQL spellings, since `ST_Within(a, b)` is `ST_Contains(b, a)`.

## What changes are included in this PR?

- `vortex-geo`: `GeoContains` kernel (`vortex.geo.contains`): OGC
containment, boundary excluded, delegating to `geo::Contains`.
Containment is asymmetric, so the operand roles are kept in separate
helpers and pinned by a test. Nullable operands are rejected like the
other kernels.
- `vortex-duckdb`: `st_contains` and `st_within` both lower to the
kernel — within is contains with the operands swapped. Both get spatial
override rows so their filters push through views.

Signed-off-by: Nemo Yu <zyu379@wisc.edu>
@HarukiMoriarty HarukiMoriarty merged commit 002e40a into develop Jul 13, 2026
68 of 69 checks passed
@HarukiMoriarty HarukiMoriarty deleted the nemo/geo-intersects branch July 13, 2026 16:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog/feature A new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants