Scala 如何使用Spark广播避免机器学习模型的序列化错误?

Scala 如何使用Spark广播避免机器学习模型的序列化错误?,scala,apache-spark,serialization,spark-streaming,Scala,Apache Spark,Serialization,Spark Streaming,我需要使用以前训练过的机器学习模型来进行预测。但是,我需要在foreachRDD中进行预测,因为输入数据vecTest通过不同的转换和if-then规则传递。为了避免序列化问题,我尝试使用广播。我的代码如下。尽管如此,我仍然得到序列化错误。欢迎任何帮助 val model = GradientBoostedTreesModel.load(sc,pathToModel) val model_sc = sc.broadcast(model) myDSTREAM.foreachRDD(rdd =&g

我需要使用以前训练过的机器学习模型来进行预测。但是,我需要在
foreachRDD
中进行预测,因为输入数据
vecTest
通过不同的转换和
if-then
规则传递。为了避免序列化问题,我尝试使用广播。我的代码如下。尽管如此,我仍然得到序列化错误。欢迎任何帮助

val model = GradientBoostedTreesModel.load(sc,pathToModel)
val model_sc = sc.broadcast(model)

myDSTREAM.foreachRDD(rdd => {
  rdd.foreachPartition({ partitionOfRecords =>
     //...
     val prediction_result = model_sc.value.predict(vecTest)
  })
})
更新:

我尝试使用Kryo序列化,但仍然没有成功

val conf = new SparkConf().setMaster(...).setAppName(...)
conf.registerKryoClasses(Array(classOf[GradientBoostedTreesModel]))
更新:

如果我运行此代码,则会出现错误(请参见下面的stacktrace):

myDSTREAM.foreachRDD(rdd=>{
foreachPartition({partitionOfRecords=>
val模型=GradientBoostedTreesModel.load(sc,pathToModel)
记录的分区。foreach(s=>{
//...
val vecTestRDD=sc.parallelize(Seq(vecTest))
val预测结果=model.predict(vecTestRDD)
})
})
})
17/03/17 13:11:00错误JobScheduler:运行作业流作业1489752660000 ms.0时出错
org.apache.spark.SparkException:任务不可序列化
位于org.apache.spark.util.ClosureCleaner$.ensureSerializable(ClosureCleaner.scala:304)
位于org.apache.spark.util.ClosureCleaner$.org$apache$spark$util$ClosureCleaner$$clean(ClosureCleaner.scala:294)
位于org.apache.spark.util.ClosureCleaner$.clean(ClosureCleaner.scala:122)
位于org.apache.spark.SparkContext.clean(SparkContext.scala:2055)
位于org.apache.spark.rdd.rdd$$anonfun$foreachPartition$1.apply(rdd.scala:919)
位于org.apache.spark.rdd.rdd$$anonfun$foreachPartition$1.apply(rdd.scala:918)
位于org.apache.spark.rdd.RDDOperationScope$.withScope(RDDOperationScope.scala:150)
位于org.apache.spark.rdd.RDDOperationScope$.withScope(RDDOperationScope.scala:111)
位于org.apache.spark.rdd.rdd.withScope(rdd.scala:316)
位于org.apache.spark.rdd.rdd.foreachPartition(rdd.scala:918)
在org.test.classifier.Predictor$$anonfun$run$2.apply上(Predictor.scala:210)
位于org.test.classifier.Predictor$$anonfun$run$2.apply(Predictor.scala:209)
在org.apache.spark.streaming.dstream.dstream$$anonfun$foreachRDD$1$$anonfun$apply$mcV$sp$3.apply(dstream.scala:661)
在org.apache.spark.streaming.dstream.dstream$$anonfun$foreachRDD$1$$anonfun$apply$mcV$sp$3.apply(dstream.scala:661)
在org.apache.spark.streaming.dstream.ForEachDStream$$anonfun$1$$anonfun$apply$mcV$sp$1.apply$mcV$sp(ForEachDStream.scala:50)
在org.apache.spark.streaming.dstream.ForEachDStream$$anonfun$1$$anonfun$apply$mcV$sp$1.apply(ForEachDStream.scala:50)
在org.apache.spark.streaming.dstream.ForEachDStream$$anonfun$1$$anonfun$apply$mcV$sp$1.apply(ForEachDStream.scala:50)
位于org.apache.spark.streaming.dstream.dstream.createRDDWithLocalProperties(dstream.scala:426)
在org.apache.spark.streaming.dstream.ForEachDStream$$anonfun$1.apply$mcV$sp(ForEachDStream.scala:49)
在org.apache.spark.streaming.dstream.ForEachDStream$$anonfun$1.apply上(ForEachDStream.scala:49)
在org.apache.spark.streaming.dstream.ForEachDStream$$anonfun$1.apply上(ForEachDStream.scala:49)
在scala.util.Try$.apply处(Try.scala:161)
位于org.apache.spark.streaming.scheduler.Job.run(Job.scala:39)
在org.apache.spark.streaming.scheduler.JobScheduler$JobHandler$$anonfun$run$1.apply$mcV$sp(JobScheduler.scala:224)
位于org.apache.spark.streaming.scheduler.JobScheduler$JobHandler$$anonfun$run$1.apply(JobScheduler.scala:224)
位于org.apache.spark.streaming.scheduler.JobScheduler$JobHandler$$anonfun$run$1.apply(JobScheduler.scala:224)
在scala.util.DynamicVariable.withValue(DynamicVariable.scala:57)中
位于org.apache.spark.streaming.scheduler.JobScheduler$JobHandler.run(JobScheduler.scala:223)
位于java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
位于java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
运行(Thread.java:745)
原因:java.io.NotSerializableException:org.test.classifier.Predictor
序列化堆栈:
-对象不可序列化(类:org.test.classifier.Predictor,值:org.test.classifier)。Predictor@26e949f7)
-字段(类:org.test.classifier.Predictor$$anonfun$run$2,名称:$outer,类型:class org.test.classifier.Predictor)
-对象(类org.test.classifier.Predictor$$anonfun$run$2,)
-字段(类:org.test.classifier.Predictor$$anonfun$run$2$$anonfun$apply$4,名称:$outer,类型:class org.test.classifier.Predictor$$anonfun$run$2)
-对象(类org.test.classifier.Predictor$$anonfun$run$2$$anonfun$apply$4,)
位于org.apache.spark.serializer.SerializationDebugger$.ImproveeException(SerializationDebugger.scala:40)
位于org.apache.spark.serializer.JavaSerializationStream.writeObject(JavaSerializer.scala:47)
位于org.apache.spark.serializer.JavaSerializerInstance.serialize(JavaSerializer.scala:101)
位于org.apache.spark.util.ClosureCleaner$.ensureSerializable(ClosureCleaner.scala:301)
更新3:

