Spark变量访问总结

Spark程序在变量的访问方式上与传统的java程序有一些不同,导致了传值和结果上的差异。本文通过一组实验来分析Spark对各种形式变量的处理方式。

        下面这个简单的小程序创建了
- 静态变量staticVariable静态广播变量staticBroadcast静态累加器staticAccumulator
- 成员变量objectVariable成员广播变量objectBroadcast成员累加器objectAccumulator
- 局部变量localVariable局部广播变量localBroadcast局部累加器localAccumulator
共计9种变量,在函数中对字符串数据修改了两次数值(“banana”和“cat”)、在flatMap函数中对累加器的值进行累加。

/**
 * Created by Alex on 2016/9/25.
 */
public class TestSharedVariable implements Serializable {
    private static Logger logger = LoggerFactory.getLogger(TestSharedVariable.class);
    private static String staticVariable = "apple";
//    private static Broadcast<String> staticBroadcast;  //java.lang.NullPointerException
//    private static Accumulator<Integer> staticAccumulator;

    private String objectVariable = "apple";
    private Broadcast<String> objectBroadcast;
    private Accumulator<Integer> objectAccumulator;


    public void testVariables(JavaSparkContext sc) throws Exception {
        staticVariable = "banana";
//        staticBroadcast = sc.broadcast("banana");
//        staticAccumulator = sc.intAccumulator(0);

        objectVariable = "banana";
        objectBroadcast = sc.broadcast("banana");
        objectAccumulator = sc.intAccumulator(0);

        String localVariable = "banana";
        accessVariables(sc, localVariable);

        staticVariable = "cat";
//        staticBroadcast = sc.broadcast("cat");
        objectVariable = "cat";
        objectBroadcast = sc.broadcast("cat");
        localVariable = "cat";
        accessVariables(sc, localVariable);
    }

    public void accessVariables(JavaSparkContext sc, final String localVariable) throws Exception {
        final Broadcast<String> localBroadcast = sc.broadcast(localVariable);
        final Accumulator<Integer> localAccumulator = sc.intAccumulator(0);

        List<String> list = Arrays.asList("machine learning", "deep learning", "graphic model");
        JavaRDD<String> rddx = sc.parallelize(list).flatMap(new FlatMapFunction<String, String>() {

            @Override
            public Iterable<String> call(String s) throws Exception {
                List<String> list = new ArrayList<String>();

                if (s.equalsIgnoreCase("machine learning")) {
                    list.add("staticVariable:" + staticVariable);
                    list.add("objectVariable:" + objectVariable);
                    list.add("objectBroadcast:" + objectBroadcast.getValue());
                    list.add("localVariable:" + localVariable);
                    list.add("localBroadcast:" + localBroadcast.getValue());
                }

//                staticAccumulator.add(1);
                objectAccumulator.add(1);
                localAccumulator.add(1);

                return list;
            }
        });


        String desPath = "learn" + localVariable;
        HdfsOperate.deleteIfExist(desPath);
        HdfsOperate.openHdfsFile(desPath);
        List<String> resultList = rddx.collect();
        for (String str : resultList) {
            HdfsOperate.writeString(str);
        }
        HdfsOperate.writeString("objectAccumulator:" + objectAccumulator.value());
        HdfsOperate.writeString("localAccumulator:" + localAccumulator.value());
        HdfsOperate.closeHdfsFile();
    }

}

最终得到两个文件:learnbanana、learncat
learnbanana的内容:

taticVariable:apple
objectVariable:banana
objectBroadcast:banana
localVariable:banana
localBroadcast:banana
objectAccumulator:3
localAccumulator:3

learncat的内容:

staticVariable:apple
objectVariable:cat
objectBroadcast:cat
localVariable:cat
localBroadcast:cat
objectAccumulator:6
localAccumulator:3                    
  1. 静态广播变量staticBroadcast静态累加器staticAccumulator在运行过程中会引发异常:
    java.lang.NullPointerException,所以在运行过程中需要注释掉。这点和普通的java函数有较大差别。另外可以看到静态变量staticVariable初始化之后无法在函数中改变它的值。

  2. 成员变量objectVariable成员广播变量objectBroadcast成员累加器objectAccumulator局部变量localVariable局部广播变量localBroadcast局部累加器localAccumulator都在程序中正常修改得到了我们想要的值。

  3. 需要注意的是局部变量局部广播变量局部累加器这三种变量由于需要在inner class中访问,需要被定义成final形式,但不影响其正常使用,可以看到局部累加器还是正确的增加了值。

小小总结一下,在使用Spark编程时如果要对变量进行访问和操作尽量使用成员类型变量局部类型变量。另外普通变量和广播变量之间的区别主要在于广播变量在处理过程中是经过优化的,可以减少不必要的资源浪费,一般size较小的变量不需要用Broadcast,详细的解释请参考文章:http://g-chi.github.io/2015/10/21/Spark-why-use-broadcast-variables/

HdfsOperate类是使用hadoop的FileSystem接口对HDFS文件进行操作,完整代码如下:

/**
 * Created by Alex on 2016/8/30.
 */
public class HdfsOperate implements Serializable{

    private static Logger logger = LoggerFactory.getLogger(HdfsOperate.class);
    private static Configuration conf = new Configuration();
    private static BufferedWriter writer = null;

