groupByKey
的文档中有一些可怕的语言,警告它可能“非常昂贵”,并建议尽可能使用aggregateByKey
。
我想知道成本的差异是否来自这样的事实:对于某些聚合,整个组永远不需要被收集并加载到同一节点,或者如果实现中存在其他差异。
基本上,问题是rdd.groupByKey()
是否等同于rdd.aggregateByKey(Nil)(_ :+ _, _ ++ _)
,还是会更贵。
答案 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)]
火花引擎如何实现此操作语义如下:
在分区中它将具有预合并操作,意味着"特定的缩减器"只需要获取随机播放地图的所有预先合并的中间结果。
这将使网络明显变亮。