Skip to main content

Coverage Validity

VectorX ships a set of geometry-processing helpers powered by shapely (GEOS under the hood), running as distributed Python UDFs across your Spark cluster. These functions fill gaps in the product's native ST_* surface — operations that are standard in shapely but have no direct built-in counterpart in Databricks Runtime.

Lightweight tier only

The functions on this page are available in the lightweight (pyvx) tier. Register pyvx before using them in SQL or Python:

from databricks.labs.gbx.pyvx import functions as vx
vx.register(spark)

A coverage is a set of polygons that together partition a region: each polygon may be valid on its own (passes ST_IsValid), yet the set may still be invalid because polygons overlap, or because gaps appear between them. Coverage validity is a set-level question that single-geometry validity functions cannot answer.

The canonical use cases are polygon layers where precise boundary alignment matters: administrative boundaries, parcels, land-cover patches, building footprints, or any layer where features share edges. Gaps and overlaps in such layers cause double-counting, broken spatial joins, and tile-rendering seams.

GeoBrix provides two SQL grouped-aggregate functions plus one Python-API helper:

  • gbx_st_coverageisvaliddetect: GROUP BY-based boolean check. true when the coverage has no overlaps and no gaps thinner than gap_width.
  • gbx_st_coverageinvalidedgesinspect: returns the union of the boundary segments that violate the coverage. Empty geometry when the coverage is clean.
  • coverage_simplifyrepair and simplify: Python-API only. Topology-preserving simplification of a whole coverage — shared edges stay shared after simplification.

What is gap_width?

Both gbx_st_coverageisvalid and gbx_st_coverageinvalidedges take a required gap_width argument:

  • Overlaps are always invalid, regardless of gap_width. Any two polygons in the group whose interiors intersect cause the coverage to fail.
  • Gaps thinner than gap_width are also flagged. A gap is a region between two adjacent polygons that does not belong to any polygon in the group. gap_width=0.0 means only overlaps are detected (no gap tolerance). A positive gap_width also flags slivers — thin corridors between nearly-touching polygons that may be digitizing artefacts rather than intentional gaps.

Worked example:

Coveragegap_width=0.0gap_width=0.5
Two squares sharing a clean edge (no gap, no overlap)validvalid
Two squares with a 0.3-unit gap between themvalid (gap ignored)invalid (gap detected)
Two squares with a 0.3-unit overlapinvalidinvalid

gbx_st_coverageisvalid

Lightweight grouped-agg

Check whether a group of polygons forms a valid coverage. Use GROUP BY to define which polygons belong to the same coverage — the aggregator evaluates the entire group at once and returns a single BOOLEAN per group.

Signature: gbx_st_coverageisvalid(geom, gap_width)

Parameters:

  • geom — Geometry column containing polygon or multipolygon values. Accepts WKB/EWKB/WKT/EWKT. Every member of the group must parse to a polygon type.
  • gap_width (DOUBLE, required) — Gap tolerance. Overlaps are always invalid; gaps thinner than this threshold are also flagged. Pass 0.0 to detect only overlaps.

Returns: BOOLEANtrue when the coverage is valid (no overlaps; no gaps narrower than gap_width). NULL when the group is empty or all members are null.

gap_width is required in SQL

gbx_st_coverageisvalid(geom) (one-argument form) does not resolve in SQL and will raise an UNRESOLVED_ROUTINE error. Always pass gap_width explicitly: gbx_st_coverageisvalid(geom, 0.0). The Python Column wrapper (vx.st_coverageisvalid) defaults gap_width to 0.0 and does not require it.

SELECT cov_id, gbx_st_coverageisvalid(geom, 0.0) AS is_valid
FROM coverage_parcels
GROUP BY cov_id
Example output
+------+--------+
|cov_id|is_valid|
+------+--------+
|1 |true |
+------+--------+
... (BOOLEAN — true when the polygon group has no overlaps and no slivers narrower than gap_width)

gbx_st_coverageinvalidedges

Lightweight grouped-agg

Return the union of the boundary segments that violate the coverage. Like gbx_st_coverageisvalid, this is a grouped aggregate — it evaluates all polygons in the group together and returns one geometry per group.

Signature: gbx_st_coverageinvalidedges(geom, gap_width)

Parameters:

  • geom — Geometry column. Accepts WKB/EWKB/WKT/EWKT. Every member must parse to a polygon type.
  • gap_width (DOUBLE, required) — Gap tolerance. Same semantics as gbx_st_coverageisvalid. Pass 0.0 to detect only overlap-zone edges.

Returns: BINARY — WKB (or EWKB if the input group carries a SRID): the union of the edges that violate the coverage. An empty MultiLineString is returned when the coverage is clean (no invalid edges). NULL when the group is empty.

