Object 获得;java.lang.NoClassDefFoundError“;在多台机器上运行spark项目时,使用spark submit

Object 获得;java.lang.NoClassDefFoundError“;在多台机器上运行spark项目时,使用spark submit,object,apache-spark,methods,jar,noclassdeffounderror,Object,Apache Spark,Methods,Jar,Noclassdeffounderror,我是scala/spark的初学者,在将代码发送到官方环境时遇到了麻烦 简而言之,我不能将SparkSession对象放在类方法中,我不知道为什么?如果我这样做,当我在一台本地单机上运行它时就可以了,但是当我将代码打包到一个jar文件并使用spark submit在多台机器上运行它时,抛出java.lang.NoClassDefFoundError,无法初始化类XXX 比如说 当我把代码放入这样的结构中时 object Main{ def main(...){ Task.

我是scala/spark的初学者,在将代码发送到官方环境时遇到了麻烦

简而言之,我不能将SparkSession对象放在类方法中,我不知道为什么?如果我这样做,当我在一台本地单机上运行它时就可以了,但是当我将代码打包到一个jar文件并使用spark submit在多台机器上运行它时,抛出
java.lang.NoClassDefFoundError,无法初始化类XXX

比如说

当我把代码放入这样的结构中时

object Main{
    def main(...){
        Task.start
    }
} 

object Task{
    case class Data(name:String, ...)
    val spark = SparkSession.builder().appName("Task").getOrCreate()
    import spark.implicits._

    def start(){
        var ds = loadFile(path) 
        ds.map(someMethod) // it dies here!
    }

    def loadFile(path:String){
        spark.read.schema(...).json(path).as[Data]
    }

    def someMethod(d:Data):String{
        d.name
    }
}
在数据集转换函数(如map、filter…等)中放置自定义方法的每个地方,它都会给出“java.lang.NoClassDefFoundError”

但是,如果我把它重写为

object Task{
    case class Data(name:String, ...)

    def start(){
        val spark = SparkSession.builder().appName("Task").getOrCreate()
        import spark.implicits._
        var ds = loadFile(spark, path) 
        ds.map(someMethod) // it works!
    }

    def loadFile(spark:SparkSession, path:String){
        import spark.implicits._
        spark.read.schema(...).json(path).as[Data]
    }

    def someMethod(d:Data):String{
        d.name
    }
}
这很好,但这意味着我需要通过我需要的每个方法传递“spark”变量,并且我需要在方法需要时编写
import spark.implicits.\u

我认为当spark尝试在节点之间洗牌我的对象时,出现了一些问题,但我不知道确切的原因是什么,以及编写代码的正确方法是什么


谢谢

不,您不需要传递
sparkSession
对象,也不需要在所有需要的方法中导入
隐式
。您可以将
sparkSession
变量设置为函数外部的对象变量,并在所有函数中使用

下面是修改后的代码示例

object Main{
  def main(args: Array[String]): Unit = {
    Task.start()
  }
}

object Task{

  case class Data(fname:String, lname : String)
  val spark = SparkSession.builder().master("local").appName("Task").getOrCreate()

  import spark.implicits._

  def start(){
    var ds = loadFile("person.json")
    ds.map(someMethod).show()

  }

  def loadFile(path:String): Dataset[Data] = {
    spark.read.json(path).as[Data]
  }

  def someMethod(d:Data):String = {
    d.fname
  }
}

希望这有帮助

谢谢你的回复,但我不明白?它几乎与我的版本相同,该版本将为我提供java.lang.NoClassDefFoundError。所以我需要在转换后添加一些动作,比如“show()”?这没有意义?不,我需要将我的spark定义放在“start()”方法中,否则无论我是否“show()”它都会给我java.lang.NoClassDefFoundError,我不知道为什么:(与您的版本相同,但文件路径不同。我很高兴数据加载部分没有问题,因为我可以毫无问题地显示数据。问题发生在我调用map并将自定义函数放入itI时。我已经制作了一个小而干净的项目,以排除其他可能的问题。并且它只发生在我在中运行代码时。)我的AWS-EMR使用一个主节点和四个从节点,它在本地单核计算机上运行良好。有趣的是,如果我编写类似ds.map(x=>x.fname)的匿名函数,没问题。SparkSession是一个单例。您不需要通过方法签名传递它,但您可以再次使用getOrCreate并获取相同的对象。我怀疑部分问题是您正在代码的静态部分创建SparkSession。您使用的是哪种jvm?当使用此外,我将避免在同一个文件/类中定义两个对象。