如何在旧版Spark流中使用foreachRDD

时间:2019-01-03 11:03:29

标签: apache-spark spark-streaming

在使用foreachRDD进行CSV数据处理时出现异常。这是我的代码

  case class Person(name: String, age: Long)
  val conf = new SparkConf()
  conf.setMaster("local[*]")
  conf.setAppName("CassandraExample").set("spark.driver.allowMultipleContexts", "true")
  val ssc = new StreamingContext(conf, Seconds(10))
  val smDstream=ssc.textFileStream("file:///home/sa/testFiles")

  smDstream.foreachRDD((rdd,time) => {
  val peopleDF = rdd.map(_.split(",")).map(attributes => 
  Person(attributes(0), attributes(1).trim.toInt)).toDF()
  peopleDF.createOrReplaceTempView("people")
  val teenagersDF = spark.sql("insert into table devDB.stam SELECT name, age 
  FROM people WHERE age BETWEEN 13 AND 29")
  //teenagersDF.show  
    })
  ssc.checkpoint("hdfs://go/hive/warehouse/devDB.db")
  ssc.start()

我遇到以下错误 java.io.NotSerializableException:已启用DStream检查点,但DStream及其功能不可序列化 org.apache.spark.streaming.StreamingContext 序列化堆栈:         -无法序列化的对象(类:org.apache.spark.streaming.StreamingContext,值:org.apache.spark.streaming.StreamingContext@1263422a)         -字段(类:$ iw,名称:ssc,类型:类org.apache.spark.streaming.StreamingContext)

请帮助

1 个答案:

答案 0 :(得分:0)

这个问题不再有意义了,因为 dStreams已被弃用/放弃。

在代码中需要考虑一些事情,因此很难找到确切的问题。就是说,我不仅要思考,而且我不是序列化专家。

您可以找到一些尝试直接写到Hive表而不是路径的文章,在我的回答中我使用了一种方法,但是您可以使用Spark SQL的方法为TempView编写,这一切都是可能的

我模拟了QueueStream的输入,因此不需要拆分。如果遵循相同的“全局”方法,则可以根据自己的情况对此进行调整。我选择写入需要时创建的镶木地板文件。您可以创建您的tempView,然后按照初始方法使用spark.sql。

  

DStream的输出操作是:

     
      
  • print()
  •   
  • saveAsTextFiles(前缀,[后缀])
  •   
  • saveAsObjectFiles(前缀,[后缀])
  •   
  • saveAsHadoopFiles(前缀,[后缀])
  •   
  • foreachRDD(func)
  •   
     

foreachRDD

     

最通用的输出运算符,将函数func应用于   从流中生成的每个RDD。此功能应推送数据   在每个RDD中保存到外部系统,例如将RDD保存到文件中,或   通过网络将其写入数据库。注意函数func   在运行流应用程序的驱动程序进程中执行,   并且通常会有RDD动作会迫使   流式RDD的计算。

     

它说明了保存到文件,但是它可以通过foreachRDD完成您想要的操作,尽管我   认为这个想法是针对外部系统的。保存到文件更快   在我看来,而不是逐步编写表格   直。您希望通过Streaming尽快卸载数据,因为卷通常很高。

两个步骤:

  

在流类的单独类中-在Spark 2.4下运行:

case class Person(name: String, age: Int)
  

然后您需要应用流逻辑-您可能需要一些导入   否则我在DataBricks下运行该笔记本时就会发现该笔记本:

import org.apache.spark.sql.SparkSession
import org.apache.spark.rdd.RDD
import org.apache.spark.streaming.{Seconds, StreamingContext}
import scala.collection.mutable
import org.apache.spark.sql.SaveMode

val spark = SparkSession
           .builder
           .master("local[4]")
           .config("spark.driver.cores", 2)
           .appName("forEachRDD")
           .getOrCreate()

val sc = spark.sparkContext
val ssc = new StreamingContext(spark.sparkContext, Seconds(1)) 

val rddQueue = new mutable.Queue[RDD[List[(String, Int)]]]()
val QS = ssc.queueStream(rddQueue) 

QS.foreachRDD(q => {
   if(!q.isEmpty) {   
      val q_flatMap = q.flatMap{x=>x}
      val q_withPerson = q_flatMap.map(field => Person(field._1, field._2))
      val df = q_withPerson.toDF()      

      df.write
        .format("parquet")
        .mode(SaveMode.Append)
        .saveAsTable("SO_Quest_BigD")
   }
 }
)

ssc.start()
for (c <- List(List(("Fred",53), ("John",22), ("Mary",76)), List(("Bob",54), ("Johnny",92), ("Margaret",15)), List(("Alfred",21), ("Patsy",34), ("Sylvester",7)) )) {
   rddQueue += ssc.sparkContext.parallelize(List(c))
} 
ssc.awaitTermination()