我有一个用例,其中我需要使用自定义分区程序并最终对分区进行排序。
implicit val ordering: Ordering[Array[Byte]] = new LexicographicalOrdering
val partitionedDf = spark.createDataFrame(
dataset
.select(RecordProvider.getKeyUDF(sparkArguments.getDatasetArguments)(col(hashKeyName), col(rangeKeyName)).as("key"),
RecordProvider.getValueUDF(avroSchema)(to_json(struct(dataset.columns.map(col): _*))).as("value")).
rdd
.map(record => (record.getAs[Array[Byte]](0),record.getAs[Array[Byte]](1)))
.repartitionAndSortWithinPartitions(new XXHashRangeBasedPartitioner(sparkArguments.getPartitionConfigurationArguments.getNumberOfPartitions))
.map(pair => Row(pair._1, pair._2))
, DefaultSource.SUPPORTED_SCHEMA)
您可能已经注意到,getKeyUDF和getValueUDF返回Array [Byte]。我定义了一个自定义分区程序 XXHashRangeBasedPartitioner ,并具有一个[Array [Byte]]供内部使用以进行排序。
我需要在某个时间点从数据集中删除重复项。考虑到 repartitionAndSortWithinPartitions 已经引起了洗牌并对我的分区进行了排序。有没有办法我可以将dropDuplicates与它合并,或者有一个dropDuplicates可以在排序的分区(仅在分区级别)上有效地工作,而无需调用另一次shuffle。因此,基本上可以实现重复删除,自定义分区和排序,而只需进行一次随机播放即可。
rdd上的reduceByKey 或数据集上的 dropDuplicates 都导致加法洗牌。 rdd上的 reduceByKey 还有另一个问题,它不适用于Array [Byte],我必须将其包装并提供hashCode和equals实现。
那么,在这种情况下最好的方法是什么?
答案 0 :(得分:0)
您可以添加mapPartitions
-在repartitionAndSortWithinPartitions
之后的步骤
def dedup(rows : Seq[(Array[Byte],Array[Byte])]) : Seq[(Array[Byte],Array[Byte])]= {
// your deduplication logic
}
rdd
.repartitionAndSortWithinPartitions(new XXHashRangeBasedPartitioner(sparkArguments.getPartitionConfigurationArguments.getNumberOfPartitions))
.mapPartitions(rows => dedup(rows.toList).toIterator, preservesPartitioning = true)
这不会添加随机播放,并且会保留分区(但可能不会排序)