您好我经常需要在我的代码中使用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个元素的列表?
你认为使用其他方法有更快的方法来达到相同的结果吗?谢谢。
答案 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
的两个优点:
在你的情况下,正如你提出的那样,第一点并不是很重要(因为数据没有真正减少,只是连接),第二点不适用,因为你想要整个列表。
但是,我强烈建议您考虑一下您是否真的需要整个列表,或者这只是计算中的一个步骤,特别是如果您正在使用大型数据集。
答案 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))