将密钥减少为Spark中的元组列表

时间:2016-01-18 02:11:35

标签: scala apache-spark

我正在尝试转置我的数据,以便它是每个键而不是数据列的元组列表。

所以输入我有:

1   234   54   7   9
2   654   34   2   1
1   987   22   4   6

我希望将输出写入镶木地板文件:

1:2   ((234, 54, 7, 9), (987, 22, 4, 6))
2:6   ((654, 34 2 1))

作为输入,我有2套实木复合地板数据。我读了它们并作为数据帧加入。 然后我将每一行映射到键值对,然后reduceByKey将每个键组合成大的元组列表。

val keyedRDD = joinedDF.map(row => (
  ""+row.getInt(0)+":"+(row.getInt(1)/PARTITION_SIZE),
  List(Record(
    row.getInt(1),
    row.getInt(2),
    row.getInt(3),
    row.getInt(4)
  ))
))

val reduced = keyedRDD.reduceByKey(_:::_)

PARTITION_SIZE这里只是我为每次运行设置的变量,用于将数据拆分为该大小的块。所以,如果我传入100000并且有200万条记录,则编号为0-99,999的记录将在一个存储桶中,100,000-199,999将在下一个存储区中,依此类推。

记录只是一个保存这些数据的简单案例类,我尝试过只使用简单的元组,只是将值放在一个列表中,并且结果相同。

据我所知,这应该减少到每个键一个列表的输出,如上所述。但是,我无法完成这项工作。在Spark History Server中,它总是显示它挂在地图阶段(甚至没有启动它),即使Ganglia显示至少80%的CPU使用率和高内存使用率。控制台卡在这些消息上:

16/01/18 01:26:10 INFO MapOutputTrackerMaster: Size of output statuses for shuffle 2 is 2485 bytes
16/01/18 01:26:10 INFO MapOutputTrackerMasterEndpoint: Asked to send map output locations for shuffle 2 to ip-172-31-7-127.ec2.internal:34337
16/01/18 01:26:10 INFO MapOutputTrackerMasterEndpoint: Asked to send map output locations for shuffle 2 to ip-172-31-7-129.ec2.internal:45407
16/01/18 01:26:17 INFO MapOutputTrackerMasterEndpoint: Asked to send map output locations for shuffle 1 to ip-172-31-7-128.ec2.internal:59468
16/01/18 01:26:17 INFO MapOutputTrackerMaster: Size of output statuses for shuffle 1 is 75087 bytes
16/01/18 01:26:18 INFO MapOutputTrackerMasterEndpoint: Asked to send map output locations for shuffle 1 to ip-172-31-7-127.ec2.internal:34337
16/01/18 01:26:18 INFO MapOutputTrackerMasterEndpoint: Asked to send map output locations for shuffle 1 to ip-172-31-7-129.ec2.internal:45407

一个数据集大约是3GB,另一个大约是22GB,所以真的不大。但我想也许我的内存已经不足(即使我没有收到OOM或遗嘱执行人丢失的信息,直到20多个小时被卡住)。我尝试过带有2个从节点的m3.xlarge的EMR集群,带有6个从节点的m3.xlarge,甚至还有6个从节点的r3.xlarge,但仍然遇到同样的问题。我已经设置了我的EMR集群,为Spark提供了最大可能的内存分配,给定Spark动态分配,与memoryFraction设置混淆等等。

我只是无法弄清楚为什么它会被挂在哪里。我尝试简化它,并在地图中将其设为(键,1)RDD并添加减少并在20分钟内完成。

1 个答案:

答案 0 :(得分:1)

在昂贵的操作中附加到列表中并且是一个常见的错误。记住Scala对不可变对象的偏见。最好的起点是,谷歌“Scala list append performance”。这将为您提供几个很好的博客,详细描述问题和建议。通常,附加到列表是一项昂贵的操作,因为每个操作都会产生一个新列表 - 非常计算和内存密集型。您可以在列表前添加,或者最佳答案通常是listbuffer。再看一下博客并注意性能特征

http://www.scala-lang.org/docu/files/collections-api/collections_40.html