groupByKey与aggregateByKey - 差异究竟来自哪里?

时间:2017-09-20 11:22:25

标签: scala apache-spark

groupByKey的文档中有一些可怕的语言,警告它可能“非常昂贵”,并建议尽可能使用aggregateByKey

我想知道成本的差异是否来自这样的事实:对于某些聚合,整个组永远不需要被收集并加载到同一节点,或者如果实现中存在其他差异。

基本上,问题是rdd.groupByKey()是否等同于rdd.aggregateByKey(Nil)(_ :+ _, _ ++ _),还是会更贵。

2 个答案:

答案 0 :(得分:5)

如果要缩减为单个元素而不是列表。

例如:像字数一样,那么aggregateByKey表现得更好,因为它不会像链接performance of group by vs aggregate by中所解释的那样导致混乱。

但在你的情况下,你正在合并到一个列表。在aggregateByKey的情况下,它将首先将分区中的键的所有值减少到单个列表,然后发送shuffle数据。这将创建与分区一样多的列表,并且内存将很高。

在groupByKey的情况下,合并仅在负责密钥的一个节点处发生。创建的列表数量在此处仅为每个键一个。 在合并到列表的情况下,groupByKey在内存方面是最佳的。

另请参阅:SO Answer by zero323

我不确定您的用例。但是如果你可以在最终结果中限制列表中元素的数量,那么与groupByKey相比,当然aggregateByKey / combineByKey将提供更好的结果。例如:如果您只想获取给定键的前10个值。然后,您可以使用combineByKey with proper merge and combiner functions来有效地实现此目的 groupByKey and take 10.

答案 1 :(得分:-1)

让我帮助说明为什么 groupByKey 操作会导致更多费用

通过理解此特定操作的语义,reduce任务需要做的是将与单个唯一键关联的整个值分组。

总之,让我们来看看它的签名

def groupByKey(): RDD[(K, Iterable[V])]

由于" groupby" 操作,与在不同节点上分区的此密钥相关联的所有值都无法预先合并。通过网络传输大量数据,导致高网络负载。

但是aggregateByKey与它不一样。让我澄清签名:

def aggregateByKey[U](zeroValue: U)(seqOp: (U, V) ⇒ U, combOp: (U, U) ⇒ U)(implicit arg0: ClassTag[U]): RDD[(K, U)]

火花引擎如何实现此操作语义如下:

在分区中它将具有预合并操作,意味着"特定的缩减器"只需要获取随机播放地图的所有预先合并的中间结果

这将使网络明显变亮。