文章地址:http://www.haha174.top/article/details/255473
updateStateByKey 操作可以让我们为每个key 维护一份state ,并持续不断的更新该state
1. 首先要定义一个state 可以是任意的数据类型
2. 其次要定义state 更新指定一个函数如何使用之前的state 和新值来更新
当然 对于每个出现的key 也会执行state 更新函数。
注意 updateStateByKey 操作要求开启checkPoint
下面给出java 示例和注释:
public class updateStateByKeyWorldCount {
public static void main(String[] args) throws InterruptedException {
System.setProperty("HADOOP_USER_NAME", "root");
SparkConf conf=new SparkConf().setMaster("local[2]").setAppName("updateStateByKeyWorldCount");
JavaStreamingContext jssc=new JavaStreamingContext(conf, Durations.seconds(5));
jssc.checkpoint("hdfs://192.168.1.26:8020/study/spark/checkPoint");
JavaReceiverInputDStream<String> lines=jssc.socketTextStream("192.168.1.26",9999);
JavaDStream<String> worlds=lines.flatMap(new FlatMapFunction<String, String>() {
@Override
public Iterator<String> call(String s) throws Exception {
return Arrays.asList(s.split(" ")).iterator();
}
}) ;
JavaPairDStream<String,Integer> pairs=worlds.mapToPair(new PairFunction<String, String, Integer>() {
@Override
public Tuple2<String, Integer> call(String s) throws Exception {
return new Tuple2(s,1);
}
}) ;
JavaPairDStream<String,Integer> results=pairs.updateStateByKey(new Function2<List<Integer>, Optional<Integer>, Optional<Integer>>() {
@Override
// Optional 代表值的存在状态 有可能存在有可能不存在
// 实际上对于每个单词每次batch 计算的时候都会调用这个函数
// 第一个参数 相当于这个batch 中这个key 新的值·
// 第二个参数就是key 之前的状态
public Optional<Integer> call(List<Integer> v1, Optional<Integer> v2) throws Exception {
Integer newValue=0;
//其次判断v2 是否存在
if(v2.isPresent()){
newValue=v2.get();
}
// 将本次新出现的值都加到newValue 中
for(Integer value:v1){
newValue+=value;
}
return Optional.of(newValue);
}
});
// 到这里为止 相当于的事 每个batch 过来 计算到pairsDstream 就会执行全局的updateStateByKey算子updateStateByKey 返回的JavaPairDStream
//代表每个key 的全局计数
results.print();
jssc.start();
jssc.awaitTermination();
jssc.stop();
jssc.close();
}
}
下面给出scala 示例:
object updateStateByKeyWorldCount {
def main(args: Array[String]): Unit = {
System.setProperty("HADOOP_USER_NAME", "root")
val conf = new SparkConf().setAppName("updateStateByKeyWorldCount").setMaster("local[2]")
//创建JavaStreamingContext
//该对象就类似于spark core 中的JavaSparkContext
//该对象除了接收sparkConf 对象之外还必须接收一个batch interval 参数,就是说 每收集多长时间的数据,划分一个batch ,进行处理
//这里设置一秒
val jssc = new StreamingContext(conf, Durations.seconds(5))
//首先创建输入DStream 代表一个数据源 (比如kafka ,socket) 来持续不断的实时数据流
//调用JavaStreamingContext 的socketTextStream 方法可以创建一个数据源为socket 的网路端口的数据源
jssc.checkpoint("hdfs://192.168.1.26:8020/study/spark/checkPoint")
val lines = jssc.socketTextStream("192.168.1.26", 9999)
val worlds = lines.flatMap(line=>line.split(" "))
val pairs = worlds.map(pair=>(pair,1))
val results= pairs.updateStateByKey((values:Seq[Int],state:Option[Int])=>{
var newValue:Int=state.getOrElse(0)
for(value<-values){
newValue+= value
}
Option(newValue)
})
results.print()
jssc.start()
jssc.awaitTermination()
}
}