问题 Spark groupByKey另类


根据Databricks的最佳实践,Spark groupByKey 应该避免作为Spark groupByKey 处理工作的方式是首先将信息拖过工人,然后进行处理。 说明

所以,我的问题是,有什么替代方案 groupByKey 以某种方式,它将以分布式和快速的方式返回以下内容?

// want this
{"key1": "1", "key1": "2", "key1": "3", "key2": "55", "key2": "66"}
// to become this
{"key1": ["1","2","3"], "key2": ["55","66"]}

也许对我来说似乎 aggregateByKey 要么 glom 可以先在分区中做到(map)然后将所有列表连接在一起(reduce)。


2906
2018-06-24 14:30


起源

在同一链接中以下是比groupByKey更喜欢的函数:combineByKey可以在组合元素时使用,但返回类型与输入值类型不同。 foldByKey使用关联函数和中性“零值”合并每个键的值。 - Abhishek Choudhary
我认为 groupByKey 这里是最有效的选择(包括时间和存储)。如果它是OOM,你只需要一个更大的集群。 - ShuaiYuan


答案:


groupByKey 如果我们想要每个键的“小”值集合,就像在问题中一样。

TL; DR

“不要使用”警告 groupByKey 适用于两个一般情况:

1)您希望聚合值:

  • rdd.groupByKey().mapValues(_.sum)
  • rdd.reduceByKey(_ + _)

在这种情况下, groupByKey 将浪费资源实现一个集合,而我们想要的只是一个元素作为答案。

2)您希望通过低基数键对非常大的集合进行分组:

  • allFacebookUsersRDD.map(user => (user.likesCats, user)).groupByKey() 
  • 只是不要

在这种情况下, groupByKey 可能会导致OOM错误。

groupByKey 在一个执行程序中实现具有相同键的所有值的集合。如上所述,它具有内存限制,因此,根据具体情况,其他选项更好。

所有分组功能,如 groupByKeyaggregateByKey 和 reduceByKey 靠基地: combineByKey 因此,对于问题中的用例,没有其他选择会更好,它们都依赖于相同的共同过程。


15
2018-06-24 16:33



那么,没有办法根据键对数组中的值进行分组,每个都在自己的worker中,然后将得到的数组与其他部分数组合并?我的问题是创建一个反向索引,我将在一个数组中包含一个页面的所有单词,并将该键作为url。 - Adriano Almeida
@AdrianoAlmeida是 - groupByKey :-)。阅读我在答案中的链接: github.com/apache/spark/blob/...  他们在那里建议反对内存影响的地图侧组合器b / c。你可以试试 aggregateByKey 如果您认为您的特定用例将首先受益于地图侧组合。 - maasg
@massg如果我们使用CassandraSQLContext使用Table_name Group by Column1中的Column1,max(Column2)来使用此查询,这是否意味着它还会妨碍性能。如果,是的,将它转换为reduceby的替代方法是什么 - Naresh
当reduce操作不关联时,最好的处理方法是什么?也就是说,如果我需要groupByKey,对分组进行排序,将一个函数应用到排序列表,我就不能使用reduceByKey。我应该使用partitionBy + mapPartitions而不是groupByKey + mapValues来避免OOM错误吗?是否存在为每个密钥创建分区的问题? - Bob Baxley
很好的答案!很干净 - guilhermecgs