Json 广播变量未显示在分区内Apache Spark

Json 广播变量未显示在分区内Apache Spark,json,mongodb,scala,apache-spark,apache-spark-sql,Json,Mongodb,Scala,Apache Spark,Apache Spark Sql,场景和问题: 我想根据查找表的值向JSON对象添加两个属性,并将JSON插入Mongo DB。我有一个保存查找表的广播变量。但是,正如您在代码中看到的,我无法在foreachPartition内部访问它。它没有给我任何错误,只是没有显示任何内容。此外,由于它,我无法将JSON插入Mongo DB。我找不到对这种行为的任何解释。非常感谢您的任何解释或解决方案 这是我的全部代码: object ProcessMicroBatchStreams { val calculateDistance = ud

场景和问题: 我想根据查找表的值向JSON对象添加两个属性,并将JSON插入Mongo DB。我有一个保存查找表的广播变量。但是,正如您在代码中看到的,我无法在foreachPartition内部访问它。它没有给我任何错误,只是没有显示任何内容。此外,由于它,我无法将JSON插入Mongo DB。我找不到对这种行为的任何解释。非常感谢您的任何解释或解决方案

这是我的全部代码:

object ProcessMicroBatchStreams {
val calculateDistance = udf { 
 (lat: String, lon: String) =>      
 GeoHash.getDistance(lat.toDouble, lon.toDouble) }
 val DB_NAME = "IRT"
 val COLLECTION_NAME = "sensordata"
 val records = Array[String]()

def main(args: Array[String]): Unit = {
  if (args.length < 0) {
  System.err.println("Usage: ProcessMicroBatchStreams <master> <input_directory>")
  System.exit(1)
}
val conf = new SparkConf()
  .setMaster("local[*]")
  .setAppName(this.getClass.getCanonicalName)
  .set("spark.hadoop.validateOutputSpecs", "false")
/*.set("spark.executor.instances", "3")
.set("spark.executor.memory", "18g")
.set("spark.executor.cores", "9")
.set("spark.task.cpus", "1")
.set("spark.driver.memory", "10g")*/

val sc = new SparkContext(conf)
val ssc = new StreamingContext(sc, Seconds(60))
val sqc = new SQLContext(sc)
val gpsLookUpTable = MapInput.cacheMappingTables(sc, sqc).persist(StorageLevel.MEMORY_AND_DISK_SER_2)
val broadcastTable = sc.broadcast(gpsLookUpTable)


ssc.textFileStream("hdfs://localhost:9000/inputDirectory/")
  .foreachRDD { rdd =>
  //broadcastTable.value.show() // I can access broadcast value here
  if (!rdd.partitions.isEmpty) {
    val partitionedRDD = rdd.repartition(4)
    partitionedRDD.foreachPartition {
      partition =>
        println("Inside Partition")
        broadcastTable.value.show() // I cannot access broadcast value here
        partition.foreach {
          row =>
            val items = row.split("\n")
            items.foreach { item =>
              val mongoColl = MongoClient()(DB_NAME)(COLLECTION_NAME)
              val jsonObject = new JSONObject(item)
              val latitude = jsonObject.getDouble(Constants.LATITUDE)
              val longitude = jsonObject.getDouble(Constants.LONGITUDE)

              // The broadcast value is not being shown here
              // However, there is no error shown
              // I cannot insert the value into Mongo DB
              val selectedRow = broadcastTable.value
                .filter("geoCode LIKE '" + GeoHash.subString(latitude, longitude) + "%'")
                .withColumn("Distance", calculateDistance(col("Lat"), col("Lon")))
                .orderBy("Distance")
                .select(Constants.TRACK_KM, Constants.TRACK_NAME).take(1)
              if (selectedRow.length != 0) {
                jsonObject.put(Constants.TRACK_KM, selectedRow(0).get(0))
                jsonObject.put(Constants.TRACK_NAME, selectedRow(0).get(1))
              }
              else {
                jsonObject.put(Constants.TRACK_KM, "NULL")
                jsonObject.put(Constants.TRACK_NAME, "NULL")
              }
              val record = JSON.parse(jsonObject.toString()).asInstanceOf[DBObject]
              mongoColl.insert(record)
            }
        }
    }
  }
}
sys.addShutdownHook {
  ssc.stop(true, true)
}

ssc.start()
ssc.awaitTermination()
}
}
对象处理流{
val calculateInstance=udf{
(lat:String,lon:String)=>
GeoHash.getDistance(lat.toDouble,lon.toDouble)}
val DB_NAME=“IRT”
val集合\u NAME=“传感器数据”
val记录=数组[字符串]()
def main(参数:数组[字符串]):单位={
如果(参数长度<0){
System.err.println(“用法:ProcessMicroBatchStreams”)
系统出口(1)
}
val conf=new SparkConf()
.setMaster(“本地[*]”)
.setAppName(此.getClass.getCanonicalName)
.set(“spark.hadoop.validateOutputSpecs”、“false”)
/*.set(“spark.executor.instances”、“3”)
.set(“spark.executor.memory”,“18g”)
.set(“spark.executor.cores”、“9”)
.set(“spark.task.cpu”,“1”)
.set(“spark.driver.memory”,“10g”)*/
val sc=新的SparkContext(配置)
val ssc=新的StreamingContext(sc,秒(60))
val sqc=新的SQLContext(sc)
val gpsLookUpTable=MapInput.cacheMappingTables(sc,sqc).persist(StorageLevel.MEMORY_和_DISK_seru_2)
val broadcastTable=sc.broadcast(gpsLookUpTable)
ssc.textFileStream(“hdfs://localhost:9000/inputDirectory/")
.foreachRDD{rdd=>
//broadcastTable.value.show()//我可以在这里访问广播值
如果(!rdd.partitions.isEmpty){
val partitionedRDD=rdd.重新分区(4)
partitioneddd.foreachPartition{
分区=>
println(“内部分区”)
broadcastTable.value.show()//我无法在此处访问广播值
分区。foreach{
行=>
val项目=行分割(“\n”)
items.foreach{item=>
val mongoColl=MongoClient()(数据库名称)(集合名称)
val jsonObject=新jsonObject(项)
val latitude=jsonObject.getDouble(常数.纬度)
val longitude=jsonObject.getDouble(Constants.longitude)
//此处未显示广播值
//但是,没有显示任何错误
//我无法将该值插入Mongo DB
val selectedRow=broadcastTable.value
.filter(“类似于“”的地理代码+GeoHash.subString(纬度、经度)+“%”)
.带列(“距离”、计算距离(列(“纬度”)、列(“经度”))
.orderBy(“距离”)
.选择(常数.TRACK\u KM,常数.TRACK\u NAME)。取(1)
如果(selectedRow.length!=0){
jsonObject.put(Constants.TRACK_KM,selectedRow(0.get(0))
jsonObject.put(Constants.TRACK_NAME,selectedRow(0.get(1))
}
否则{
jsonObject.put(Constants.TRACK_KM,“NULL”)
jsonObject.put(Constants.TRACK_NAME,“NULL”)
}
val record=JSON.parse(jsonObject.toString()).asInstanceOf[DBObject]
mongoColl.insert(记录)
}
}
}
}
}
sys.addShutdownHook{
ssc.停止(正确,正确)
}
ssc.start()
ssc.终止协议()
}
}

看起来您正在尝试广播RDD。试着这样做:

broadCastVal = gpsLookUpTable.collect
broadCastTable = sc.broadcast(broadCastVal)

你应该能够得到你期望的值。

我不完全确定这一点,但在两次遭遇之后,我写下了这个答案。我可以广播RDD,但无法访问该值。如果我创建一个列表或树形图,我也能够广播和检索该值。我不知道为什么。尽管如此,我还没有发现任何地方写过我们不能广播RDD。

MapInput来自哪里,以及
gpsLookUpTable的类型是什么?我有一个文件gpsLookUpTable.json,它是一个查找表。MapInput Function使用该表的SparkSQL返回数据帧。函数是:
def cacheMappingTables(sc:SparkContext,sqlContext:sqlContext):DataFrame={val allRows=sc.textFile('hdfs://localhost:9000/supportFiles/GeoHashLookUpTable)sqlContext.read.json(allRows.RegisterEmptable(“GeoHashLookUpTable”)val-gpsLookUpTable=sqlContext.sql(“从GeoHashLookUpTable中选择Lat、Lon、geoCode、TrackKM、TrackCode、TrackName、SubTrackCode、SubTrackName”)返回gpsLookUpTable}
@Patrick McGloin您的见解please@Erik施密格请说出您的见解我仍然停留在这里。有人知道我如何并行处理并访问广播变量的答案吗?我正在尝试对广播值执行一些选择操作
val selectedRow=broadcastTable.value.filter(“地理编码,如“'+GeoHash.subString(纬度、经度)+“%”。带列(“距离”、计算距离(col(“Lat”)、col(“Lon”)))。排序依据(“距离”)。选择(常量.TRACK_KM、常量.TRACK_NAME)。取(1)
在代码中,使用collect returns数组,我将无法执行此操作。我想知道是什么原因导致了此问题。在重新分区之前,我可以使用相同的方法访问值。有什么想法吗?我在spark shell上瞎搞了一番,发现了这个问题。当使用broadCastTable.value时,它会返回一个内存地址,然后scala计算出如何打印它。您可以通过在代码
println(broadCastTable.value)
中添加以下行来检查这一点。如果您尝试获取广播变量的某个索引,它将返回值
println(broadCastTable.value[1])
不确定这有多大帮助,但希望它能将您推向正确的方向,您可以