JavaStatefulNetworkWordCount

331 阅读2分钟

这次的代码是基于第一次简单的单词统计演化而来,新加入的功能从类名中可以看出,即stateful(有状态的)---可以记录历史输入的单词数据,这就是所谓的有状态吧。 除此之外要注意:这里使用的仍是netcat开启端口进行数据源的读取。这里有几个概念:数据源、接收器(Receiver)。

  1. 未来数据源可能来自文件系统如HDFS、kafka、flume,都要做相应的配置。
  2. 接收器也存在自定义的情况,但如从文件系统直接读取可不需要接收器,其他的情况内核cpu个数要大于接收器个数,否则可能出现接受数据却不处理数据的现象。
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.function.Function3;
import org.apache.spark.streaming.Durations;
import org.apache.spark.api.java.Optional;
import org.apache.spark.streaming.State;
import org.apache.spark.streaming.StateSpec;
import org.apache.spark.streaming.api.java.*;
import scala.Tuple2;

import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;

/**
 * Created by Chailx on 2019/9/26.
 */
public class JavaStatefulNetworkWordCount {
    private static final Pattern SPACE = Pattern.compile(" ");

    public static void main(String[] args) throws Exception{
        SparkConf conf = new SparkConf().setMaster("local[2]").setAppName("JavaStatefulNetworkWordCount");
        JavaStreamingContext jssc = new JavaStreamingContext(conf, Durations.seconds(5));
        jssc.checkpoint(".");
//
//        初始化RDD  with mapWithState
        @SuppressWarnings("unchecked")
        List<Tuple2<String, Integer>>tuples = Arrays.asList(new Tuple2<>("hello",1),new Tuple2<>("world",1));
        JavaPairRDD<String ,Integer>initialRDD = jssc.sparkContext().parallelizePairs(tuples);

        JavaReceiverInputDStream<String> lines = jssc.socketTextStream("localhost",9999);

        JavaDStream<String> words = lines.flatMap(x ->Arrays.asList(SPACE.split(x)).iterator());

        JavaPairDStream<String,Integer>wordsDstream = words.mapToPair(s -> new Tuple2<>(s,1));

Function3是spark中的一个API。代码最上端导入了包含它的包import org.apache.spark.api.java.function.Function3,这里使用了lambda语法 word,one,state属于传入参数,在spark streaming官方文档中查找相应的方法,如stata.exists(),state.get(),state.update(),使用这些方法来构造业务逻辑。之后将此函数作为参数,根据官方文档中对StateSpet的描述,见下图

spark streaming API文档

        //更新累加功能(cumulative count)
        Function3<String,Optional<Integer>,State<Integer>,Tuple2<String,Integer>>mappingFunc =
                (word,one,state)->{
            int sum = one.orElse(0)+(state.exists()?state.get():0);
            Tuple2<String,Integer> output = new Tuple2<>(word,sum);
            state.update(sum);
            return output;
        };

        //Dstream由获取累积计数组成,该累积计数在每个批次中都会更新
        JavaMapWithStateDStream<String ,Integer,Integer,Tuple2<String,Integer>> stateDstream =
                wordsDstream.mapWithState(StateSpec.function(mappingFunc).initialState(initialRDD));
        stateDstream.print();
        jssc.start();
        jssc.awaitTermination();
    }
}

由于spark源码由scala编写,这里目前便没有下载源码,只对抽象接口、方法进行查阅文档了解。

参考

  1. lambda语法官方文档
  2. onjava8中文版lambda语法
  3. 官方示例代码
  4. 官方API文档