Spark作业中的Scala成员字段可见性

Spark作业中的Scala成员字段可见性,scala,initialization,apache-spark,visibility,Scala,Initialization,Apache Spark,Visibility,我有一个Scala类,我这样定义: import org.apache.spark.{SparkConf, SparkContext} object TestObject extends App{ val FAMILY = "data".toUpperCase override def main(args: Array[String]) { val sc = new SparkContext(new SparkConf()) sc.parallelize(1 to

我有一个Scala类,我这样定义:

import org.apache.spark.{SparkConf, SparkContext}

object TestObject extends App{
  val FAMILY = "data".toUpperCase

  override def main(args: Array[String]) {
    val sc = new SparkContext(new SparkConf())

    sc.parallelize(1 to 10)
      .map(getData)
      .saveAsTextFile("my_output")
  }

  def getData(i: Int) = {
    ( i, FAMILY, "data".toUpperCase )
  }
}
我将其提交给一个纱线簇,如下所示:

HADOOP_CONF_DIR=/etc/hadoop/conf spark-submit \
    --conf spark.hadoop.validateOutputSpecs=false \
    --conf spark.yarn.jar=hdfs:/apps/local/spark-assembly-1.2.1-hadoop2.4.0.jar \
    --deploy-mode=cluster \
    --master=yarn \
    --class=TestObject \
    target/scala-2.11/myjar-assembly-1.1.jar
意外地,输出如下所示,表明
getData
方法无法看到
FAMILY
的值:

(1,null,DATA)
(2,null,DATA)
(3,null,DATA)
(4,null,DATA)
(5,null,DATA)
(6,null,DATA)
(7,null,DATA)
(8,null,DATA)
(9,null,DATA)
(10,null,DATA)

关于字段、范围、可见性、spark提交、对象、单例等等,我需要了解什么,才能理解为什么会发生这种情况?如果我基本上希望变量定义为对
getData
方法可见的“常量”,那么我应该怎么做呢。这是导致麻烦的
应用程序
特性。它甚至在这个简单的类中也表现出来:

object TestObject extends App {
  val FAMILY = "data"
  override def main(args: Array[String]) = println(FAMILY, "data")
}
# prints "(null,data)"

显然
App
,这意味着当
main()
运行时,
FAMILY
尚未初始化。正是我不想要的,所以我要停止使用
App

我可能遗漏了什么,但我认为您不应该定义
main
方法。当您扩展
应用程序时,您不应该覆盖它,因为这是实际调用
应用程序中的代码的原因

例如,答案中的简单类应该是

object TestObject extends App {
  val FAMILY = "data"
  println(FAMILY, "data")
}

这是一个序列化问题,看起来您正在使用Kryo作为序列化。您是否提供了正确的班级注册?你试过删除
spark.serializer=org.apache.spark.serializer.KryoSerializer
行吗?如果我没有在RDD中使用自定义类型,我需要任何Kryo注册吗?我已经从作业提交中删除了Kryo行,同样的问题仍然会发生。我编辑了代码,使它更简单,删除所有HBase内容,因为这不是问题的一部分。肯,我想你误解了应用程序的工作原理。您不扩展应用程序,还定义了一个主应用程序;您可以扩展应用程序而不是定义主应用程序。扩展应用程序时,您继承了一个main,该main调用应用程序中的代码,该代码被编译器保存为函数。您是对的。这似乎避免了初始化时间的问题,我接受你的答案。