foreachPartitionAsync throws无法在已停止的SparkContext上调用方法

时间:2017-01-06 09:24:14

标签: scala asynchronous apache-spark future

我有2个不同数据的文件。我试图在2差分RDD&读取它们然后将它们转换为Dataframe&插入蜂巢。我能够做这个正常的代码。但是火花处理了一个接一个的RDD计算。因此,虽然我在群集中有足够的资源,但第二个人正在等待第一个人过来。我了解到可以使用异步方法并行化RDD计算。所以我正在尝试foreachPartitionAsync。但它会抛出错误,我无法进一步调试。示例代码:

object asynccode {
  def main(args: Array[String]) = {
    val conf = new SparkConf()
      .setAppName("Parser")
    val sc = new SparkContext(conf)
    val hiveContext = new HiveContext(sc)
    import hiveContext.implicits._

    val ercs = sc.wholeTextFiles("hdfs://x.x.x.x:8020/file1.txt")
    val test = ercs.map { k =>
      var rc = method1(k._2, k._1).toSeq
      rc
    }
      .flatMap(identity)
      .foreachPartitionAsync { f =>
        f.toSeq.toDF()
          .write.insertInto("dbname.tablename1")
      }

    val ercs2 = sc.wholeTextFiles("hdfs://x.x.x.x:8020/file2.txt")
    val test2 = ercs2.map { k =>
      var rs = method2(k._2, k._1)
      rs
    }
      .flatMap(identity)
      .foreachPartitionAsync(f => f.toSeq.toDF()
        .write.insertInto("dbname.tablename2")

      )
    sc.stop()
  }

  def method1 = ???
  def method2 = ???
}

但它会抛出以下错误消息。如果我从代码中删除foreachPartitionAsync,它可以正常工作。不确定我对foreachPartitionAsync做错了什么。

  

任务序列化失败:java.lang.IllegalStateException:无法在已停止的SparkContext上调用方法。

更新: 谢谢你的建议。我在下面更新了它。但现在它根本没有做任何事情。 Spark web UI,我可以看到没有触发任何阶段(它是空的)。我的所有表都没有更新。但是工作完成没有错误。

val ercs = sc.wholeTextFiles("hdfs://x.x.x.x:8020/file1.txt")
    val test = ercs.map { k =>
      var rc = method1(k._2, k._1).toSeq
      rc
    }
      .flatMap(identity)
     toDF()
     val f1 = Future(test.write.insertInto("dbname.tablename1"))
      }

    val ercs2 = sc.wholeTextFiles("hdfs://x.x.x.x:8020/file2.txt")
    val test2 = ercs2.map { k =>
      var rs = method2(k._2, k._1)
      rs
    }
      .flatMap(identity)
      toSeq.toDF()

val f2 = Future(test2.write.insertInto("dbname.tablename2"))

      )
      Future.sequence(Seq(f1,f2)).onComplete(_ => sc.stop)

我错过了什么?

1 个答案:

答案 0 :(得分:1)

您无需等待SparkContext完成就停止FutureActions。您应该等待操作完成并停止响应中的上下文:

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.util.{Success, Failure}

val f1: Future[Unit] = sc.range(1, 200).foreachAsync(_ => Thread.sleep(10))
val f2: Future[Unit] = sc.range(1, 200).foreachAsync(_ => Thread.sleep(10))

Future.sequence(Seq(f1, f2)).onComplete {
  case Success(_) => sc.stop
  case Failure(e) => 
    e.printStackTrace  // or some other appropriate actions 
    sc.stop
}

即使我们忽略了异步操作,也说你的代码无效。您无法在操作或转换中使用分布式数据结构

 .foreachPartitionAsync(
   f => f.toSeq.toDF().write.insertInto("dbname.tablename2")
 )

如果您想要异步写入操作,请直接使用Futures

val df1: Dataframe = ???
val df2: Dataframe = ???

val f1: Future[Unit] = Future(df1.write.insertInto("dbname.tablename1"))
val f2: Future[Unit] = Future(df2.write.insertInto("dbname.tablename2"))

并等待操作完成,如上所示。