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


##########
hudi-spark-datasource/hudi-spark-common/src/main/scala/org/apache/hudi/HoodieBaseRelation.scala:
##########
@@ -81,7 +80,6 @@ case class HoodieTableState(tablePath: String,
                             recordKeyField: String,
                             orderingFields: List[String],
                             usesVirtualKeys: Boolean,

Review Comment:
   With recordPayloadClassName gone, latestCommitTimestamp is the only field of 
HoodieTableState that anything still reads. Worth dropping the other seven by 
the same criterion, or noting that they are deliberately kept - follow-up, not 
a blocker.



##########
hudi-spark-datasource/hudi-spark/src/test/scala/org/apache/spark/sql/hudi/common/TestNestedSchemaPruningOptimization.scala:
##########
@@ -58,26 +64,34 @@ class TestNestedSchemaPruningOptimization extends 
HoodieSparkSqlTestBase {
     }
   }
 
-  test("Test nested schema pruning with DefaultHoodieRecordPayload") {
+  test("Test nested schema pruning with a projection-incompatible custom 
payload") {
     withTempDir { tmp =>
       val tableName = generateTableName
       val tablePath = s"${tmp.getCanonicalPath}/$tableName"
 
-      // NOTE: On the file-group-reader based read path the payload class does 
not affect nested
-      //       schema pruning, so the read schema is pruned the same way as 
with the default payload
+      // NOTE: A payload class outside the well-known set puts the table in 
CUSTOM merge mode, whose
+      //       merger is not projection compatible, so the file group reader 
merges on the full
+      //       table schema internally 
(FileGroupReaderSchemaHandler#generateRequiredSchema) and
+      //       projects the merged rows back down to the pruned read schema 
afterwards
       createTableWithNestedStructSchema("mor", tableName, tablePath,
-        Map(HoodieWriteConfig.WRITE_PAYLOAD_CLASS_NAME.key -> 
"org.apache.hudi.common.model.DefaultHoodieRecordPayload"))
+        Map(HoodieWriteConfig.WRITE_PAYLOAD_CLASS_NAME.key -> 
classOf[CustomPayloadForTesting].getName),
+        populateMetaFields = true)
+
+      // The update writes a log file, so the pruned reads below actually 
merge through that gate
+      spark.sql(s"UPDATE $tableName SET ts = 123457 WHERE id = 1")
 
       val selectDF = spark.sql(s"SELECT id, item.name FROM $tableName")
 
+      // Spark still prunes the scan schema; the full-schema requirement is 
internal to the reader
       val expectedSchema = StructType(Seq(
         StructField("id", IntegerType, nullable = true),
         StructField("item", StructType(Seq(StructField("name", StringType, 
nullable = false))), nullable = true)
       ))
-
       assertPrunedReadSchema(selectDF, tableName, expectedSchema)
 
       checkAnswer(s"SELECT id, item.name FROM $tableName")(Seq(1, "a1"))
+      // The merged row keeps nested leaves that the pruned read schema dropped
+      checkAnswer(s"SELECT id, item.price, ts FROM $tableName")(Seq(1, 10, 
123457))

Review Comment:
   Both assertions here read FileSourceScanExec.requiredSchema and 
post-projection row values, which is what the DefaultHoodieRecordPayload 
version asserted too. Does this test fail if the CUSTOM projection-incompatible 
branch in FileGroupReaderSchemaHandler is removed, or is SchemaHandlerTestBase 
the only place pinning it?



##########
hudi-spark-datasource/hudi-spark-common/src/main/scala/org/apache/hudi/HoodieHadoopFsRelationFactory.scala:
##########
@@ -335,7 +335,7 @@ class 
HoodieMergeOnReadIncrementalHadoopFsRelationFactoryV2(override val sqlCont
                                                             isBootstrap: 
Boolean,
                                                             rangeType: 
RangeType = RangeType.OPEN_CLOSED)
   extends HoodieMergeOnReadIncrementalHadoopFsRelationFactory(sqlContext, 
metaClient, options, schemaSpec, isBootstrap,
-    MergeOnReadIncrementalRelationV2(sqlContext, options, metaClient, 
schemaSpec, None, rangeType))
+    MergeOnReadIncrementalRelationV2(sqlContext, options, metaClient, 
schemaSpec, rangeType))

Review Comment:
   The description says only metadata-table reads and the schema-on-read branch 
still produce a HoodieBaseRelation, but the incremental factories here build 
MergeOnReadIncrementalRelationV1/V2 on the non-metadata path for both MOR and 
COW. They never reach a LogicalRelation because HoodieIncrementalFileIndex only 
calls listFileSplits and getRequiredFilters on them, so the conclusion stands - 
could you correct the enumeration in the description?



##########
hudi-common/src/test/java/org/apache/hudi/common/table/read/SchemaHandlerTestBase.java:
##########
@@ -130,6 +130,27 @@ public void testMor(RecordMergeMode mergeMode,
     }
     assertEquals(expectedRequiredSchema, schemaHandler.getRequiredSchema());
     assertFalse(readerContext.getNeedsBootstrapMerge());
+
+    //read subset of columns with a nested-narrowed field, the shape Spark's 
nested schema pruning
+    //requests: "fare" keeps only its "amount" leaf
+    requestedSchema = 
narrowFareToAmountOnly(generateProjectionSchema("begin_lat", "fare", "rider"));
+    schemaHandler = createSchemaHandler(readerContext, dataSchema, 
requestedSchema, supportsParquetRowIndex);
+    if (mergeMode == EVENT_TIME_ORDERING && hasPrecombine) {
+      expectedRequiredSchema = 
narrowFareToAmountOnly(generateProjectionSchema(hasBuiltInDelete, "begin_lat", 
"fare", "rider", "_hoodie_record_key", "timestamp"));
+    } else if (mergeMode == EVENT_TIME_ORDERING || mergeMode == 
COMMIT_TIME_ORDERING) {
+      expectedRequiredSchema = 
narrowFareToAmountOnly(generateProjectionSchema(hasBuiltInDelete, "begin_lat", 
"fare", "rider", "_hoodie_record_key"));
+    } else if (mergeMode == CUSTOM && isProjectionCompatible) {
+      expectedRequiredSchema = 
narrowFareToAmountOnly(generateProjectionSchema("begin_lat", "fare", "rider", 
"begin_lon", "_hoodie_record_key", "timestamp"));
+    } else {
+      //a projection-incompatible custom merger may need any column to merge, 
so the handler must
+      //re-expand the nested-narrowed request back to the full data schema 
(see HUDI-5443)
+      expectedRequiredSchema = dataSchema;

Review Comment:
   The CUSTOM projection-incompatible branch returns the table schema before it 
looks at the requested schema, so narrowing fare changes nothing here and this 
repeats the assertion already made for the flat projection above. Consider 
dropping this branch and keeping the block for the three cases where the nested 
narrowing actually has to survive.



##########
hudi-spark-datasource/hudi-spark/src/test/scala/org/apache/spark/sql/hudi/common/TestNestedSchemaPruningOptimization.scala:
##########
@@ -58,26 +64,34 @@ class TestNestedSchemaPruningOptimization extends 
HoodieSparkSqlTestBase {
     }
   }
 
-  test("Test nested schema pruning with DefaultHoodieRecordPayload") {
+  test("Test nested schema pruning with a projection-incompatible custom 
payload") {

Review Comment:
   The PR description says this suite is kept unchanged, but this commit 
renames the test, swaps in a custom payload, enables meta fields and adds an 
UPDATE plus a new answer assertion. Could you refresh the description so 
Summary and Risk Level also cover the test changes and the 
HoodieTableState.recordPayloadClassName removal?



-- 
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