The output geometry is useful for spatial debugging: join it back to a map layer to highlight exactly where the coverage breaks down.

gap_width is required in SQL

Same constraint as gbx_st_coverageisvalid — always pass the second argument explicitly.

SELECT cov_id, gbx_st_coverageinvalidedges(geom, 0.0) AS bad_edges
FROM coverage_overlap
GROUP BY cov_id
Example output
+------+---------+
|cov_id|bad_edges|
+------+---------+
|1 |[binary] |
+------+---------+
... (BINARY — union of the invalid edge segments; empty geometry when the coverage is clean)

coverage_simplify (Python API)

Lightweight

Topology-preserving simplification of a whole coverage. Unlike gbx_st_simplifypreservetopology (which simplifies each geometry independently), coverage_simplify simplifies the entire coverage as a unit — vertices on shared edges are dropped or kept together in both polygons, so boundaries that were shared before simplification remain shared after.

This is a Python-API only function. There is no SQL form; it operates directly on a Spark DataFrame.

Signature: coverage_simplify(df, group_col, geom_col, tolerance, simplify_boundary=True, out_col="geom_simplified")

Parameters:

  • df — Input Spark DataFrame.
  • group_col — Column name that identifies coverage groups (e.g. "cov_id"). All rows with the same value form one coverage and are simplified together.
  • geom_col — Column name of the geometry (WKB/EWKB/WKT/EWKT column).
  • tolerance (float) — Simplification tolerance in the geometry's coordinate units. Vertices whose removal would shift the boundary by less than tolerance are candidates for removal.
  • simplify_boundary (bool, default True) — Whether to simplify the outer boundary of the coverage (the edges that are not shared between polygons). Set to False to preserve the outer boundary exactly and simplify only interior shared edges.
  • out_col (str, default "geom_simplified") — Name of the new column added to the output DataFrame for the simplified geometry.

Returns: A Spark DataFrame with the same rows and all original columns, plus out_col (BINARY WKB/EWKB). Row identity is preserved — the output has exactly the same number of rows as the input (N→N), in the same order within each group.

Import:

from databricks.labs.gbx.pyvx import functions as vx
vx.register(spark)

result = vx.coverage_simplify(df, "admin_level", "geom_wkb", tolerance=50.0)
from databricks.labs.gbx.pyvx import functions as vx
from shapely import from_wkt, to_wkb

left = from_wkt("POLYGON((0 0, 2.5 0.001, 5 0, 5 5, 0 5, 0 0))")
right = from_wkt("POLYGON((5 0, 7.5 0.001, 10 0, 10 5, 5 5, 5 0))")
df = spark.createDataFrame(
[
(1, to_wkb(left)),
(1, to_wkb(right)),
],
["cov_id", "geom"],
)
result = vx.coverage_simplify(df, "cov_id", "geom", 0.1)
rows = result.collect()
Example output
+------+--------+----------------+
|cov_id| geom|geom_simplified |
+------+--------+----------------+
| 1|[binary]| [binary] |
| 1|[binary]| [binary] |
+------+--------+----------------+
... (BINARY — 2 rows in, 2 rows out; near-collinear vertices dropped, shared edge preserved)

When to use coverage_simplify vs gbx_st_simplifypreservetopology

ScenarioRecommendation
Simplify features in isolation (no shared edges)gbx_st_simplifypreservetopology — simpler, per-row operation
Simplify a parcel/boundary layer where features share edgescoverage_simplify — shared edges stay aligned after simplification
Very large coverage that does not fit in one executorSee Scale ceiling below

Scale ceiling

gbx_st_coverageisvalid, gbx_st_coverageinvalidedges, and coverage_simplify all require the entire coverage group to be resident on a single executor — GEOS needs to see all polygons in the group at once to evaluate shared edges. This is a fundamental constraint of coverage-level operations.

Practical limit: A coverage group that fits in one executor's Python worker (typically ~1–3 GB on Serverless, more on dedicated clusters) will process without issue. Large administrative boundary datasets with thousands of polygons and complex geometries may exceed this limit.

If your coverage exceeds executor memory:

  • Partition the coverage spatially into sub-regions (e.g. by grid cell or administrative hierarchy level) and process sub-regions independently.
  • Use gbx_st_coverageinvalidedges on candidate problem zones rather than on the full coverage.
  • For simplification of very large coverages, consider iterating over spatial tiles with an overlap buffer.

Future versions of GeoBrix will explore streaming coverage algorithms that relax the all-in-memory constraint.

Tier availability

FunctionLightweight (pyvx)Heavyweight (vectorx)
gbx_st_coverageisvalidSupported
gbx_st_coverageinvalidedgesSupported
coverage_simplifySupported (Python API)