用Spark中的reduceByKey替换groupByKey

时间:2017-04-20 11:36:37

标签: scala apache-spark mapreduce rdd distributed-computing

您好我经常需要在我的代码中使用groupByKey,但我知道这是一个非常繁重的操作。由于我正在努力提高性能,我想知道我删除所有groupByKey调用的方法是否有效。

我习惯于从另一个RDD创建一个RDD并创建一对类型(Int,Int)

rdd1 = [(1, 2), (1, 3), (2 , 3), (2, 4), (3, 5)]

因为我需要获得这样的东西:

[(1, [2, 3]), (2 , [3, 4]), (3, [5])]

我使用的是out = rdd1.groupByKey,但由于这种方法对于庞大的数据集可能非常有问题,我认为使用此解决方案:

我没有创建类型为(Int,Int)的RDD rdd1,而是创建了类型对(Int,List [Int]),所以我的rdd1就像此

rdd1 = [(1, [2]), (1, [3]), (2 , [3]), (2, [4]), (3, [5])]

但是这次达到相同的结果我使用reduceByKey(_ ::: _)按键加入所有值,这应该更快。您认为使用这种方法可能会提高性能吗?我害怕这种类型(Int,List [Int])是不是愚蠢创建一对哪个值是一个只包含1个元素的列表?

你认为使用其他方法有更快的方法来达到相同的结果吗?谢谢。

3 个答案:

答案 0 :(得分:3)

  

由于我正在努力提高性能,我想知道我删除所有groupByKey调用的方法是否有效。

查看RDD.toDebugString以查看RDD转换的逻辑计划。这应该可以很好地概述你的行动有多快(或不行动)。

避免ShuffledRDD,因为它们会导致通常非常昂贵的随机操作。

至于您之前使用reduceByKey考虑keyBy的想法,例如

rdd.keyBy(_.kind).reduceByKey(....)

您也可以将aggregateByKey视为最常见的转换(位于groupBy和亲戚身后)。

最后但并非最不重要的是,groupBy有两个变体,允许定义分区数或Partitioner。这些可以避免昂贵的洗牌。

阅读org.apache.spark.rdd.PairRDDFunctions

使用网络用户界面更好地了解您的"查询"的效果。了解您的数据将有很大帮助。花费足够的时间(因为优化查询的时间可能会被浪费)。

答案 1 :(得分:3)

如果你的结束结果是

,我认为你不应该使用reduceByKey
[(1, [2, 3]), (2 , [3, 4]), (3, [5])]

为什么呢?因为这是groupByKey所做的,所以它可能做得最好。

groupByKey的问题在于,您通常不需要具有相同密钥的所有值的列表(或数组),但您可以从此列表中获取。如果你真的不需要这个列表,你可以使用reduceByKey在与shuffle相同的步骤中进行缩减。

reduceByKey的两个优点:

  • 它可以在改组之前开始减少(减少同一执行器上的值,以避免不必要的网络负载)
  • 它永远不会将具有相同键的整个值数组加载到内存中。这在巨大的数据集中很重要,其中数组可能有几GB大。

在你的情况下,正如你提出的那样,第一点并不是很重要(因为数据没有真正减少,只是连接),第二点不适用,因为你想要整个列表。

但是,我强烈建议您考虑一下您是否真的需要整个列表,或者这只是计算中的一个步骤,特别是如果您正在使用大型数据集。

答案 2 :(得分:2)

回答这个可能有点晚了。它可能会帮助别人。

val tuples = List((1, 2), (1, 3), (2 , 3), (2, 4), (3, 5))
val context = getContext() // get Spark Context.
val tuplesRDD = context.parallelize(tuples)

val list = mutable.MutableList.empty[Int]
val addItemsToList = (s: mutable.MutableList[Int], v : Int) => s +=  v
val mergeLists = (x: mutable.MutableList[Int], 
                  y: mutable.MutableList[Int]) => x ++= y

val groupByKey = tuplesRDD.aggregateByKey(list)(addItemsToList, mergeLists)
groupByKey.cache()
groupByKey.foreach(x => println(x))

输出

(1,MutableList(2,3))
(2,MutableList(3,4))
(3,MutableList(5))