我尝试了另一种方法,但还是遇到了同样的问题:

  val model = GradientBoostedTreesModel.load(sc,mySet.value("modelAddress") + mySet.value("modelId"))
  val new_dstream = myDStream.map(session => {
    val features : Array[String] = UtilsPredictor.getFeatures()
    val parsedSession = UtilsPredictor.parseJSON(session)
    var input: String = ""
    var count: Integer = 1
    for (i <- 0 until features.length) {
      if (count < features.length) {
        input += parsedSession(features(i)) + ","
        count += 1
      }
      else {
        input += parsedSession(features(i))
      }
    }
    input = "[" + input + "]"
    val vecTest = Vectors.parse(input)
    parsedSession + ("prediction_result" -> model.predict(vecTest).toString)
  })
val model=GradientBoostedTreesModel.load(sc,mySet.value(“modeldaddress”)+mySet.value(“modelId”))
val new_dstream=myDStream.map(会话=>{
val功能:数组[String]=UtilsPredictor.getFeatures()
val parsedSession=UtilsPredictor.parseJSON(会话)
变量输入:String=“”
变量计数:整数=1
对于(i model.predict(vecTest.toString)
})

如果您想广播您的模型,那么它应该是可序列化的。广播对您没有帮助,因为它所做的只是先发制人地将模型发送到工作节点,而不是在必要时这样做。我没有尝试过这个,但是如何围绕模型创建一个可序列化的包装器(例如使用case类)并使用Json为GBM编写自己的序列化代码呢@你的想法似乎很有用。你能给我一个电话吗
  val model = GradientBoostedTreesModel.load(sc,mySet.value("modelAddress") + mySet.value("modelId"))
  val new_dstream = myDStream.map(session => {
    val features : Array[String] = UtilsPredictor.getFeatures()
    val parsedSession = UtilsPredictor.parseJSON(session)
    var input: String = ""
    var count: Integer = 1
    for (i <- 0 until features.length) {
      if (count < features.length) {
        input += parsedSession(features(i)) + ","
        count += 1
      }
      else {
        input += parsedSession(features(i))
      }
    }
    input = "[" + input + "]"
    val vecTest = Vectors.parse(input)
    parsedSession + ("prediction_result" -> model.predict(vecTest).toString)
  })