使用外部数据转换DStream RDD

时间:2017-08-25 16:29:28

标签: scala apache-spark spark-streaming

我们正在开发一个火花流式ETL应用程序,它将从Kafka获取数据,应用必要的转换并将数据加载到MongoDB中。从Kafka收到的数据是JSON格式。根据从MongoDB获取的查找数据,转换应用于RDD的每个元素(JSON字符串)。由于查找数据发生了变化,我需要为每个批处理间隔获取它。使用MongoDB中的SqlContext.read读取查找数据。我无法在DStream.transform中使用SqlContext.read,因为SqlContext不可序列化,因此我无法将其广播到工作节点。现在我尝试使用DStream.foreachRDD,在其中从MongoDB获取数据并将查找数据广播给worker。 RDD元素上的所有转换都在rdd.map闭包内执行,该闭包利用广播数据并执行转换并返回RDD。然后将RDD转换为数据帧并写入MongoDB。目前,这个应用程序运行速度很慢。

PS:如果我移动从DStream.foreachRDD中取出查找数据的代码部分并添加DStream.transform来应用转换并让DStream.foreachRDD只将数据插入MongoDB,性能非常好。但是使用这种方法,查找数据不会针对每个批处理间隔进行更新。

我正在寻求帮助,以了解这是否是一个好方法,我正在寻找一些提高绩效的指导。

以下是伪代码

package com.testing


object Pseudo_Code {
  def main(args: Array[String]) {

    val sparkConf = new SparkConf().setAppName("Pseudo_Code")
      .setMaster("local[4]")

    val sc = new SparkContext(sparkConf)
    sc.setLogLevel("ERROR")

    val sqlContext = new SQLContext(sc)
    val ssc = new StreamingContext(sc, Seconds(1))

    val mongoIP = "127.0.0.1:27017"

    val DBConnectionURI = "mongodb://" + mongoIP + "/" + "DBName"

    val bootstrap_server_config = "127.0.0.100:9092"
    val zkQuorum = "127.0.0.101:2181"

    val group = "streaming"

    val TopicMap = Map("sampleTopic" -> 1)


    val KafkaDStream = KafkaUtils.createStream(ssc, zkQuorum,  group,  TopicMap).map(_._2)

     KafkaDStream.foreachRDD{rdd => 
       if (rdd.count() > 0) {

       //This lookup data has information required to perform transformation
       //This information keeps changing, so the data should be fetched for every batch interval

       val lookup1 = sqlContext.read.format("com.mongodb.spark.sql.DefaultSource")
        .option("spark.mongodb.input.uri", DBConnectionURI)
        .option("spark.mongodb.input.collection", "lookupCollection1")
        .load()

      val broadcastLkp1 = sc.broadcast(lookup1)

      val new_rdd = rdd.map{elem => 
      val json: JValue = parse(elem)

      //Foreach element in rdd, there are some values that should be looked up from the broadcasted lookup data
      //"value" extracted from json
      val param1 = broadcastLkp1.value.filter(broadcastLkp1.value("key")==="value").select("param1").distinct()
      val param1ReplaceNull = if(param1.count() == 0){
                                  "constant"
                                }
                                else{
                                  param1.head().getString(0)
                                }
      //create a new JSON with a different structure
      val new_JSON = """"""

      compact(render(new_JSON))
     }

     val targetSchema = new StructType(Array(StructField("key1",StringType,true)
                                                  ,StructField("key2",TimestampType,true)))
     val transformedDf = sqlContext.read.schema(targetSchema).json(new_rdd)


     transformedDf.write
          .option("spark.mongodb.output.uri",DBConnectionURI)
          .option("collection", "tagetCollectionName")
          .mode("append").format("com.mongodb.spark.sql").save()
       }
   }

    // Run the streaming job
    ssc.start()
    ssc.awaitTermination()
  }




}

1 个答案:

答案 0 :(得分:0)

经过研究,有效的解决方案是在工作人员阅读后广播数据帧。以下是我为改善性能而必须做的代码更改。

int *ptr = (int*)&local;

另外,在群集上运行时,此方法存在问题。访问广播的数据帧时抛出空指针异常。我创建了另一个线程。 Spark Streaming - null pointer exception while accessing broadcast variable