Spark reduceBykey效果不佳

时间:2017-08-11 14:52:24

标签: scala apache-spark spark-dataframe

我正在使用Scala在Spark上编写程序。它用于计算键的数量。这是数据示例:

 Name     Fruit         Place
 A        apple         China
 A        apple         China
 A        apple         U.S
 A        banana        U.K
 B        apple         Japan
 B        orange        Chile
 C        apple         French

它是许多列的数据框,但我只关心上面的三列,因此可能会有一些重复的记录。我想数一下,例如,A吃的水果的生产地点数量。

val res = data.select("name","fruit","place")
.map(v=>((v.getString(0),v.getString(1)),ArrayBuffer(v.getString(2)))).rdd.reduceByKey((a,b)=>a++=b)
.map(v=>(v._1._1,Map(v._1._2 -> v._2.toSet.size))).reduceByKey((a,b)=>a++=b)

我首先选择我需要的列,然后使用(" name"," fruit")作为关键,在一个ArrayBuffer中为每种吃过的水果收集生产地点每个人。然后我使用" name"作为在{" apple":2}等地图中收集每种水果的生产地点数量的关键。所以结果非常像RDD [(" name",Map(" fruit" - >" place count"))]。

在程序中我做了 3次的这种工作来计算类似于上面例子的信息。例如,计算每个人吃掉的一个生产地点的不同水果的数量。

数据大小约为80GB,我在50个执行器上运行作业。每个执行器有4个内核,内存为24GB。此外,数据被重新划分为200个分区。所以这项工作应该在我预期的很短的时间内完成。但是,由于 org.apache.spark.shuffle.MetadataFetchFailedException:缺少shuffle 10的输出位置 和<,因此我花了一天多的时间来运行该作业并失败了strong> java.lang.OutOfMemoryError:超出GC开销限制

我做了很多事情来优化这个程序,比如重置spark.mesos.executor.memoryOverhead并使用可变映射来最小化频繁创建和清理对象的GC成本。我甚至尝试使用reduceByKey将具有相同密钥的数据移动到一个分区中以提高性能,但几乎没有帮助。代码如下:

val new_data = data.map(v=>(v.getAs[String]("name"),ArrayBuffer((v.getAs[String]("fruit"),v.getAs[String]("place"))))) 
 .rdd.reduceByKey((a,b)=>a++=b).cache()

然后,每次进行类似的计算时,我都不需要对数据进行随机播放。后来的工作可以在new_data的基础上完成。但是,似乎这种优化并不起作用。

最后,我发现大约有50%的数据在字段上具有相同的值&#34; name&#34 ;,说&#34; H&#34;。我删除了名为&#34; H&#34;的数据。并且工作在1小时内完成。

以下是我的问题:

  1. 为什么密钥的分配会对reduceByKey的性能产生如此大的影响?我使用&#34;分发&#34;表示不同键的出现次数。在我的情况下,数据的大小并不大,但是一个键在数据中占主导地位,因此性能受到很大影响。我认为它是reduceByKey的问题,我错了吗?

  2. 如果我必须保留名称为&#34; H&#34;的记录,如何避免性能问题?

  3. 是否可以使用reduceByKey重新分区数据并将具有相同密钥(&#34; name&#34;)的记录放入一个分区?

  4. 将具有相同密钥(&#34; name&#34;)的记录移动到一个分区以提高性能是否真的有帮助?我知道这可能会导致内存问题,但我必须在程序中多次运行类似的代码,所以我想这可能对以后的工作有所帮助。我是对的吗?

  5. 感谢您的帮助!

0 个答案:

没有答案