如何从spark设置和获取静态变量?

dip*_*uru 7 java apache-spark spark-streaming

我有一个班级:

public class Test {
    private static String name;

    public static String getName() {
        return name;
    }

    public static void setName(String name) {
        Test.name = name;
    }

    public static void print() {
        System.out.println(name);
    }

}
Run Code Online (Sandbox Code Playgroud)

在我的Spark驱动程序中,我正在设置这样的名称并调用print()命令:

public final class TestDriver{

    public static void main(String[] args) throws Exception {
        SparkConf sparkConf = new SparkConf().setAppName("TestApp");
        // ...
        // ...
        Test.setName("TestName")
        Test.print();
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,我得到了一个NullPointerException.如何将值传递给全局变量并使用它?

Dan*_*don 23

好的,基本上有两种方法可以将master知道的值带给执行者:

  1. 将值放入要序列化的闭包中以执行任务.这是最常见的,非常简单/优雅.样本和文档在这里.
  2. 使用数据创建广播变量.这适用于大尺寸的不可变数据,因此您希望保证它只发送一次.如果反复使用相同的数据也很好.样本和文档在这里.

在任何一种情况下都不需要使用静态变量.但是,如果您希望在执行程序VM上提供静态值,则需要执行以下操作之一:

  1. 如果值是固定的或配置在执行程序节点上可用(生活在jar内等),那么你可以有一个惰性val,保证只初始化一次.
  2. 您可以使用上述2个选项之一的代码调用mapPartitions(),然后将值存储在静态变量/对象上.mapPartitions保证每个分区只运行一次(比每行一次好多了),并且适用于这种事情(初始化数据库连接等).

希望这可以帮助!

PS:至于你的异常:我只是没有在代码示例中看到它,我的赌注是它正在其他地方发生.


编辑以获得额外的说明:懒惰的val解决方案只是Scala,没有涉及Spark ...

object MyStaticObject
{
  lazy val MyStaticValue = {
     // Call a database, read a file included in the Jar, do expensive initialization computation, etc
     4
  }
} 
Run Code Online (Sandbox Code Playgroud)

由于每个Executor都对应一个JVM,因此一旦加载了类MyStaticObject就会被初始化.该lazy关键字保证了MyStaticValue变量将只在首次初始化它实际上是要求,并从此保持其价值.


Sea*_*wen 6

驱动程序进程中的类副本不是执行程序中的副本.它们不在同一台ClassLoader甚至相同的JVM中,甚至不在同一台机器上.在驱动程序上设置静态变量对其他副本没有任何作用,因此您可以远程找到它.