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

Posted

技术标签:

【中文标题】Spark 作业中的 Scala 成员字段可见性【英文标题】:Scala member field visibility in Spark jobs 【发布时间】:2015-05-21 21:25:29 【问题描述】:

我有一个这样定义的 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 )
  

我将它提交到一个 YARN 集群,如下所示:

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)

关于字段、范围、可见性、火花提交、对象和单例等等,我需要了解什么,才能理解为什么会发生这种情况?如果我基本上希望将变量定义为getData 方法可见的“常量”,我应该怎么做?

【问题讨论】:

这是一个序列化问题,看起来您正在使用 Kryo 作为序列化。您是否提供正确的课程注册?您是否尝试过删除 spark.serializer=org.apache.spark.serializer.KryoSerializer 行? 如果我不在我的 RDD 中使用自定义类型,是否需要任何 Kryo 注册? 我已经从作业提交中删除了 Kryo 行,但仍然出现同样的问题。 我编辑了代码以使其更简单,删除了所有 HBase 内容,因为这不是问题的一部分。 【参考方案1】:

我可能遗漏了一些东西,但我认为您不应该定义 main 方法。当您扩展 App、you inherit a main 时,您不应覆盖它,因为这实际上是调用您的 App 中的代码。

例如,你的答案中的简单类应该写成

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

【讨论】:

【参考方案2】:

想通了。这是App 造成麻烦的特征。它甚至体现在这个简单的类中:

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

# prints "(null,data)"

显然Appinherits from DelayedInit,这意味着当main()运行时,FAMILY还没有被初始化。正是我不想要的,所以我将停止使用App

【讨论】:

Ken,我想你误解了 App 的工作原理。您不扩展 App 并定义一个 main;你扩展 App 代替定义一个主。当您扩展 App 时,您继承一个 main,该 main 调用您 App 中的代码,该代码被编译器保存为函数。 你是对的。这似乎避免了初始化时间问题,我会接受你的回答。

以上是关于Spark 作业中的 Scala 成员字段可见性的主要内容,如果未能解决你的问题,请参考以下文章

forEach Spark Scala 中的错误:值选择不是 org.apache.spark.sql.Row 的成员

java.lang.NoSuchMethodError: Scala.Predef$.refArrayOps 在 Spark 作业中使用 Scala

Scala - 具有大量字段的域对象

使用数据框的子集和 spark/scala 中的两个特定字段过滤数据框 [关闭]

Spark&Hive:如何使用scala开发spark作业,并访问hive。

Spark 中用 Scala 和 java 开发有啥区别