    public static boolean isExist(String path) {
        try {
            FileSystem fileSystem = FileSystem.get(conf);
            Path path1 = new Path(path);
            if (fileSystem.exists(path1)) {
                return true;
            }
        } catch (Exception e) {
            logger.error("[HdfsOperate]>>>isExist error", e);
        }
        return false;
    }

    public static void deleteIfExist(String path) {
        try {
            FileSystem fileSystem = FileSystem.get(conf);
            Path path1 = new Path(path);
            if (fileSystem.exists(path1)) {
                fileSystem.delete(path1, true);
            }
        } catch (Exception e) {
            logger.error("[HdfsOperate]>>>deleteHdfsFile error", e);
        }
    }

    public static void openHdfsFile(String path) throws Exception {
        FileSystem fs = FileSystem.get(URI.create(path),conf);
        writer = new BufferedWriter(new OutputStreamWriter(fs.create(new Path(path))));
        if(null!=writer){
            logger.info("[HdfsOperate]>> initialize writer succeed!");
        }
    }

    public static void writeString(String line) {
        try {
            writer.write(line + "\n");
        }catch(Exception e){
            logger.error("[HdfsOperate]>> writer a line error:"  ,  e);
        }
    }

    public static void closeHdfsFile() {
        try {
            if (null != writer) {
                writer.close();
                logger.info("[HdfsOperate]>> closeHdfsFile close writer succeed!");
            }
            else{
                logger.error("[HdfsOperate]>> closeHdfsFile writer is null");
            }
        }catch(Exception e){
            logger.error("[HdfsOperate]>> closeHdfsFile close hdfs error:" + e);
        }
    }

    public static void main(String[] args) {

    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 动态广播变量Spark Streaming非常有用的功能。它可以让我们在流处理过程动态地更新广播变量的值,从而提高程序的性能和灵活性。 在Spark Streaming,我们可以使用SparkContext的broadcast方法来创建广播变量。然后,我们可以在DStream的foreachRDD方法使用广播变量来进行一些计算。 当我们需要动态地更新广播变量的值时,我们可以使用Spark Streaming的transform方法。这个方法可以让我们在DStream使用任意的RDD转换操作,包括更新广播变量的值。 例如,我们可以使用transform方法来读取一个外部的配置文件,并将其转换为一个广播变量。然后,我们可以在DStream的foreachRDD方法使用这个广播变量来进行一些计算。当配置文件发生变化时,我们可以重新读取它,并使用transform方法来更新广播变量的值。 总之,动态广播变量Spark Streaming非常有用的功能,可以帮助我们提高程序的性能和灵活性。 ### 回答2: Spark Streaming的动态广播变量允许我们将一个可变的变量发送到Spark集群的每个节点上,并在每个节点上更新它。这使得我们能够在流数据处理过程共享和更新全局状态。 动态广播变量的使用步骤如下: 1. 创建一个广播变量:使用SparkContext的broadcast方法将一个可变的变量广播到整个集群。例如,可以将一个关键字列表广播Spark Streaming的每个节点上。 2. 在转换操作使用广播变量:在Spark Streaming的转换操作可以通过使用广播变量的value属性来访问广播变量的值。例如,在DStream的foreachRDD操作可以访问广播变量并执行与广播变量相关的计算。 3. 更新广播变量:通过在driver程序修改广播变量的值,然后使用新值再次调用广播方法来更新广播变量的内容。这样,新值将在下一次广播时传播到集群的每个节点。 使用动态广播变量的好处是可以将一些全局状态共享到整个Spark Streaming应用程序,而无需将其传递给每个节点。这样可以减少网络传输的开销,并提高应用程序的性能。 总结起来,动态广播变量Spark Streaming管理全局状态的一个强大工具。它可以实现在流数据处理过程对全局状态进行共享和更新,从而提高应用程序的性能和效率。 ### 回答3: Spark Streaming的动态广播变量是一种在Spark Streaming作业共享变量的机制。它可以用于将某个变量广播给所有的工作节点,这样每个节点都可以在本地访问变量而不需要通过网络传输。动态广播变量在一些需要频繁更新的场景特别有用。 在Spark Streaming,要使用动态广播变量,需要首先创建一个Broadcast变量,并通过前端驱动程序将其广播到所有工作节点。然后,在每个工作节点的任务,可以直接引用该变量而不需要序列化和传输。 动态广播变量的使用步骤如下: 1. 在Spark Streaming应用程序的驱动程序,通过创建一个共享变量Broadcast来定义需要广播变量。 2. 使用Spark Streaming的dstream.foreachRDD方法迭代每一个RDD。 3. 在每一个RDD的foreachPartition方法内,通过调用Broadcast.value方法访问广播变量。 这样,每个工作节点都可以在本地获取广播变量,而无需将变量从驱动程序传输到工作节点。 动态广播变量Spark Streaming的应用场景非常广泛,例如在进行实时机器学习或实时数据分析时,可以使用动态广播变量来保存模型参数或预定义的规则等,以便在每个工作节点上进行使用,提高计算的效率和性能。 总的来说,Spark Streaming动态广播变量的使用可以帮助我们在作业共享变量,并且在处理实时数据时提高作业的效率和性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值