【问题标题】:Efficient grouping by key using mapPartitions or partitioner in Spark在 Spark 中使用 mapPartitions 或 partitioner 进行有效的按键分组
【发布时间】:2016-05-03 16:32:12
【问题描述】:

所以,我有如下数据,

[ (1, data1), (1, data2), (2, data3), (1, data4), (2, data5) ]

我想将其转换为以下内容,以进行进一步处理。

[ (1, [data1, data2, data4]), (2, [data3, data5]) ]

我使用了 groupByKey 和 reduceByKey,但由于数据量很大,它失败了。数据不高,但很宽。换句话说,键是从 1 到 10000,但值列表的范围是从 100k 到 900k。

我正在努力解决这个问题,并计划申请mapPartitions(Hash)partitioner

所以,如果其中一个可行,我想知道

  1. 使用mapPartions,你能给出一些代码sn-p吗?
  2. 使用(Hash)partitioner,您能否举个例子,如何通过键等元素来控制分区。例如有没有一种方法可以根据键(即上面的 1,2,..)创建每个分区,而无需洗牌。

Exception in thread "main" org.apache.spark.SparkException: Job aborted due to stage failure: ShuffleMapStage 9 (flatMap at TSUMLR.scala:209) has failed the maximum allowable number of times: 4. Most recent failure reason: org.apache.spark.shuffle.MetadataFetchFailedException: Missing an output location for shuffle 1
        at org.apache.spark.MapOutputTracker$$anonfun$org$apache$spark$MapOutputTracker$$convertMapStatuses$2.apply(MapOutputTracker.scala:542)
        at org.apache.spark.MapOutputTracker$$anonfun$org$apache$spark$MapOutputTracker$$convertMapStatuses$2.apply(MapOutputTracker.scala:538)
        at scala.collection.TraversableLike$WithFilter$$anonfun$foreach$1.apply(TraversableLike.scala:772)
        at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:33)
        at scala.collection.mutable.ArrayOps$ofRef.foreach(ArrayOps.scala:108)
        at scala.collection.TraversableLike$WithFilter.foreach(TraversableLike.scala:771)
        at org.apache.spark.MapOutputTracker$.org$apache$spark$MapOutputTracker$$convertMapStatuses(MapOutputTracker.scala:538)
        at org.apache.spark.MapOutputTracker.getMapSizesByExecutorId(MapOutputTracker.scala:155)
        at org.apache.spark.shuffle.BlockStoreShuffleReader.read(BlockStoreShuffleReader.scala:47)
        at org.apache.spark.rdd.ShuffledRDD.compute(ShuffledRDD.scala:98)
        at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:306)
        at org.apache.spark.rdd.RDD.iterator(RDD.scala:270)
        at org.apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:38)
        at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:306)
        at org.apache.spark.rdd.RDD.iterator(RDD.scala:270)
        at org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:73)
        at org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:41)
        at org.apache.spark.scheduler.Task.run(Task.scala:89)
        at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:213)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:745)

【问题讨论】:

    标签: apache-spark grouping partition


    【解决方案1】:

    建议的方法都不起作用。根据定义,分区器必须对数据进行洗牌,并且会受到与groupByKey 相同的限制。 mapPartitions 无法将数据移动到另一个分区,所以它完全没用。由于您对问题的描述相当模糊,因此很难给出具体建议,但总的来说,我会尝试以下步骤:

    • 尝试重新考虑问题。你真的需要一次所有的价值观吗?你打算如何利用这些?如果不收集到单个分区,您能否获得相同的结果?
    • 是否可以减少流量?您期望有多少独特的价值?是否可以在 shuffle 之前压缩数据(例如计数值或使用 RLE)?
    • 考虑使用更大的执行器。 Spark 必须仅将单个键的值保存在内存中,并且可以将处理后的键溢出到磁盘。
    • 按键拆分数据:

      val keys =  rdd.keys.distinct.collect
      val rdds = keys.map(k => rdd.filter(_._1 == k))
      

      并分别处理每个 RDD。

    【讨论】:

    • 你的建议真的很棒! ) 真的很有帮助。
    猜你喜欢
    • 1970-01-01
    • 2014-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-06
    • 1970-01-01
    相关资源
    最近更新 更多