1.代码
SparkConf conf = new SparkConf().setMaster("local[2]").setAppName("UpdateStateByKeyDemo");
JavaStreamingContext jsc = new JavaStreamingContext(conf, Durations.seconds(5));
//报错解决办法做checkpoint,开启checkpoint机制,把checkpoint中的数据放在这里设置的目录中,
//生产环境下一般放在HDFS中
jsc.checkpoint("/checkPoint");
JavaReceiverInputDStream lines = jsc.socketTextStream("master", 9999);
JavaDStream<String> words = lines.flatMap(new FlatMapFunction<String, String>() { //如果是Scala,由于SAM转换,所以可以写成val words = lines.flatMap { line => line.split(" ")}
@Override
public Iterable<String> call(String line) throws Exception {
return Arrays.asList(line.split(" "));
}
});
JavaPairDStream<String, Integer> pairs = words.mapToPair(new PairFunction<String, String, Integer>() {
@Override
public Tuple2<String, Integer> call(String word) throws Exception {
return new Tuple2<String, Integer>(word, 1);
}
});
//关键方法updateStateByKey,其中有关于状态的方法实现。
//注意此处的optionnals一定要导入com.google.common.base.Optional;
/*在这里是通过updateStateByKey来以Batch Interval为单位来对历史状态进行更新,
* 这是功能上的一个非常大的改进,否则的话需要完成同样的目的,就可能需要把数据保存在Redis、
* Tagyon或者HDFS或者HBase或者数据库中来不断的完成同样一个key的State更新,如果你对性能有极为苛刻的要求,
* 且数据量特别大的话,可以考虑把数据放在分布式的Redis或者Tachyon内存文件系统中;
* 当然从Spark1.6.x开始可以尝试使用mapWithState,Spark2.X后mapWithState应该非常稳定了。*/
JavaPairDStream<String, Integer> wordsCount = pairs.updateStateByKey(new Function2<List<Integer>, Optional<Integer>, Optional<Integer>>() { //对相同的Key,进行Value的累计(包括Local和Reducer级别同时Reduce)
@Override
public Optional<Integer> call(List<Integer> values, Optional<Integer> state) throws Exception {
Integer updatedValue = 0 ;
if(state.isPresent()){
updatedValue = state.get();
}
for(Integer value: values){
updatedValue += value;
}
return Optional.of(updatedValue);
}
});
wordsCount.print();