Proposal: drop Spark 4.0 in Hudi 1.3.0 -- the only Spark 4 profile below the parquet 1.16 VARIANT floor #19585
Replies: 2 comments 1 reply
|
@CTTY @wombatu-kun @yihua For visibility Removing Spark 4.0 pretty much reduces our test coverage scope too if we want to push for Variant. |
|
+1, though the load-bearing argument is narrower than the TL;DR: Shredding is unreachable at default config. The drop does not make variant files self-describing. AVRO is the default write-path record type, and the avro path writes the variant group through One practical note for the drop PR: On gate (2): DBR 17.3 LTS ships Spark 4.0.0 with an LTS window into 2028, so that is the population to name in the deprecation note. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Proposal: drop the
spark4.0profile andhudi-spark-datasource/hudi-spark4.0.xin 1.3.0. Supported Spark matrix becomes 3.5, 4.1, 4.2.We want to push hard on VARIANT. Spark 4.0 is not "one minor behind" on variant -- its native variant support sits on the other side of a format boundary. It also reaches EOL on 2026-11-23.
Spark 4.0 ships parquet-java 1.15.2; 4.1 ships 1.16.0. Concretely, on 4.0:
VariantLogicalTypeAnnotation-- added in parquet-java 1.16.0 (apache/parquet-java#3070). Variant groups are written as bare, unannotatedmetadata/valuestructs, so nothing in the file metadata says "this is a VARIANT". Hudi falls back to a name/arity shape heuristic to recognise them.ParquetUnshreddedVariantConverterlooksvalue/metadataup by name but installs the converters at fixed[value, metadata]array positions; parquet then callsgetConverter(fieldIndex)by schema position. So a spec-ordered[metadata, value]file hands metadata bytes to the value converter ->MALFORMED_VARIANT(Spark 4.0.x reads Variant Parquet group fields by position instead of by name, causing MALFORMED_VARIANT #18334). Hudi carries a forkedReadSupportthat rewrites the requested schema to[value, metadata]purely to dodge this. Fixed in 4.1 by SPARK-54410. (Hudi's AVRO read path does not go through Spark's row converters and is unaffected.)buildFullVariantReadSchemais implemented for 4.1/4.2 only; 4.0 falls through to the baseNone.4.1 and 4.2 have none of these. This is a capability boundary, not a version gap.
The core problem: a compile floor, not a runtime gate
The annotation gap is not something a runtime check can paper over.
hudi-spark4-commonis compiled once per Spark profile, and under-Dspark4.0parquet.versionresolves to 1.15.2 -- so whilespark4.0is in the build, shared Spark 4 code cannot referenceVariantLogicalTypeAnnotationat all. No config flag, version check, or reflection shim buys that back.VariantLogicalTypeAnnotationspark3.5spark4.0spark4.1spark4.2This is why
BaseSpark4Adaptercarries a no-op that 4.1 and 4.2 each override identically:hudi-spark4-commonis exactly where cross-version variant logic belongs. The floor evicts that logic into per-version modules -- the duplication the version-module layout exists to prevent.What it costs today
Variant features get pushed out of shared code. In #18961,
Spark41VariantShreddingSchemaInferrerhad to go inhudi-spark4.1.xrather thanhudi-spark4-common, because it needs parquet 1.16-era APIs. CompareSpark4VariantShreddingProvider, which is shared across all three minors because it only needs Spark's variant library. That split is the compile floor drawn in code.Every variant PR pays a per-profile compile tax. #18961 records compile checks under "the spark3.5, spark4.0 and spark4.1 profiles" -- three passes, soon four with 4.2.
~5,000 LOC.
hudi-spark4.0.xis 21 files, eight with no 4.1 counterpart -- the forkedReadSupportabove, a forked legacy parquet format and reader, and a version-specific extended SQL parser and AST builder.Refactor multiplication. 34 commits touched the module since 2025-01-01, mostly cross-cutting refactors (#19193, #19195, #19147-#19150, #19132, #19455, #19460) applied N times because N version modules exist.
Why now: sequencing against #18961
#18961 (auto-infer per-file shredding schemas) is what makes shredded files common in the wild for the first time. That flips a latent Spark 4.0 gap into a live one.
hudi-spark4.1.x, so a 4.0 writer has none on the classpath and keeps writing unshredded.HoodieVariantReconstructionresolvesSpark4VariantShreddingProviderfromhudi-spark4-common, and fails loudly rather than droppingtyped_value.buildFullVariantReadSchemareturns the baseNone, plus SPARK-54410.I have not verified whether that last case throws
MALFORMED_VARIANTor returns wrong results -- and it is awkward to test today because no unit job runshudi-spark4.0.x(allspark4.0rows inbot.ymlare commented out under[CI-TRIM]; onlyspark3.5andspark4.2run unit tests).If we keep 4.0, that test plus likely an explicit read guard become prerequisites for flipping the inference default (#18937). If we drop it, neither is needed.
Scope: what this does not fix
Worth stating plainly so expectations are right.
This does not make Hudi's variant files self-describing to other engines. AVRO is the default write-path record type, and it converts variants via
AvroSchemaConverterWithTimestampNTZ, which emits a bareGroupTypewith no annotation. That converter lives inhudi-hadoop-common, which must keep compiling underspark3.5at parquet 1.13.1 -- so it cannot reference the annotation regardless of what happens to 4.0. OnlyHoodieRowParquetWriteSupportreachesapplyVariantLogicalType.Consequences:
hudi-spark4-commononly.isVariantPhysicalSchema(the name/arity shape heuristic) stays as the fallback for unannotated files. It cannot be deleted by this change.Annotating the AVRO path is a follow-up blocked on Spark 3.5, not on 4.0. I will file it separately.
Who is actually affected
Vendors shipping Spark 4.0 do not ship a Hudi version this change would reach:
emr-spark-8.0Databricks Runtime 17.3 LTS ships Spark 4.0.0 into Oct 2028, but does not bundle Hudi.
So the only population this could strand is self-managed deployments on Hudi 1.3.0+ with Spark 4.0 -- who control both versions and can move to 4.1/4.2. Existing Spark 4.0 users also keep working 1.2.x bundles; this removes a build profile going forward, it does not break deployments.
Happy to be corrected if there is a population I have missed.
Proposed motion
Drop
spark4.0in 1.3.0:hudi_trino_e2e.yml(currently hardcoded to-Dspark4.0/ thespark402compose) onto a higher Spark compose -- needstrinocoordinatoradded to the target pair.applyVariantLogicalTypeintoBaseSpark4Adapter, delete both overrides.spark4.0.0rows andspark400base images.isVariantPhysicalSchema-- still needed for unannotated files.Open question: does Hudi require a deprecation-notice release before removal? If so, deprecate in 1.3.0 and remove in 1.4.0.
References
All reactions