wombatu-kun commented on code in PR #19808:
URL: https://github.com/apache/hudi/pull/19808#discussion_r3910318194


##########
hudi-common/src/main/java/org/apache/hudi/common/config/HoodieStorageConfig.java:
##########
@@ -308,22 +310,26 @@ public class HoodieStorageConfig extends HoodieConfig {
 
   public static final ConfigProperty<Boolean> 
PARQUET_VARIANT_SHREDDING_SCHEMA_INFERENCE_ENABLED = ConfigProperty
       .key("hoodie.parquet.variant.shredding.schema.inference.enabled")
-      .defaultValue(false)
+      .defaultValue(true)
       .sinceVersion("1.3.0")
-      .withDocumentation("When enabled, the shredding schema for variant 
columns without an explicit "
-          + "typed_value in the write schema is inferred automatically per 
parquet file from a sample of "
-          + "the records written to that file, mirroring Spark 4.1's "
-          + "spark.sql.variant.inferShreddingSchema. Requires Spark 4.1+ on 
the writer classpath; "
-          + "writes stay unshredded otherwise (Spark 4.0, Flink, Java 
engines). Applies to every "
-          + "parquet file the writer produces: base files and, on table 
version 10+, the native "
+      .withDocumentation("Infers the shredding schema of variant columns that 
have no explicit "
+          + "typed_value in the write schema, per parquet file, from a sample 
of the records written "
+          + "to that file, mirroring Spark 4.1's 
spark.sql.variant.inferShreddingSchema (also on by "
+          + "default there). Takes effect only when a Spark 4.1+ writer is on 
the classpath; other "
+          + "writers (Spark 3.x, Spark 4.0, Flink, Java) ignore it and write 
unshredded. Applies to "
+          + "every parquet file the writer produces: base files and, on table 
version 10+, the native "
           + "parquet log files of MOR tables (each infers its own schema). 
Data blocks inside "
           + "Avro-format log files, whether Avro or parquet 
(hoodie.logfile.data.block.format), stay "
           + "unshredded and shred at compaction. Applies to top-level variant 
columns only; a variant "
-          + "nested inside a struct, array or map stays unshredded. This is a 
write config rather than "
-          + "a table config: SQL DML and procedures called by table name pick 
it up from the table's "
-          + "catalog properties, while path-based procedures, the DataSource 
writer and the streamer "
-          + "must be handed it explicitly. Up to 4096 records or 64MB are 
buffered per "
-          + "open file writer before the writer is created, on top of 
parquet's own row-group "
+          + "nested inside a struct, array or map stays unshredded. Shredded 
files can only be read "
+          + "back by Spark 4.1+: Spark 4.0, Hive and Flink readers fail fast 
on them, so disable this "
+          + "option (or hoodie.parquet.variant.write.shredding.enabled) on 
tables those engines read, "
+          + "and rewrite already shredded files through clustering with it 
disabled to return to the "

Review Comment:
   "with it disabled" binds to the inference option, but 
`HoodieAvroWriteSupport.generateEffectiveSchema` strips `typed_value` only when 
`hoodie.parquet.variant.write.shredding.enabled` is false, which is also what 
the error message added in this PR tells users. Name the write-shredding config 
in the recipe here.



##########
hudi-common/src/main/java/org/apache/hudi/common/config/HoodieStorageConfig.java:
##########
@@ -308,22 +310,26 @@ public class HoodieStorageConfig extends HoodieConfig {
 
   public static final ConfigProperty<Boolean> 
PARQUET_VARIANT_SHREDDING_SCHEMA_INFERENCE_ENABLED = ConfigProperty
       .key("hoodie.parquet.variant.shredding.schema.inference.enabled")
-      .defaultValue(false)
+      .defaultValue(true)
       .sinceVersion("1.3.0")
-      .withDocumentation("When enabled, the shredding schema for variant 
columns without an explicit "
-          + "typed_value in the write schema is inferred automatically per 
parquet file from a sample of "
-          + "the records written to that file, mirroring Spark 4.1's "
-          + "spark.sql.variant.inferShreddingSchema. Requires Spark 4.1+ on 
the writer classpath; "
-          + "writes stay unshredded otherwise (Spark 4.0, Flink, Java 
engines). Applies to every "
-          + "parquet file the writer produces: base files and, on table 
version 10+, the native "
+      .withDocumentation("Infers the shredding schema of variant columns that 
have no explicit "
+          + "typed_value in the write schema, per parquet file, from a sample 
of the records written "
+          + "to that file, mirroring Spark 4.1's 
spark.sql.variant.inferShreddingSchema (also on by "
+          + "default there). Takes effect only when a Spark 4.1+ writer is on 
the classpath; other "
+          + "writers (Spark 3.x, Spark 4.0, Flink, Java) ignore it and write 
unshredded. Applies to "
+          + "every parquet file the writer produces: base files and, on table 
version 10+, the native "
           + "parquet log files of MOR tables (each infers its own schema). 
Data blocks inside "
           + "Avro-format log files, whether Avro or parquet 
(hoodie.logfile.data.block.format), stay "
           + "unshredded and shred at compaction. Applies to top-level variant 
columns only; a variant "
-          + "nested inside a struct, array or map stays unshredded. This is a 
write config rather than "
-          + "a table config: SQL DML and procedures called by table name pick 
it up from the table's "
-          + "catalog properties, while path-based procedures, the DataSource 
writer and the streamer "
-          + "must be handed it explicitly. Up to 4096 records or 64MB are 
buffered per "
-          + "open file writer before the writer is created, on top of 
parquet's own row-group "
+          + "nested inside a struct, array or map stays unshredded. Shredded 
files can only be read "
+          + "back by Spark 4.1+: Spark 4.0, Hive and Flink readers fail fast 
on them, so disable this "

Review Comment:
   The reader list here says Spark 4.0, Hive and Flink fail fast but leaves out 
Spark 3.x, which this PR itself makes fail fast through 
`ParquetSchemaEvolutionUtils.validateNoShreddedVariantStructs`. Add Spark 3.x 
to that sentence.



##########
hudi-spark-datasource/hudi-spark-common/src/test/scala/org/apache/spark/sql/execution/datasources/parquet/TestParquetSchemaEvolutionUtils.scala:
##########
@@ -199,6 +201,71 @@ class TestParquetSchemaEvolutionUtils {
   private def footerOf(column: Type): FileMetaData =
     new FileMetaData(Types.buildMessage().addField(column).named("test"), new 
HashMap[String, String](), "test")
 
+  /**
+   * The Spark 3.x shape: no VariantType there, so a variant column is 
declared as
+   * struct&lt;value: binary, metadata: binary&gt; (the shape Hive sync also 
writes). Either member
+   * order is the same column, and the unshredded twin of the same file must 
still read.
+   */
+  @Test
+  def testValidateNoShreddedVariantStructsRejectsTopLevelShreddedVariant(): 
Unit = {

Review Comment:
   These pin the schema walk, but nothing pins that the four new call sites 
reach it: every Spark 3.x leg of `TestVariantDataType` runs on an unshredded 
fixture. `variant_shredded_mixed_cow.zip` is already checked in and used by 
`ITTestVariantCrossEngineCompatibility`, so a Spark 3 leg pointing the compat 
struct DDL at it would close that gap.



##########
hudi-spark-datasource/hudi-spark3.5.x/src/main/scala/org/apache/spark/sql/execution/datasources/parquet/Spark35ParquetReader.scala:
##########
@@ -117,6 +117,11 @@ class Spark35ParquetReader(enableVectorizedReader: Boolean,
     }
 
     val footerFileMetaData = fileFooter.getFileMetaData
+    // A variant column is declared as its unshredded struct shape on Spark 
3.x (no VariantType);
+    // reject a file that shreds it here, before the reader is built, so the 
read fails naming the
+    // column instead of projecting the group by name and returning a null 
value for every
+    // shredded row.
+    
ParquetSchemaEvolutionUtils.validateNoShreddedVariantStructs(requiredSchema, 
footerFileMetaData)

Review Comment:
   This covers base files only: `SparkFileFormatInternalRowReaderContext` 
routes native and inline parquet log blocks to 
`HoodieSparkParquetReader.getUnsafeRowIterator`, which builds its own 
`ParquetReader` on the plain `HoodieParquetReadSupport` that `SparkAdapter` 
hands Spark 3.x, so a shredded variant in a log block still reads back as a 
null value. Worth calling the guard from that log branch too, or having 
`BaseSpark3Adapter` override `createParquetReadSupport` the way 
`Spark4_0Adapter` does.



##########
hudi-hadoop-common/src/test/java/org/apache/hudi/io/storage/hadoop/TestHoodieAvroFileWriterFactoryVariantInference.java:
##########
@@ -54,25 +54,28 @@
 
 /**
  * Pins the no-inferrer degradation of shredding-schema inference in
- * {@link HoodieAvroFileWriterFactory}: this module's classpath carries no 
Spark version module,
- * so {@link VariantShreddingRuntime#lookupInferrer()} is empty here, which is 
what engines without
- * Spark 4.1+ (Flink, Java, Spark 4.0) see in production.
+ * {@link HoodieAvroFileWriterFactory}. Inference is on by default, so this 
gate is reached by every

Review Comment:
   `HoodieAvroFileWriterFactory.newParquetFileWriter` requires 
`isShreddingProviderAvailable` before it reaches the inferrer gate, and the 
only provider ships in hudi-spark4-common, so on Flink, Java and Spark 3.x 
classpaths a stock config short-circuits before this gate - which is why the 
test names a provider class explicitly. Reword "reached by every engine's Avro 
write path with a stock config".



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to