hudi-agent commented on code in PR #19898:
URL: https://github.com/apache/hudi/pull/19898#discussion_r3983854441


##########
hudi-spark-datasource/hudi-spark-common/src/main/scala/org/apache/hudi/HoodieIncrementalFileIndex.scala:
##########
@@ -43,6 +43,25 @@ class HoodieIncrementalFileIndex(override val spark: 
SparkSession,
     spark, metaClient, schemaSpec, options, fileStatusCache, includeLogFiles, 
shouldEmbedFileSlices = true
   ) with FileIndex {
 
+  // Skip the Spark optimizer's partition pruning rule (e.g. 
Spark33HoodiePruneFileSourcePartitions)
+  // which would trigger a full-table partition listing via the base class. 
The incremental file
+  // index already selects only modified file groups via listFileSplits().
+  hasPushedDownPartitionPredicates = true

Review Comment:
   🤖 Setting this in the constructor means 
`Spark3xHoodiePruneFileSourcePartitions` never runs for this index, so 
`sizeInBytes` is now computed from an empty `cachedAllInputFileSlices` 
(`getTotalCachedFilesSize` == 0) at planning time — with the Hudi extension 
enabled that reports a 0-byte relation, which can make the optimizer broadcast 
an arbitrarily large incremental scan. Have you checked what stats the planner 
sees for an incremental read after this change?
   
   <sub><i>⚠️ AI-generated; verify before applying. React 👍/👎 to flag 
quality.</i></sub>



##########
hudi-spark-datasource/hudi-spark-common/src/main/scala/org/apache/hudi/MergeOnReadIncrementalRelationV2.scala:
##########
@@ -124,11 +124,9 @@ case class MergeOnReadIncrementalRelationV2(override val 
sqlContext: SQLContext,
         val fsView = new HoodieTableFileSystemView(metaClient, timeline, 
affectedFilesInCommits)
         val modifiedPartitions = getWritePartitionPaths(commitsMetadata)
 
-        
fileIndex.listMatchingPartitionPaths(HoodieFileIndex.convertFilterForTimestampKeyGenerator(metaClient,
 partitionFilters))
-          .map(p => p.getPath).filter(p => modifiedPartitions.contains(p))
-          .flatMap { relativePartitionPath =>
-            fsView.getLatestMergedFileSlicesBeforeOrOn(relativePartitionPath, 
latestCommit).iterator().asScala
-          }
+        modifiedPartitions.asScala.flatMap { relativePartitionPath =>

Review Comment:
   🤖 Dropping `listMatchingPartitionPaths(...)` here also drops the 
partition-predicate filtering it was doing (the old code intersected the pruned 
partitions with `modifiedPartitions`), so `listFileSplits` now returns every 
modified partition regardless of `partitionFilters`. Since 
`HoodieIncrementalFileIndex.partitionSchema` is non-empty for a partitioned 
table, Spark's `FileSourceStrategy` removes partition-only predicates from 
`afterScanFilters` and trusts the index to prune — so an incremental read like 
`.load().where("partition_col = 'x'")` could return rows from other partitions. 
Would it work to keep the predicate evaluation but apply it only to 
`modifiedPartitions` (no full listing) rather than removing it? @yihua could 
you sanity-check this one?
   
   <sub><i>⚠️ AI-generated; verify before applying. React 👍/👎 to flag 
quality.</i></sub>



##########
hudi-spark-datasource/hudi-spark-common/src/main/scala/org/apache/hudi/HoodieIncrementalFileIndex.scala:
##########
@@ -43,6 +43,25 @@ class HoodieIncrementalFileIndex(override val spark: 
SparkSession,
     spark, metaClient, schemaSpec, options, fileStatusCache, includeLogFiles, 
shouldEmbedFileSlices = true
   ) with FileIndex {
 
+  // Skip the Spark optimizer's partition pruning rule (e.g. 
Spark33HoodiePruneFileSourcePartitions)
+  // which would trigger a full-table partition listing via the base class. 
The incremental file
+  // index already selects only modified file groups via listFileSplits().
+  hasPushedDownPartitionPredicates = true
+
+  override def filterFileSlices(dataFilters: Seq[Expression], 
partitionFilters: Seq[Expression], isPartitionPruned: Boolean = false)

Review Comment:
   🤖 This override returns `Option.empty` for the partition path, but the 
base-class contract treats it as present (`HoodieFileIndex.listFiles` does 
`partitionOpt.get.getValues`), so any caller other than the prune rules would 
hit a `NoSuchElementException`. It also silently ignores the third parameter 
(renamed here from `isPartitionPruneOnly` to `isPartitionPruned`), meaning the 
"safety net" does a full `listFileSplits` during optimization. Would it be 
cleaner to preserve the `PartitionPath` from the grouping, or keep the base 
name/semantics of the flag?
   
   <sub><i>⚠️ AI-generated; verify before applying. React 👍/👎 to flag 
quality.</i></sub>



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