repartitionAndSortWithinPartitions并删除单个洗牌的重复项

时间:2019-12-18 09:47:17

标签: scala apache-spark

我有一个用例,其中我需要使用自定义分区程序并最终对分区进行排序。

    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实现。

那么,在这种情况下最好的方法是什么?

1 个答案:

答案 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)

这不会添加随机播放,并且会保留分区(但可能不会排序)