Hi Tanmay, Thanks, this is very helpful.
The field ID point makes sense. If we move forward with this design, we will avoid relying on a name-based mapping and revise it to use Iceberg field IDs instead. One distinction we wanted to clarify is the pruning layer. We already have file-level spatial pruning in our planner using existing partition information. The main reason we are considering an explicit bbox covering column is to improve performance below the file level, especially for row-level prefiltering before evaluating exact geometry predicates. We have seen row-group-level filtering mentioned in prior discussions, but we have not found much discussion around row-level bbox prefiltering or executor-side predicate rewrites using an associated bbox column. If you are aware of any prior discussion or planned direction around that layer, pointers would be very helpful. Thanks again, Min -----Original Message----- From: "Tanmay Rauth" <[email protected]> To: <[email protected]>; Cc: Sent: 2026-07-04 (토) 09:53:39 (UTC+09:00) Subject: Re: [DISCUSS] Declaring row-level bbox covering columns in Iceberg metadata Hi Min, Thanks for raising this, spatial pruning is worth getting right while the geo types are still young in v3. On Q1: there's no Iceberg-native "column X is the bbox covering for column Y" mechanism today. The native direction is different, the v3 spec defines bounding-box bounds for the geometry/geography columns themselves (the "Bounds for Geometry and Geography" section, stored as the geo_lower/geo_upper stat structs), and the plumbing is actively landing: Conversions already serializes geospatial bounds, and the API has bounding-box types plus an intersects evaluator (#12667). So the intended long-term path is pruning from the geometry column's own bounds, not a side column. The key caveat is that this native path doesn't appear to be functional end-to-end yet. As of current main, the metrics path deliberately skips producing geometry/geography bounds, #16850 has ParquetMetrics emit counts only for those types, since Parquet's lexicographic WKB min/max isn't meaningful, and as far as I can tell I don't see any spatial predicate or geo-bound-based pruning wired into the scan-planning/expression layer. Given that, your covering-column idea is a reasonable interim: a struct<xmin,ymin,xmax,ymax> of doubles gets ordinary min/max metrics and prunes via the numeric predicate pushdown Iceberg already supports, which is exactly the leverage GeoParquet's bbox covering exploits. The thing I'd flag is that it overlaps with where native geo bounds are clearly headed, so I'd design it to converge with that mechanism rather than as a permanent parallel convention. And honestly, given how fast this area is moving (WKB read/write and Spark geo types landed just this week), it may be higher-leverage to help push the native path, producing geo bounds and wiring the existing intersects evaluator into manifest/scan evaluation, than to build a separate covering convention. Worth pulling in the folks driving the geo work to confirm the current state and direction. One correctness point regardless of route: the spec gives geography bounds antimeridian semantics where xmin may be greater than xmax (an OR match across the ±180 seam). A hand-rolled bbox pruned via ordinary min/max stats treats that as a normal interval and would prune incorrectly near the dateline, so a covering column would need to special-case geography. On Q2's shape: Iceberg identifies columns by field ID, not name, so a name-keyed property like "geo.geom.covering.bbox": "geom_bbox" is brittle under rename/reorder. If a declared relationship is needed, anchoring it to field IDs fits the format better. On Q4/Q5: native Parquet GEOMETRY/GEOGRAPHY logical types and GeoParquet's file-level geo metadata are separate conventions, so writer-side geo emission is its own question; I'm not aware of an existing covering-column proposal, and #12667 plus the geo-bounds spec work are the prior art I'd anchor on. Net: reasonable as an interim while native geo-bound pruning doesn't appear to be available yet, but I'd coordinate it with that native path so it doesn't become a competing convention. Thanks, Tanmay Rauth On Tue, Jun 30, 2026 at 11:43 PM 이선민 (Sunmin Lee) <[email protected]> wrote: Hi everyone, We are considering a design in which a separate bbox column is stored alongside a geometry column, similar to the GeoParquet 1.1 bbox covering pattern: geom: geometry geom_bbox: struct< xmin: double, ymin: double, xmax: double, ymax: double > We would use `geom_bbox` as the row-level bbox covering for `geom`. We are interested in thoughts on the following approach: 1. Is there already an Iceberg-native mechanism for declaring that one column is the bbox covering for a geometry or geography column? 2. If not, would a table property be a reasonable way to declare this relationship? For example: "geo.geom.covering.bbox": "geom_bbox" 3. If a table property is a reasonable direction, is there a preferred naming convention or value format? In particular, would it make sense to follow the relevant GeoParquet 1.1 `covering.bbox` semantics and field-path format? 4. When writing native Parquet `GEOMETRY` / `GEOGRAPHY` logical types, would it make sense to also write GeoParquet 1.1 `geo` metadata so that existing GeoParquet readers can discover the bbox covering column? 5. Are there any existing discussions or proposals related to row-level geometry covering columns, metadata mappings, or planner support for rewriting or pushing down geometry predicates through an associated bbox covering column? We are mainly trying to understand whether this looks like a reasonable direction, and whether there are existing conventions or prior work that we should align with. Thanks, Min
