ReduceByKey函数在Spark中

时间:2015-11-23 16:16:16

标签: scala apache-spark rdd partitioning reduce

我已经读过某个地方,对于作用于单个RDD的操作,例如reduceByKey(),在预分区的RDD上运行将导致每个键的所有值在本地计算机器,只需要从每个工作节点发送最终的本地减少的值回到主机。这意味着我必须声明一个像:

这样的分区器
val sc = new SparkContext(...)
val userData = sc.sequenceFile[UserID, UserInfo]("hdfs://...")
             .partitionBy(new HashPartitioner(100))   // Create 100 partitions
             .persist() 

以便reduceByKey按照我之前的解释工作。

我的问题是,如果我想使用reduceByKey(最佳),我是否需要在每次分区时声明或者不需要声明。

1 个答案:

答案 0 :(得分:2)

实际上,你所谈论的两个品质有点不相关。

对于reduceByKey(),第一个质量会聚合同一个键的元素,并在每个执行器上使用提供的关联reduce函数本地优先,然后最终在执行程序之间进行聚合。它封装在一个名为mapSideCombine的布尔参数中,如果设置为true则执行上述操作。如果设置为false,与groupByKey()一样,则每个记录将被洗牌并发送给正确的执行者。

第二个质量涉及分区及其使用方式。根据其定义,每个RDD包含分裂列表和(可选地)分区器。方法reduceByKey()被重载,实际上有一些定义。例如:

  • def reduceByKey(func: (V, V) => V): RDD[(K, V)]

    此方法的定义实际上使用来自父RDD的默认现有分区程序,并减少为设置为默认并行级别的分区数。

  • def reduceByKey(func: (V, V) => V, numPartitions: Int): RDD[(K, V)]

    该方法的定义将使用HashPartitioner将适当的数据提供给相应的执行者,分区数量为numPartitions

  • def reduceByKey(partitioner: Partitioner, func: (V, V) => V): RDD[(K, V)]

    最后,该方法的这个定义取代了另外两个,并且接受了一个通用(可能是自定义)分区器,它将产生由分区器如何分区键确定的分区数。

关键是你可以在reduceByKey()本身内实际编码所需的分区逻辑。如果你的意图是通过预分区避免改变开销,那么它也没有意义,因为你仍然会在你的预分区上进行洗牌。