-
Notifications
You must be signed in to change notification settings - Fork 2.5k
[HUDI-3085] improve bulk insert partitioner abstraction #4441
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -77,8 +77,12 @@ public HoodieWriteMetadata<List<WriteStatus>> bulkInsert(final List<HoodieRecord | |
| config.shouldAllowMultiWriteOnSameInstant()); | ||
| } | ||
|
|
||
| BulkInsertPartitioner partitioner = userDefinedBulkInsertPartitioner.isPresent() | ||
| ? userDefinedBulkInsertPartitioner.get() | ||
| : JavaBulkInsertInternalPartitionerFactory.get(config.getBulkInsertSortMode()); | ||
|
|
||
| // write new files | ||
| List<WriteStatus> writeStatuses = bulkInsert(inputRecords, instantTime, table, config, performDedupe, userDefinedBulkInsertPartitioner, false, config.getBulkInsertShuffleParallelism(), new CreateHandleFactory(false)); | ||
| List<WriteStatus> writeStatuses = bulkInsert(inputRecords, instantTime, table, config, performDedupe, partitioner, false, config.getBulkInsertShuffleParallelism(), new CreateHandleFactory(false)); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this line can be split into two lines.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Got it, fixed. |
||
| //update index | ||
| ((BaseJavaCommitActionExecutor) executor).updateIndexAndCommitIfNeeded(writeStatuses, result); | ||
| return result; | ||
|
|
@@ -90,7 +94,7 @@ public List<WriteStatus> bulkInsert(List<HoodieRecord<T>> inputRecords, | |
| HoodieTable<T, List<HoodieRecord<T>>, List<HoodieKey>, List<WriteStatus>> table, | ||
| HoodieWriteConfig config, | ||
| boolean performDedupe, | ||
| Option<BulkInsertPartitioner> userDefinedBulkInsertPartitioner, | ||
| BulkInsertPartitioner partitioner, | ||
| boolean useWriterSchema, | ||
| int parallelism, | ||
| WriteHandleFactory writeHandleFactory) { | ||
|
|
@@ -103,12 +107,7 @@ public List<WriteStatus> bulkInsert(List<HoodieRecord<T>> inputRecords, | |
| parallelism, table); | ||
| } | ||
|
|
||
| final List<HoodieRecord<T>> repartitionedRecords; | ||
| BulkInsertPartitioner partitioner = userDefinedBulkInsertPartitioner.isPresent() | ||
| ? userDefinedBulkInsertPartitioner.get() | ||
| : JavaBulkInsertInternalPartitionerFactory.get(config.getBulkInsertSortMode()); | ||
| // only List is supported for Java partitioner, but it is not enforced by BulkInsertPartitioner API. To improve this, TODO HUDI-3463 | ||
| repartitionedRecords = (List<HoodieRecord<T>>) partitioner.repartitionRecords(dedupedRecords, parallelism); | ||
| final List<HoodieRecord<T>> repartitionedRecords = (List<HoodieRecord<T>>) partitioner.repartitionRecords(dedupedRecords, parallelism); | ||
|
|
||
| FileIdPrefixProvider fileIdPrefixProvider = (FileIdPrefixProvider) ReflectionUtils.loadClass( | ||
| config.getFileIdPrefixProviderClassName(), | ||
|
|
@@ -119,7 +118,7 @@ public List<WriteStatus> bulkInsert(List<HoodieRecord<T>> inputRecords, | |
| new JavaLazyInsertIterable<>(repartitionedRecords.iterator(), true, | ||
| config, instantTime, table, | ||
| fileIdPrefixProvider.createFilePrefix(""), table.getTaskContextSupplier(), | ||
| new CreateHandleFactory<>()).forEachRemaining(writeStatuses::addAll); | ||
| (WriteHandleFactory) partitioner.getWriteHandleFactory(0).orElse(writeHandleFactory)).forEachRemaining(writeStatuses::addAll); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. here what's the meaning of passing 0 as partitioneId?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 0 means getting write handle factory for partition 0. The code is consistent with previous behavior, as java engine always has only one data partition.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we can add some comments here.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure. |
||
|
|
||
| return writeStatuses; | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -49,9 +49,9 @@ | |
| public class RDDSpatialCurveSortPartitioner<T extends HoodieRecordPayload> | ||
| implements BulkInsertPartitioner<JavaRDD<HoodieRecord<T>>> { | ||
|
|
||
| private final HoodieSparkEngineContext sparkEngineContext; | ||
| private final transient HoodieSparkEngineContext sparkEngineContext; | ||
| private final String[] orderByColumns; | ||
| private final Schema schema; | ||
| private final SerializableSchema schema; | ||
| private final HoodieClusteringConfig.LayoutOptimizationStrategy layoutOptStrategy; | ||
| private final HoodieClusteringConfig.SpatialCurveCompositionStrategyType curveCompositionStrategyType; | ||
|
|
||
|
|
@@ -64,14 +64,13 @@ public RDDSpatialCurveSortPartitioner(HoodieSparkEngineContext sparkEngineContex | |
| this.orderByColumns = orderByColumns; | ||
| this.layoutOptStrategy = layoutOptStrategy; | ||
| this.curveCompositionStrategyType = curveCompositionStrategyType; | ||
| this.schema = schema; | ||
| this.schema = new SerializableSchema(schema); | ||
| } | ||
|
|
||
| @Override | ||
| public JavaRDD<HoodieRecord<T>> repartitionRecords(JavaRDD<HoodieRecord<T>> records, int outputSparkPartitions) { | ||
| SerializableSchema serializableSchema = new SerializableSchema(schema); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nice improvement. |
||
| JavaRDD<GenericRecord> genericRecordsRDD = | ||
| records.map(f -> (GenericRecord) f.getData().getInsertValue(serializableSchema.get()).get()); | ||
| records.map(f -> (GenericRecord) f.getData().getInsertValue(schema.get()).get()); | ||
|
|
||
| Dataset<Row> sourceDataset = | ||
| AvroConversionUtils.createDataFrame( | ||
|
|
@@ -82,7 +81,7 @@ public JavaRDD<HoodieRecord<T>> repartitionRecords(JavaRDD<HoodieRecord<T>> reco | |
|
|
||
| Dataset<Row> sortedDataset = reorder(sourceDataset, outputSparkPartitions); | ||
|
|
||
| return HoodieSparkUtils.createRdd(sortedDataset, schema.getName(), schema.getNamespace(), false, Option.empty()) | ||
| return HoodieSparkUtils.createRdd(sortedDataset, schema.get().getName(), schema.get().getNamespace(), false, Option.empty()) | ||
| .toJavaRDD() | ||
| .map(record -> { | ||
| String key = record.get(HoodieRecord.RECORD_KEY_METADATA_FIELD).toString(); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,7 +20,6 @@ | |
|
|
||
| import org.apache.hudi.client.WriteStatus; | ||
| import org.apache.hudi.common.data.HoodieData; | ||
| import org.apache.hudi.common.fs.FSUtils; | ||
| import org.apache.hudi.common.model.HoodieKey; | ||
| import org.apache.hudi.common.model.HoodieRecord; | ||
| import org.apache.hudi.common.model.HoodieRecordPayload; | ||
|
|
@@ -39,8 +38,6 @@ | |
| import org.apache.spark.api.java.JavaRDD; | ||
|
|
||
| import java.util.List; | ||
| import java.util.stream.Collectors; | ||
| import java.util.stream.IntStream; | ||
|
|
||
| /** | ||
| * A spark implementation of {@link BaseBulkInsertHelper}. | ||
|
|
@@ -76,9 +73,14 @@ public HoodieWriteMetadata<HoodieData<WriteStatus>> bulkInsert(final HoodieData< | |
| table.getActiveTimeline().transitionRequestedToInflight(new HoodieInstant(HoodieInstant.State.REQUESTED, | ||
| executor.getCommitActionType(), instantTime), Option.empty(), | ||
| config.shouldAllowMultiWriteOnSameInstant()); | ||
|
|
||
| BulkInsertPartitioner partitioner = userDefinedBulkInsertPartitioner.isPresent() | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see the duplicate code in JavaBulkInsertHelper, can we unify it?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The BulkInsertPartitionerFactory is different for spark&java. I could extract an interface(e.g., GetBulkInsertPartitionerFactory) to the base class if we want to unify the code. But as yihua said, the change of public interface may broken existing users' code, requiring them to update their code too. ps. I have re-written this part of the code to make it more clear. |
||
| ? userDefinedBulkInsertPartitioner.get() | ||
| : BulkInsertInternalPartitionerFactory.get(config.getBulkInsertSortMode()); | ||
|
|
||
| // write new files | ||
| HoodieData<WriteStatus> writeStatuses = | ||
| bulkInsert(inputRecords, instantTime, table, config, performDedupe, userDefinedBulkInsertPartitioner, false, config.getBulkInsertShuffleParallelism(), new CreateHandleFactory(false)); | ||
| bulkInsert(inputRecords, instantTime, table, config, performDedupe, partitioner, false, config.getBulkInsertShuffleParallelism(), new CreateHandleFactory(false)); | ||
| //update index | ||
| ((BaseSparkCommitActionExecutor) executor).updateIndexAndCommitIfNeeded(writeStatuses, result); | ||
| return result; | ||
|
|
@@ -90,7 +92,7 @@ public HoodieData<WriteStatus> bulkInsert(HoodieData<HoodieRecord<T>> inputRecor | |
| HoodieTable<T, HoodieData<HoodieRecord<T>>, HoodieData<HoodieKey>, HoodieData<WriteStatus>> table, | ||
| HoodieWriteConfig config, | ||
| boolean performDedupe, | ||
| Option<BulkInsertPartitioner> userDefinedBulkInsertPartitioner, | ||
| BulkInsertPartitioner partitioner, | ||
| boolean useWriterSchema, | ||
| int parallelism, | ||
| WriteHandleFactory writeHandleFactory) { | ||
|
|
@@ -103,20 +105,12 @@ public HoodieData<WriteStatus> bulkInsert(HoodieData<HoodieRecord<T>> inputRecor | |
| parallelism, table); | ||
| } | ||
|
|
||
| final HoodieData<HoodieRecord<T>> repartitionedRecords; | ||
| BulkInsertPartitioner partitioner = userDefinedBulkInsertPartitioner.isPresent() | ||
| ? userDefinedBulkInsertPartitioner.get() | ||
| : BulkInsertInternalPartitionerFactory.get(config.getBulkInsertSortMode()); | ||
| // only JavaRDD is supported for Spark partitioner, but it is not enforced by BulkInsertPartitioner API. To improve this, TODO HUDI-3463 | ||
| repartitionedRecords = HoodieJavaRDD.of((JavaRDD<HoodieRecord<T>>) partitioner.repartitionRecords(HoodieJavaRDD.getJavaRDD(dedupedRecords), parallelism)); | ||
|
|
||
| // generate new file ID prefixes for each output partition | ||
| final List<String> fileIDPrefixes = | ||
| IntStream.range(0, parallelism).mapToObj(i -> FSUtils.createNewFileIdPfx()).collect(Collectors.toList()); | ||
| final HoodieData<HoodieRecord<T>> repartitionedRecords = HoodieJavaRDD.of((JavaRDD<HoodieRecord<T>>) partitioner.repartitionRecords(HoodieJavaRDD.getJavaRDD(dedupedRecords), parallelism)); | ||
|
|
||
| JavaRDD<WriteStatus> writeStatusRDD = HoodieJavaRDD.getJavaRDD(repartitionedRecords) | ||
| .mapPartitionsWithIndex(new BulkInsertMapFunction<>(instantTime, | ||
| partitioner.arePartitionRecordsSorted(), config, table, fileIDPrefixes, useWriterSchema, writeHandleFactory), true) | ||
| partitioner.arePartitionRecordsSorted(), config, table, useWriterSchema, partitioner, writeHandleFactory), true) | ||
| .flatMap(List::iterator); | ||
|
|
||
| return HoodieJavaRDD.of(writeStatusRDD); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The description is not correct since it returns empty?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Fixed.