Spark: Backport Hilbert-curve sort clustering to Spark 4.0 and 3.5
- Dominant language
- Java
- Stars
- 9.2k
- Forks
- 3.5k
- Avg merge
- 2d 11h
- Merged PRs (30d)
- 132
Description
## Description
Hilbert-curve ordering for `rewriteDataFiles` compaction is currently
implemented only for **Spark 4.1**. The shared building blocks already live
in the version-agnostic `core` module, so the remaining work is to port the
Spark integration to the still-supported **Spark 4.0** and **Spark 3.5**
modules to keep feature parity across Spark versions.
Hilbert ordering, like Z-order, is an engine-side compaction strategy: it
sorts data files along a space-filling curve for better multi-column data
locality. It is **not** persisted in table metadata, so this is purely an
engine-integration backport with no table-format or format-version impact.
## Current state
Already present and shared (no change needed):
- `core`: `org.apache.iceberg.expressions.Hilbert` (the `Term`)
- `core`: `org.apache.iceberg.util.HilbertByteUtils`
Implemented only in Spark 4.1:
- New: `spark/v4.1/.../actions/SparkHilbertUDF.java`
- New: `spark/v4.1/.../actions/SparkHilbertFileRewriteRunner.java`
- Wired: `spark/v4.1/.../actions/RewriteDataFilesSparkAction.java`
- Wired: `spark/v4.1/.../Spark3Util.java` (parses the `hilbert(...)` sort transform)
- Wired: `spark/v4.1/.../procedures/RewriteDataFilesProcedure.java`
(accepts Hilbert sort expressions; rejects mixing Hilbert with Z-order or
identity sort columns)
Missing in Spark 4.0 and 3.5:
- `grep -r Hilbert spark/v4.0/spark/src/main` → 0 references
- `grep -r Hilbert spark/v3.5/spark/src/main` → 0 references
## Scope of work
For each of `spark/v4.0` and `spark/v3.5`:
1. Port `SparkHilbertUDF` and `SparkHilbertFileRewriteRunner`.
2. Wire `Spark3Util` to parse the `hilbert(...)` transform.
3. Wire `RewriteDataFilesSparkAction` to select the Hilbert runner.
4. Wire `RewriteDataFilesProcedure` to accept Hilbert sort expressions and
keep the existing guardrails (no mixing with Z-order / identity columns).
5. Port the corresponding tests (e.g. the Hilbert cases in
`TestRewriteDataFilesAction` and any Hilbert-specific unit tests).
## Notes / considerations
- Watch for Spark-version API differences (Scala 2.12 vs 2.13 for 3.5;
Connector/Catalyst API drift between 3.5, 4.0, 4.1). The UDF and runner
should port with minimal changes since the heavy lifting is in `core`.
- No format-version gating is required: Hilbert leaves no trace in table
metadata, so old readers/writers are unaffected.
- Keep behavior identical across versions; add tests that assert equivalence
of the produced ordering against the shared `HilbertByteUtils` reference,
mirroring the Z-order test pattern.
## Acceptance criteria
- Hilbert compaction usable from `rewriteDataFiles` action and the
`rewrite_data_files` SQL procedure on Spark 4.0 and 3.5.
- Parity tests pass on all three Spark versions.
- No changes to `core` or table-format spec.
---
*AI Disclosure: this issue was drafted with Claude Opus 4.6 (Claude Code) and reviewed by a human before filing.*
Follow-up of https://github.com/apache/iceberg/pull/16827
Contributor guide
Research direction
Compare the Spark 4.1 implementations of SparkHilbertUDF, SparkHilbertFileRewriteRunner, Spark3Util, RewriteDataFilesSparkAction, and RewriteDataFilesProcedure with their Spark 4.0 and 3.5 counterparts. Port the corresponding Hilbert cases from TestRewriteDataFilesAction and Hilbert-specific unit tests, accounting for Spark and Scala API differences. Done means rewriteDataFiles and rewrite_data_files support Hilbert ordering on both versions, parity tests pass, and core remains unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, scala, spark
- Domain
- data-engineering, distributed-systems
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 55/100