updateStateByKey案例(Java版本)

来源:互联网 发布:廉租住房软件 编辑:程序博客网 时间:2024/06/18 01:02
package gh.spark.SparkStreaming;


import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.Optional; //注意Optional的包
import org.apache.spark.api.java.function.FlatMapFunction;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.api.java.function.PairFunction;
import org.apache.spark.streaming.Durations;
import org.apache.spark.streaming.api.java.JavaPairDStream;
import org.apache.spark.streaming.api.java.JavaReceiverInputDStream;
import org.apache.spark.streaming.api.java.JavaStreamingContext;


import scala.Tuple2;


public class UpdateStateByKeyWC {


public static void main(String[] args) throws Exception {

SparkConf conf=new SparkConf().setAppName("UpdateStateByKeyWC")
.setMaster("local[2]");
JavaStreamingContext jsc=new JavaStreamingContext(conf,Durations.seconds(5));

/** 第一点,如果要使用updateStateByKey算子,就必须设置一个checkpoint目录,开启checkpoint机制
* 这样的话才能把每个key对应的state除了在内存中有,那么也要checkpoint一份
* 因为你要长期保存一份key的state的话,那么spark streaming是要求必须用checkpoint的,
* 以便于在内存数据丢失的时候,可以从checkpoint中恢复数据
**/
// 开启checkpoint机制,很简单,只要调用jssc的checkpoint()方法,设置一个hdfs目录即可
jsc.checkpoint("hdfs://tgmaster:9000/in/chk");

JavaReceiverInputDStream<String> lines = jsc.socketTextStream("tgmaster", 9999);


JavaPairDStream<String, Integer> pairRDD = lines.flatMap(new FlatMapFunction<String, String>() {
private static final long serialVersionUID = 1L;


public Iterator<String> call(String line) throws Exception {

List<String> words = Arrays.asList(line.split(" "));
return words.iterator();
}
}).mapToPair(new PairFunction<String, String, Integer>() {
private static final long serialVersionUID = 1L;


public Tuple2<String, Integer> call(String word) throws Exception {
// TODO Auto-generated method stub
return new Tuple2<String, Integer>(word, 1);
}
});
// 到了这里,就不一样了,之前的话,是不是直接就是pairs.reduceByKey
// 然后,就可以得到每个时间段的batch对应的RDD,计算出来的单词计数
// 然后,可以打印出那个时间段的单词计数
// 但是,有个问题,你如果要统计每个单词的全局的计数呢?
// 就是说,统计出来,从程序启动开始,到现在为止,一个单词出现的次数,那么就之前的方式就不好实现
// 就必须基于redis这种缓存,或者是mysql这种db,来实现累加

// 但是,我们的updateStateByKey,就可以实现直接通过Spark维护每个单词的全局的统计次数
    //*****注意Optional的包
JavaPairDStream<String, Integer> updateStateByKeyRDD = pairRDD.updateStateByKey(new Function2<List<Integer>, Optional<Integer>, Optional<Integer>>() {


private static final long serialVersionUID = 1L;


public Optional<Integer> call(List<Integer> values, Optional<Integer> state)
throws Exception {

// 首先定义一个全局的单词计数
Integer newValue = 0;

   /**
    * 1、在新输入的内容中,没有出现,但是之前已经存在
    * 2、在新输入的内容中,第一次出现,之前不存在
    */
if(state.isPresent()) {
newValue = state.get();
}

/**
* 在新输入的内容中,又出现了,并且之前也已经存在,此时需要累加
*/
for(Integer value : values) {
newValue += value;
}

return Optional.of(newValue);  
}


});
/**到这里为止,相当于是,每个batch过来是,计算到pairs DStream,就会执行全局的updateStateByKey算子,
* updateStateByKey返回的JavaPairDStream,其实就代表了每个key的全局的计数
*/
// 将结果打印出来
updateStateByKeyRDD.print();

jsc.start();
jsc.awaitTermination();
jsc.close();
}


}
0 0
原创粉丝点击