如何在 Spark 2.4 中加载自定义转换器

我正在尝试在 Spark 2.4.0 中创建一个自定义转换器。保存它工作正常。但是,当我尝试加载它时,出现以下错误:


java.lang.NoSuchMethodException: TestTransformer.<init>(java.lang.String)

  at java.lang.Class.getConstructor0(Class.java:3082)

  at java.lang.Class.getConstructor(Class.java:1825)

  at org.apache.spark.ml.util.DefaultParamsReader.load(ReadWrite.scala:496)

  at org.apache.spark.ml.util.MLReadable$class.load(ReadWrite.scala:380)

  at TestTransformer$.load(<console>:40)

  ... 31 elided

这向我表明它找不到我的变压器的构造函数,这对我来说真的没有意义。


MCVE:


import org.apache.spark.sql.{Dataset, DataFrame}

import org.apache.spark.sql.types.{StructType}

import org.apache.spark.ml.Transformer

import org.apache.spark.ml.param.ParamMap

import org.apache.spark.ml.util.{DefaultParamsReadable, DefaultParamsWritable, Identifiable}


class TestTransformer(override val uid: String) extends Transformer with DefaultParamsWritable{


    def this() = this(Identifiable.randomUID("TestTransformer"))


    override def transform(df: Dataset[_]): DataFrame = {

        val columns = df.columns

        df.select(columns.head, columns.tail: _*)

    }


    override def transformSchema(schema: StructType): StructType = {

        schema

    }


    override def copy(extra: ParamMap): TestTransformer = defaultCopy[TestTransformer](extra)

}


object TestTransformer extends DefaultParamsReadable[TestTransformer]{


    override def load(path: String): TestTransformer = super.load(path)


}


val transformer = new TestTransformer("test")


transformer.write.overwrite().save("test_transformer")

TestTransformer.load("test_transformer")

运行这个(我使用的是 Jupyter notebook)会导致上述错误。我尝试将其编译为 .jar 文件并将其运行,没有任何区别。


如何制作可以保存和加载的自定义 Spark 转换器?


慕的地6264312
浏览 150回答 1
1回答

翻翻过去那场雪

我可以在 spark-shell 中重现您的问题。试图找到我调查的问题的根源DefaultParamsReadable和DefaultParamsReader来源,我可以看到他们利用 Java 反射。https://github.com/apache/spark/blob/v2.4.0/mllib/src/main/scala/org/apache/spark/ml/util/ReadWrite.scala第 495-496 行val&nbsp;instance&nbsp;= &nbsp;&nbsp;&nbsp;&nbsp;cls.getConstructor(classOf[String]).newInstance(metadata.uid).asInstanceOf[Params]我认为 scala REPL 和 Java 反射不是好朋友。如果您运行此代码段(在您的代码之后):new&nbsp;TestTransformer().getClass.getConstructors你会得到以下输出:res1:&nbsp;Array[java.lang.reflect.Constructor[_]]&nbsp;=&nbsp;Array(public&nbsp;TestTransformer($iw),&nbsp;public&nbsp;TestTransformer($iw,java.lang.String))是真的!TestTransformer.<init>(java.lang.String)不存在。我找到了2个解决方法,用 sbt 编译你的代码并创建一个 jar,然后包含在 spark-shell 中:require,对我有用(你提到你尝试了一个 jar,但我不知道如何)将代码粘贴到 spark-shell 中:paste -raw,效果也很好。我想-raw可以防止 REPL 对您的课程进行恶作剧。请参阅:https ://docs.scala-lang.org/overviews/repl/overview.html我不确定如何将其中的任何一个调整到 Jupyter,但我希望这些信息对你有用。注意:我实际上在 spark 2.4.1 中使用了 spark-shell
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java