与广播变量的加入过程最终会无休止地溢出

时间:2015-09-30 13:44:30

标签: scala join intellij-idea apache-spark

我在独立模式下从文本文件加入两个RDD。一个有4亿(9 GB)行,另一个有400万(110 KB)。

3-grams  doc1           3-grams   doc2
ion -    100772C111      ion -    200772C222  
on  -    100772C111      gon -    200772C222  
 n  -    100772C111        n -    200772C222
... -    ....            ... -    .... 
ion -    3332145654      on  -    58898874
mju -    3332145654      mju -    58898874
... -    ....            ... -    ....

在每个文件中,doc编号(doc1或doc2)显示在另一个文件下。由于加入,我希望在docs.e.g。

之间获得一些常见的3克
  (100772C111-200772C222,2) --> There two common 3-grams which are 'ion' and  '  n'

我运行代码的服务器有128 GB RAM和24个内核。我设置了IntelliJ配置 - 使用-Xmx64G

的VM选项部分

这是我的代码:

val conf = new SparkConf().setAppName("abdulhay").setMaster("local[4]").set("spark.shuffle.spill", "true")
      .set("spark.shuffle.memoryFraction", "0.6").set("spark.storage.memoryFraction", "0.4")
      .set("spark.executor.memory","40g")
      .set("spark.driver.memory","40g")

val sc = new SparkContext(conf)

val emp = sc.textFile("\\doc1.txt").map(line => (line.split("\t")(3),line.split("\t")(1))).distinct()
    val emp_new = sc.textFile("\\doc2.txt").map(line => (line.split("\t")(3),line.split("\t")(1))).distinct()

val emp_newBC = sc.broadcast(emp_new.groupByKey.collectAsMap)

val joined = emp.mapPartitions(iter => for {
      (k, v1) <- iter
      v2 <- emp_newBC.value.getOrElse(k, Iterable())
    } yield (s"$v1-$v2", 1))

val olsun = joined.reduceByKey((a,b) => a+b)

olsun.map(x => x._1 + "\t" + x._2).saveAsTextFile("...\\out.txt")

如图所示,在使用广播变量的连接过程中,我的键值会发生变化。所以我似乎需要重新分配连接的值?它非常昂贵。结果,我结束了太多的溢出问题,它从未结束。我认为128 GB内存必须足够。据我所知,当使用广播变量时​​,洗牌正在显着减少?那我的申请有什么问题?

提前致谢。

编辑:

我也尝试过spark的连接功能,如下所示:

var joinRDD = emp.join(emp_new);

val kkk = joinRDD.map(line => (line._2,1)).reduceByKey((a, b) => a + b)

再次结束了太多的溢出。

EDIT2:

val conf = new SparkConf().setAppName("abdulhay").setMaster("local[12]").set("spark.shuffle.spill", "true")
      .set("spark.shuffle.memoryFraction", "0.4").set("spark.storage.memoryFraction", "0.6")
      .set("spark.executor.memory","50g")
      .set("spark.driver.memory","50g")
    val sc = new SparkContext(conf)

val emp = sc.textFile("S:\\Staff_files\\Mehmet\\Projects\\SPARK - scala\\wos14.txt").map{line => val s = line.split("\t"); (s(5),s(0))}//.distinct()
    val emp_new = sc.textFile("S:\\Staff_files\\Mehmet\\Projects\\SPARK - scala\\fwo_word.txt").map{line => val s = line.split("\t"); (s(3),s(1))}//.distinct()

    val cog = emp_new.cogroup(emp)

val skk =  cog.flatMap {
      case (key: String, (l1: Iterable[String], l2: Iterable[String])) =>
        (l1.toSeq ++ l2.toSeq).combinations(2).map { case Seq(x, y) => if (x < y) ((x, y),1) else ((y, x),1) }.toList
    }

    val com = skk.countByKey()

1 个答案:

答案 0 :(得分:1)

我不会使用广播变量。当你说:

val emp_newBC = sc.broadcast(emp_new.groupByKey.collectAsMap)

Spark首先将ENTIRE数据集移动到主节点,这是一个巨大的瓶颈,容易在主节点上产生内存错误。然后,这块内存被拖回到所有节点(大量网络开销),也会产生内存问题。

相反,请使用join加入RDD(请参阅说明here

如果钥匙太少,也要弄清楚。对于加入Spark,基本上需要将整个密钥加载到内存中,如果你的密钥太少,对任何给定的执行程序来说可能仍然是一个太大的分区。

另外注意:reduceByKey无论如何都会重新分配。

编辑:---------------------

好的,鉴于澄清,并假设每个文档#3克的数量不是太大,这就是我要做的:

  1. 按3克键入两个文件以获取(3-gram,doc#)元组。
  2. cogroup两个RDD,它们可以获得3gram密钥和2个doc#列表
  3. 在单个scala函数中处理它们,输出一组(doc-pairs)的所有唯一排列。
  4. 然后执行coutByKeycountByKeyAprox以计算每个文档对的不同3克数。
  5. 注意:您可以跳过此.distinct()来电。此外,您不应该将每一行拆分两次。更改line => (line.split("\t")(3),line.split("\t")(1)))

    line => { val s = line.split("\t"); (s(3),s(1)))

    编辑2:

    你似乎也在严重调整记忆力。例如,使用.set("spark.shuffle.memoryFraction", "0.4").set("spark.storage.memoryFraction", "0.6")基本上没有任务用于执行任务(因为它们总计为1.0)。我本应该早点看到这个问题本身。

    查看修改指南herehere

    此外,如果您在一台计算机上运行它,您可能会尝试使用单个巨大的执行程序(甚至完全忽略Spark),因为您不需要分布式处理平台的开销(以及分布式硬件容错等)。