lokeshj1703 commented on code in PR #19550:
URL: https://github.com/apache/hudi/pull/19550#discussion_r4036097499


##########
hudi-utilities/src/main/java/org/apache/hudi/utilities/streamer/SparkSampleWritesUtils.java:
##########
@@ -109,12 +125,16 @@ private static Pair<Boolean, String> 
doSampleWrites(JavaSparkContext jsc, Option
     Pair<Boolean, String> emptyRes = Pair.of(false, null);
     try (SparkRDDWriteClient sampleWriteClient = new SparkRDDWriteClient(new 
HoodieSparkEngineContext(jsc), sampleWriteConfig, Option.empty())) {
       int size = writeConfig.getIntOrDefault(SAMPLE_WRITES_SIZE);
+      long maxSampleBytes = resolveMaxSampleBytes(jsc);
       return recordsOpt.map(records -> {
-        // Empty partition path so all sampled records write to a single 
non-partitioned file,
-        // instead of fanning out into one tiny file per source partition and 
skewing the estimate.
-        List<HoodieRecord> samples = records.coalesce(1).take(size).stream()
-            .map(r -> r.newInstance(new HoodieKey(r.getRecordKey(), "")))
-            .collect(Collectors.toList());
+        // Collapse to a single partition, then take a sample bounded by both 
record count and total
+        // serialized bytes on the executor. The sample is later shipped 
inside one Spark task, so
+        // bounding its serialized size keeps that task under 
spark.rpc.message.maxSize even when the
+        // source records are large.
+        List<HoodieRecord> samples = records.coalesce(1)

Review Comment:
   Done. Reworked to hand the persisted single-partition RDD straight to 
`bulkInsert`, so the sample never crosses the driver. `persist()` because it is 
read more than once (isEmpty, bulkInsert, commit).



##########
hudi-utilities/src/main/java/org/apache/hudi/utilities/streamer/SparkSampleWritesUtils.java:
##########
@@ -109,12 +125,16 @@ private static Pair<Boolean, String> 
doSampleWrites(JavaSparkContext jsc, Option
     Pair<Boolean, String> emptyRes = Pair.of(false, null);
     try (SparkRDDWriteClient sampleWriteClient = new SparkRDDWriteClient(new 
HoodieSparkEngineContext(jsc), sampleWriteConfig, Option.empty())) {
       int size = writeConfig.getIntOrDefault(SAMPLE_WRITES_SIZE);
+      long maxSampleBytes = resolveMaxSampleBytes(jsc);
       return recordsOpt.map(records -> {
-        // Empty partition path so all sampled records write to a single 
non-partitioned file,
-        // instead of fanning out into one tiny file per source partition and 
skewing the estimate.
-        List<HoodieRecord> samples = records.coalesce(1).take(size).stream()
-            .map(r -> r.newInstance(new HoodieKey(r.getRecordKey(), "")))
-            .collect(Collectors.toList());
+        // Collapse to a single partition, then take a sample bounded by both 
record count and total
+        // serialized bytes on the executor. The sample is later shipped 
inside one Spark task, so
+        // bounding its serialized size keeps that task under 
spark.rpc.message.maxSize even when the
+        // source records are large.
+        List<HoodieRecord> samples = records.coalesce(1)
+            .mapPartitions((FlatMapFunction<Iterator<HoodieRecord>, 
HoodieRecord>) sourceRecords ->
+                takeBoundedSample(sourceRecords, size, maxSampleBytes))

Review Comment:
   Fixed. The rewritten description no longer states those defaults, and the 
change no longer hinges on the per-record threshold.



##########
hudi-utilities/src/main/java/org/apache/hudi/utilities/streamer/SparkSampleWritesUtils.java:
##########
@@ -109,12 +125,16 @@ private static Pair<Boolean, String> 
doSampleWrites(JavaSparkContext jsc, Option
     Pair<Boolean, String> emptyRes = Pair.of(false, null);
     try (SparkRDDWriteClient sampleWriteClient = new SparkRDDWriteClient(new 
HoodieSparkEngineContext(jsc), sampleWriteConfig, Option.empty())) {
       int size = writeConfig.getIntOrDefault(SAMPLE_WRITES_SIZE);
+      long maxSampleBytes = resolveMaxSampleBytes(jsc);
       return recordsOpt.map(records -> {
-        // Empty partition path so all sampled records write to a single 
non-partitioned file,
-        // instead of fanning out into one tiny file per source partition and 
skewing the estimate.
-        List<HoodieRecord> samples = records.coalesce(1).take(size).stream()
-            .map(r -> r.newInstance(new HoodieKey(r.getRecordKey(), "")))
-            .collect(Collectors.toList());
+        // Collapse to a single partition, then take a sample bounded by both 
record count and total
+        // serialized bytes on the executor. The sample is later shipped 
inside one Spark task, so
+        // bounding its serialized size keeps that task under 
spark.rpc.message.maxSize even when the
+        // source records are large.
+        List<HoodieRecord> samples = records.coalesce(1)
+            .mapPartitions((FlatMapFunction<Iterator<HoodieRecord>, 
HoodieRecord>) sourceRecords ->
+                takeBoundedSample(sourceRecords, size, maxSampleBytes))
+            .collect();

Review Comment:
   Addressed. The rework removes the driver round trip that caused the failure, 
so estimation no longer aborts on large records. Widening the catch so any 
estimation error can never fail ingestion is a separate hardening; can follow 
up if you prefer.



##########
hudi-utilities/src/main/java/org/apache/hudi/utilities/streamer/SparkSampleWritesUtils.java:
##########
@@ -139,6 +159,46 @@ private static Pair<Boolean, String> 
doSampleWrites(JavaSparkContext jsc, Option
     }
   }
 
+  /**
+   * Resolves the maximum total serialized size (in bytes) allowed for the 
sampled records, derived
+   * as {@link #SAMPLE_WRITES_TASK_BYTES_FRACTION} of the cluster's {@code 
spark.rpc.message.maxSize}
+   * (read from {@link 
org.apache.spark.internal.config.Network#RPC_MESSAGE_MAX_SIZE}, which also
+   * supplies Spark's default). Deriving it from the RPC limit keeps the bound 
correct if operators
+   * raise that limit.
+   */
+  private static long resolveMaxSampleBytes(JavaSparkContext jsc) {
+    int rpcMaxSizeMb = (Integer) 
jsc.getConf().get(Network$.MODULE$.RPC_MESSAGE_MAX_SIZE());

Review Comment:
   Moot now. The rework drops the RPC-config read entirely: 
`resolveMaxSampleBytes` and the `Network` lookup are gone.



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