在Spark Streaming中,每次收到新消息时,都会使用模型根据此新消息预测某个消息。但随着时间的推移,模型可以由于某种原因而改变,所以我想在新消息进入时重新加载模型。我的代码看起来像这样
def loadingModel(@transient sc:SparkContext)={
val model=LogisticRegressionModel.load(sc, "/home/zefu/BIA800/LRModel")
model
}
var error=0.0
var size=0.0
implicit def bool2int(b:Boolean) = if (b) 1 else 0
def updateState(batchTime: Time, key: String, value: Option[String], state: State[Array[Double]]): Option[(String, Double,Double)] = {
val model=loadingModel(sc)
val parts = value.getOrElse("0,0,0,0").split(",").map { _.toDouble }
val pairs = LabeledPoint(parts(0), Vectors.dense(parts.tail))
val prediction = model.predict(pairs.features)
val wrong= prediction != pairs.label
error = state.getOption().getOrElse(Array(0.0,0.0))(0) + 1.0*(wrong:Int)
size=state.getOption().getOrElse(Array(0.0,0.0))(1) + 1.0
val output = (key, error,size)
state.update(Array(error,size))
Some(output)
}
val stateSpec = StateSpec.function(updateState _)
.numPartitions(1)
setupLogging()
val kafkaParams = Map("metadata.broker.list" -> "localhost:9092")
val topics = List("test").toSet
val lines = KafkaUtils.createDirectStream[String, String, StringDecoder, StringDecoder](
ssc, kafkaParams, topics).mapWithState(stateSpec)
当我运行此代码时,会出现这样的异常
Exception in thread "main" org.apache.spark.SparkException: Task not serializable
如果您需要更多信息,请告诉我们。 谢谢!
答案 0 :(得分:0)
当在DStream函数中使用模型时,spark似乎序列化上下文对象(因为模型的加载函数使用sc),并且它失败,因为上下文对象不可序列化。一种解决方法是将DStream转换为RDD,收集结果,然后在驱动程序中运行模型预测/评分。
使用netcat实用程序来模拟流,尝试使用以下代码将DStream转换为RDD,它可以工作。看看它是否有帮助。
val ssc = new StreamingContext(sc,Seconds(10))
val lines = ssc.socketTextStream("xxx", 9998)
val linedstream = lines.map(lineRDD => Vectors.dense(lineRDD.split(" ").map(_.toDouble)) )
val logisModel = LogisticRegressionModel.load(sc, /path/LR_Model")
linedstream.foreachRDD( rdd => {
for(item <- rdd.collect().toArray) {
val predictedVal = logisModel.predict(item)
println(predictedVal + "|" + item);
}
})
理解收集在此处不可扩展,但如果您认为您的流式传输消息的数量较少,则可能是一个选项。这是我在Spark 1.4.0中看到的可能,更高版本可能有一个修复。如果它有用,请看这个