groupByKey和aggregateByKey - 两者的区别在哪里?

4

groupByKey的文档中有一些令人担忧的语言,警告它可能非常昂贵,并建议尽可能使用aggregateByKey代替。

我想知道成本差异是否源于某些聚合不需要将整个组收集并加载到同一节点,或者实现上还有其他差异。

基本上,问题是rdd.groupByKey()是否等价于rdd.aggregateByKey(Nil)(_ :+ _, _ ++ _),还是说它仍然更昂贵。


我在想成本差异是否来自于某些聚合操作,整个组永远不需要被收集并加载到同一节点,或者实现上还有其他差异。 - T. Gawęda
2
投票关闭的人们 - 能解释一下吗?“不是编程”?哼? - Dima
1
声明:在大多数情况下,rdd.groupByKey()的成本显著低于rdd.aggregateByKey(Nil)(_ :+ _, _ ++ _)。我在这里提出了这一点(链接)并与@eliasah在这里进行了讨论(外部链接)。 - zero323
2个回答

6
如果你要将一个列表缩减为单个元素,例如像单词计数这样的操作,那么使用aggregateByKey会更好,因为它不会像链接performance of group by vs aggregate by中所解释的那样引起洗牌。
但在你的情况下,你正在合并为一个列表。在使用aggregateByKey时,它将首先将分区中的所有键值对缩减为单个列表,然后发送数据进行洗牌。这将创建与分区一样多的列表,占用的内存将很高。
而在使用groupByKey时,合并仅发生在负责该键的一个节点上。这里每个键只创建一个列表。
如果要合并到列表中,则从内存方面考虑,groupByKey是最优选择。
另请参阅: zero323的SO答案
我不确定你的使用情况。但是,如果您可以限制最终结果列表中元素的数量,则使用aggregateByKey / combineByKey肯定比groupByKey更好。例如:如果您只想为给定键获取前10个值,则可以通过使用具有适当合并和组合器函数的combineByKey来有效地实现这一点,而不是使用groupByKey and take 10。

可以安全地假设,只有在数据分布在多个分区上并且所使用的函数可以作为组合器应用于每个分区时,(combine/aggregate/reduce)ByKey 的好处才能得到充分利用。 - philantrovert
假设是正确的。此外,我提供了一个使用案例,除了这些操作在哪里有效之外。简而言之,当您的数据可以被收缩时,请使用(aggregate/reduce/combine)ByKey。 - Knight71

-1

让我来帮助解释为什么groupByKey操作会导致更高的成本

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

简而言之,让我们看一下它的签名

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

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

但是,aggregateByKey与之不同。让我澄清一下签名:

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

Spark引擎实现操作的语义如下:

在分区中,它将具有预合并操作,这意味着“特定的Reducer”只需要获取洗牌映射的所有预合并中间结果。

这将使网络IO显着减轻。


所以,您似乎在说rdd.aggregateByKey(Nil)(_ :+ _, _ ++ _)确实等同于rdd.groupByKey。对吗? - Dima
@Dima,绝对不行。 - ashburshui
1
那我不明白你在说什么。我的聚合结果对于同一节点上的一个键具有所有元素。这不是你说导致“groupBy”成本增加的原因吗? - Dima

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接