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");
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();
}
}
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();
}
}