我想在foreachPartition
中使用SparkContext和SQLContext,但由于序列化错误而无法执行此操作。我知道这两个对象都不是可序列化的,但我认为foreachPartition
是在master上执行的,其中Spark Context和SQLContext都可用。
符号:
`msg -> Map[String,String]`
`result -> Iterable[Seq[Row]]`
这是我当前的代码(UtilsDM是extends Serializable
)的对象。失败的代码部分从val schema =...
开始,我想将result
写入DataFrame
,然后将其保存到Parquet。也许我组织代码的方式效率低下,那么我想在此提出您的建议。感谢。
// Here I am creating df from parquet file on S3
val exists = FileSystem.get(new URI("s3n://" + bucketNameCode), sc.hadoopConfiguration).exists(new Path("s3n://" + bucketNameCode + "/" + pathToSentMessages))
var df: DataFrame = null
if (exists) {
df = sqlContext
.read.parquet("s3n://bucket/pathToParquetFile")
}
UtilsDM.setDF(df)
// Here I process myDStream
myDStream.foreachRDD(rdd => {
rdd.foreachPartition{iter =>
val r = new RedisClient(UtilsDM.getHost, UtilsDM.getPort)
val producer = UtilsDM.createProducer
var df = UtilsDM.getDF
val result = iter.map{ msg =>
// ...
Seq(msg("key"),msg("value"))
}
// HERE I WANT TO WRITE result TO S3, BUT IT FAILS
val schema = StructType(
StructField("key", StringType, true) ::
StructField("value", StringType, true)
result.foreach { row =>
val rdd = sc.makeRDD(row)
val df2 = sqlContext.createDataFrame(rdd, schema)
// If the parquet file is not created, then create it
var df_final: DataFrame = null
if (df != null) {
df_final = df.unionAll(df2)
} else {
df_final = df2
}
df_final.write.parquet("s3n://bucket/pathToSentMessages)
}
}
})
编辑:
我正在使用Spark 1.6.2和Scala 2.10.6。
答案 0 :(得分:6)
这是不可能的。 SparkContext
,SQLContext
和SparkSession
只能在驱动程序上使用。您可以在foreachRDD
的顶级使用sqlContext:
myDStream.foreachRDD(rdd => {
val df = sqlContext.createDataFrame(rdd, schema)
...
})
你无法在转型/行动中使用它:
myDStream.foreachRDD(rdd => {
rdd.foreach {
val df = sqlContext.createDataFrame(...)
...
}
})
您可能需要等效于:
myDStream.foreachRDD(rdd => {
val foo = rdd.mapPartitions(iter => doSomethingWithRedisClient(iter))
val df = sqlContext.createDataFrame(foo, schema)
df.write.parquet("s3n://bucket/pathToSentMessages)
})
答案 1 :(得分:1)
我发现在循环中使用现有的SparkContext(假设我已事先创建了一个sparkContext sc),即
。// this works
stream.foreachRDD( _ => {
// update rdd
.... = SparkContext.getOrCreate().parallelize(...)
})
// this doesn't work - throws a SparkContext not serializable error
stream.foreachRDD( _ => {
// update rdd
.... = sc.parallelize(...)
})