一、前述

今天分享一篇SparkStreaming常用的算子transform和updateStateByKey。

  • 可以通过transform算子,对Dstream做RDD到RDD的任意操作。其实就是DStream的类型转换。

算子内,拿到的RDD算子外,代码是在Driver端执行的,每个batchInterval执行一次,可以做到动态改变广播变量。

  • 为SparkStreaming中每一个Key维护一份state状态,通过更新函数对该key的状态不断更新。

二、具体细节

        1、transform 是一个transformation类算子

package com.spark.sparkstreaming;

import java.util.ArrayList;
import java.util.List; import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.function.Function;
import org.apache.spark.api.java.function.PairFunction;
import org.apache.spark.api.java.function.VoidFunction;
import org.apache.spark.streaming.Durations;
import org.apache.spark.streaming.api.java.JavaDStream;
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 com.google.common.base.Optional; import scala.Tuple2;
/**
* 过滤黑名单
* transform操作
* DStream可以通过transform做RDD到RDD的任意操作。
* @author root
*
*/
public class TransformOperator {
public static void main(String[] args) {
SparkConf conf = new SparkConf();
conf.setMaster("local[2]").setAppName("transform");
JavaStreamingContext jsc = new JavaStreamingContext(conf,Durations.seconds(5)); //模拟黑名单
List<Tuple2<String,Boolean>> blackList = new ArrayList<Tuple2<String,Boolean>>();
blackList.add(new Tuple2<String,Boolean>("zhangsan",true));
//将黑名单转换成RDD
final JavaPairRDD<String, Boolean> blackNameRDD = jsc.sparkContext().parallelizePairs(blackList); //接受socket数据源
JavaReceiverInputDStream<String> nameList = jsc.socketTextStream("node5", 9999);
JavaPairDStream<String, String> pairNameList =
nameList.mapToPair(new PairFunction<String, String, String>() { /**
*这块代码在Driver端执行。
*/
private static final long serialVersionUID = 1L; @Override
public Tuple2<String, String> call(String s) throws Exception {
return new Tuple2<String, String>(s.split(" ")[1], s);
}
});
JavaDStream<String> transFormResult =
pairNameList.transform(new Function<JavaPairRDD<String,String>, JavaRDD<String>>() { /**
*
*/
private static final long serialVersionUID = 1L; @Override
public JavaRDD<String> call(JavaPairRDD<String, String> nameRDD)
throws Exception {
/**
* nameRDD:
* ("zhangsan","1 zhangsan")
* ("lisi","2 lisi")
* ("wangwu","3 wangwu")
* blackNameRDD:
* ("zhangsan",true)
*
* ("zhangsan",("1 zhangsan",[true]))
*
*/
JavaPairRDD<String, Tuple2<String, Optional<Boolean>>> leftOuterJoin =
nameRDD.leftOuterJoin(blackNameRDD);
//打印下leftOuterJoin
/*leftOuterJoin.foreach(new VoidFunction<Tuple2<String,Tuple2<String,Optional<Boolean>>>>() { *//**
*
*//*
private static final long serialVersionUID = 1L; @Override
public void call(Tuple2<String, Tuple2<String, Optional<Boolean>>> t)
throws Exception {
System.out.println(t);
}
});*/ //过滤:true的留下,false的过滤
//("zhangsan",("1 zhangsan",[true]))
JavaPairRDD<String, Tuple2<String, Optional<Boolean>>> filter =
leftOuterJoin.filter(new Function<Tuple2<String,Tuple2<String,Optional<Boolean>>>, Boolean>() { /**
*
*/
private static final long serialVersionUID = 1L; @Override
public Boolean call(Tuple2<String, Tuple2<String, Optional<Boolean>>> tuple)throws Exception {
if(tuple._2._2.isPresent()){
return !tuple._2._2.get();
}
return true;
}
}); JavaRDD<String> resultJavaRDD = filter.map(new Function<Tuple2<String,Tuple2<String,Optional<Boolean>>>, String>() { /**
*
*/
private static final long serialVersionUID = 1L; @Override
public String call(
Tuple2<String, Tuple2<String, Optional<Boolean>>> tuple)
throws Exception { return tuple._2._1;
}
}); //返回过滤好的结果
return resultJavaRDD;
}
}); transFormResult.print(); jsc.start();
jsc.awaitTermination();
jsc.stop();
}
}

 2、UpdateStateByKey算子(相当于对不同批次的累加和更新)

UpdateStateByKey的主要功能:
* 1、为Spark Streaming中每一个Key维护一份state状态,state类型可以是任意类型的, 可以是一个自定义的对象,那么更新函数也可以是自定义的。
* 2、通过更新函数对该key的状态不断更新,对于每个新的batch而言,Spark Streaming会在使用updateStateByKey的时候为已经存在的key进行state的状态更新

*  使用到updateStateByKey要开启checkpoint机制和功能。

*   多久会将内存中的数据写入到磁盘一份?

         如果batchInterval设置的时间小于10秒,那么10秒写入磁盘一份。如果batchInterval设置的时间大于10秒,那么就会batchInterval时间间隔写入磁盘一份。

 java代码:

package com.spark.sparkstreaming;

import java.util.Arrays;
import java.util.List; import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaSparkContext;
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.JavaDStream;
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 com.google.common.base.Optional; import scala.Tuple2; /**
* UpdateStateByKey的主要功能:
* 1、为Spark Streaming中每一个Key维护一份state状态,state类型可以是任意类型的, 可以是一个自定义的对象,那么更新函数也可以是自定义的。
* 2、通过更新函数对该key的状态不断更新,对于每个新的batch而言,Spark Streaming会在使用updateStateByKey的时候为已经存在的key进行state的状态更新
*
* hello,3
* spark,2
*
* 如果要不断的更新每个key的state,就一定涉及到了状态的保存和容错,这个时候就需要开启checkpoint机制和功能
*
* 全面的广告点击分析
* @author root
*
* 有何用? 统计广告点击流量,统计这一天的车流量,统计点击量
*/ public class UpdateStateByKeyOperator {
public static void main(String[] args) {
SparkConf conf = new SparkConf().setMaster("local[2]").setAppName("UpdateStateByKeyDemo");
JavaStreamingContext jsc = new JavaStreamingContext(conf, Durations.seconds(5));
/**
* 设置checkpoint目录
*
* 多久会将内存中的数据(每一个key所对应的状态)写入到磁盘上一份呢?
* 如果你的batch interval小于10s 那么10s会将内存中的数据写入到磁盘一份
* 如果bacth interval 大于10s,那么就以bacth interval为准

*
* 这样做是为了防止频繁的写HDFS
*/
JavaSparkContext sparkContext = jsc.sparkContext();
sparkContext.setCheckpointDir("./checkpoint"); // jsc.checkpoint("hdfs://node1:9000/spark/checkpoint");
// jsc.checkpoint("./checkpoint"); JavaReceiverInputDStream<String> lines = jsc.socketTextStream("node5", 9999); JavaDStream<String> words = lines.flatMap(new FlatMapFunction<String, String>() {
/**
*
*/
private static final long serialVersionUID = 1L; @Override
public Iterable<String> call(String s) {
return Arrays.asList(s.split(" "));
}
}); JavaPairDStream<String, Integer> ones = words.mapToPair(new PairFunction<String, String, Integer>() {
/**
*
*/
private static final long serialVersionUID = 1L; @Override
public Tuple2<String, Integer> call(String s) {
return new Tuple2<String, Integer>(s, 1);
}
}); JavaPairDStream<String, Integer> counts =
ones.updateStateByKey(new Function2<List<Integer>, Optional<Integer>, Optional<Integer>>() { /**
*
*/
private static final long serialVersionUID = 1L; @Override
public Optional<Integer> call(List<Integer> values, Optional<Integer> state) throws Exception {
/**
* values:经过分组最后 这个key所对应的value [1,1,1,1,1]
* state:这个key在本次之前之前的状态
*/
Integer updateValue = 0 ;
if(state.isPresent()){
updateValue = state.get();
} for (Integer value : values) {
updateValue += value;
}
return Optional.of(updateValue);
}
});
//output operator  counts.print(); jsc.start(); jsc.awaitTermination(); jsc.close(); } }

 scala代码:

package com.bjsxt.sparkstreaming

import org.apache.spark.SparkConf
import org.apache.spark.streaming.Durations
import org.apache.spark.streaming.StreamingContext object Operator_UpdateStateByKey {
def main(args: Array[String]): Unit = {
val conf = new SparkConf()
conf.setMaster("local[2]").setAppName("updateStateByKey")
val jsc = new StreamingContext(conf,Durations.seconds(5))
//设置日志级别
jsc.sparkContext.setLogLevel("WARN")
//设置checkpoint路径
jsc.checkpoint("hdfs://node1:9000/spark/checkpoint") val lineDStream = jsc.socketTextStream("node5", 9999)
val wordDStream = lineDStream.flatMap { _.split(" ") }
val pairDStream = wordDStream.map { (_,1)} val result = pairDStream.updateStateByKey((seq:Seq[Int],option:Option[Int])=>{
var value = 0
value += option.getOrElse(0)
for(elem <- seq){
value +=elem
} Option(value)
}) result.print()
jsc.start()
jsc.awaitTermination()
jsc.stop()
}
}

结果:

 可见从启动以来一直维护这个累加状态!!!

 2、windows窗口函数(实现一阶段内的累加 ,而不是程序启动时)

  假设每隔5s 1个batch,上图中窗口长度为15s,窗口滑动间隔10s。

        窗口长度和滑动间隔必须是batchInterval的整数倍。如果不是整数倍会检测报错。

优化后的window操作要保存状态所以要设置checkpoint路径,没有优化的window操作可以不设置checkpoint路径。

package com.spark.sparkstreaming;

import java.util.Arrays;

import org.apache.spark.SparkConf;
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.JavaDStream;
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; /**
* 基于滑动窗口的热点搜索词实时统计
* @author root
*
*/
public class WindowOperator { public static void main(String[] args) {
SparkConf conf = new SparkConf()
.setMaster("local[2]")
.setAppName("WindowHotWord"); JavaStreamingContext jssc = new JavaStreamingContext(conf, Durations.seconds(5));
/**
* 设置日志级别为WARN
*
*/
jssc.sparkContext().setLogLevel("WARN");
/**
* 注意:
* 没有优化的窗口函数可以不设置checkpoint目录
* 优化的窗口函数必须设置checkpoint目录
*/
// jssc.checkpoint("hdfs://node1:9000/spark/checkpoint");
jssc.checkpoint("./checkpoint");
JavaReceiverInputDStream<String> searchLogsDStream = jssc.socketTextStream("node04", 9999);
//word 1
JavaDStream<String> searchWordsDStream = searchLogsDStream.flatMap(new FlatMapFunction<String, String>() { /**
*
*/
private static final long serialVersionUID = 1L; @Override
public Iterable<String> call(String t) throws Exception {
return Arrays.asList(t.split(" "));
}
}); // 将搜索词映射为(searchWord, 1)的tuple格式
JavaPairDStream<String, Integer> searchWordPairDStream = searchWordsDStream.mapToPair( new PairFunction<String, String, Integer>() { private static final long serialVersionUID = 1L; @Override
public Tuple2<String, Integer> call(String searchWord)
throws Exception {
return new Tuple2<String, Integer>(searchWord, 1);
} });
/**
* 每隔10秒,计算最近60秒内的数据,那么这个窗口大小就是60秒,里面有12个rdd,在没有计算之前,这些rdd是不会进行计算的。
* 那么在计算的时候会将这12个rdd聚合起来,然后一起执行reduceByKeyAndWindow操作 ,
* reduceByKeyAndWindow是针对窗口操作的而不是针对DStream操作的。
*/
JavaPairDStream<String, Integer> searchWordCountsDStream = searchWordPairDStream.reduceByKeyAndWindow(new Function2<Integer, Integer, Integer>() { private static final long serialVersionUID = 1L; @Override
public Integer call(Integer v1, Integer v2) throws Exception {
return v1 + v2;
}
}, Durations.seconds(15), Durations.seconds(5)); //窗口长度,滑动间隔 /**
* window窗口操作优化:不用设置checkpoint目录。
*/
// JavaPairDStream<String, Integer> searchWordCountsDStream =
//
// searchWordPairDStream.reduceByKeyAndWindow(new Function2<Integer, Integer, Integer>() {
//
// private static final long serialVersionUID = 1L;
//
// @Override
// public Integer call(Integer v1, Integer v2) throws Exception {
// return v1 + v2;
// }
//
// },new Function2<Integer, Integer, Integer>() {
//
// private static final long serialVersionUID = 1L;
//
// @Override
// public Integer call(Integer v1, Integer v2) throws Exception {
// return v1 - v2;
// }
//
// }, Durations.seconds(15), Durations.seconds(5)); searchWordCountsDStream.print(); jssc.start();
jssc.awaitTermination();
jssc.close();
} }

Scala代码:

package com.bjsxt.sparkstreaming

import org.apache.spark.SparkConf
import org.apache.spark.streaming.Durations
import org.apache.spark.streaming.StreamingContext object Operator_Window {
def main(args: Array[String]): Unit = {
val conf = new SparkConf()
conf.setMaster("local[2]").setAppName("updateStateByKey")
val jsc = new StreamingContext(conf,Durations.seconds(5))
//设置日志级别
jsc.sparkContext.setLogLevel("WARN")
//设置checkpoint路径
jsc.checkpoint("hdfs://node1:9000/spark/checkpoint")
val lineDStream = jsc.socketTextStream("node04", 9999)
val wordDStream = lineDStream.flatMap { _.split(" ") }
val mapDStream = wordDStream.map { (_,1)} //window没有优化后的
val result = mapDStream.reduceByKeyAndWindow((v1:Int,v2:Int)=>{
v1+v2
}, Durations.seconds(60), Durations.seconds(10)) //优化后的
// val result = mapDStream.reduceByKeyAndWindow((v1:Int,v2:Int)=>{
// v1+v2
// }, (v1:Int,v2:Int)=>{
// v1-v2
// }, Durations.seconds(60), Durations.seconds(10)) result.print()
jsc.start()
jsc.awaitTermination()
jsc.stop()
}
}

结果:

【Spark篇】---SparkStreaming算子操作transform和updateStateByKey的更多相关文章

  1. SparkStreaming算子操作,Output操作

    SparkStreaming练习之StreamingTest,UpdateStateByKey,WindowOperator 一.SparkStreaming算子操作 1.1 foreachRDD 1 ...

  2. 【SparkStreaming学习之二】 SparkStreaming算子操作

    环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 jdk1.8 scala-2.10.4(依赖jdk1.8) spark ...

  3. 【Spark篇】---Spark中控制算子

    一.前述 Spark中控制算子也是懒执行的,需要Action算子触发才能执行,主要是为了对数据进行缓存. 控制算子有三种,cache,persist,checkpoint,以上算子都可以将RDD持久化 ...

  4. Spark-读写HBase,SparkStreaming操作,Spark的HBase相关操作

    Spark-读写HBase,SparkStreaming操作,Spark的HBase相关操作 1.sparkstreaming实时写入Hbase(saveAsNewAPIHadoopDataset方法 ...

  5. Spark Streaming中的操作函数讲解

    Spark Streaming中的操作函数讲解 根据根据Spark官方文档中的描述,在Spark Streaming应用中,一个DStream对象可以调用多种操作,主要分为以下几类 Transform ...

  6. Spark Streaming通过JDBC操作数据库

    本文记录了学习使用Spark Streaming通过JDBC操作数据库的过程,源数据从Kafka中读取. Kafka从0.10版本提供了一种新的消费者API,和0.8不同,因此Spark Stream ...

  7. 【Spark篇】---Spark调优之代码调优,数据本地化调优,内存调优,SparkShuffle调优,Executor的堆外内存调优

    一.前述 Spark中调优大致分为以下几种 ,代码调优,数据本地化,内存调优,SparkShuffle调优,调节Executor的堆外内存. 二.具体    1.代码调优 1.避免创建重复的RDD,尽 ...

  8. 【转帖】HBase读写的几种方式(二)spark篇

    HBase读写的几种方式(二)spark篇 https://www.cnblogs.com/swordfall/p/10517177.html 分类: HBase undefined 1. HBase ...

  9. sparkRDD:第3节 RDD常用的算子操作

    4.      RDD编程API 4.1 RDD的算子分类 Transformation(转换):根据数据集创建一个新的数据集,计算后返回一个新RDD:例如:一个rdd进行map操作后生了一个新的rd ...

随机推荐

  1. James Munkres Topology: Lemma 21.2 The sequence lemma

    Lemma 21.2 (The sequence lemma) Let \(X\) be a topological space; let \(A \subset X\). If there is a ...

  2. Jmeter实现dubbo接口压测案例

    当前项目中重构了消息服务,需要对消息服务接口做性能压测,评估消息服务的性能情况 通过和开发对接,目前消息服务是通过dubbo接口对内提供服务,所以才有了这边文章的记录 最初的压测这个dubbo接口有三 ...

  3. STL 贺习笔记

    贺文链接www.cnblogs.com/zhouzhendong/p/STL.html C++ STL 的一些基础用法 前言 ​ 创建一个空的 vector ,我一直是这样写的: vector < ...

  4. UOJ#465. 【HNOI2019】校园旅行 其他

    原文链接www.cnblogs.com/zhouzhendong/p/UOJ465.html 前言 tmd并查集写挂,调到自闭. cly和我写挂了同一个地方. 一下救了两个人感觉挺开心. 题解 首先直 ...

  5. 032 Java再次总结

    1.大纲 多线程怎么用的,线程池,事务,传播机制与隔离级别,反射,泛型,数据库引擎的区别,数据库merge,窗口函数,fastJson,JVM调优,GC钩子,Linux的awk,shell,HashM ...

  6. 8、socket以及socketserver

    Python 提供了两个基本的 socket 模块.第一个是 Socket,它提供了标准的 BSD Sockets API.第二个是 SocketServer, 它提供了服务器中心类,可以简化网络服务 ...

  7. idea通过mapper快速定位到xml文件

    1.点击File找到设置(Settings) 2.点击Plugins下的 Browse respositories 3.在搜索栏搜索mybatis ,选中 Free Mybatis plugin——i ...

  8. CF.802C.Heidi and Library (hard) (费用流zkw)

    题目链接 复习了下餐巾计划问题.全忘了=-= 首先这是一道网络流.然后本题有\(n\)种建图方法,以及\(smy\) dalao还有单纯形做法. 先假设所有物品都是买入的.那么对于每一天,拆成两个点\ ...

  9. Y1吐槽001 怎么做产品

    做一个产品,这个产品是做给用户用的还是做给领导看的完全是两个不同的出发点..做给领导看有好处,毕竟领导有知道进展的权利和指导方向的作用,还有一个好处就是表现得好. 忽略了使用者的感受是非常致命的,标模 ...

  10. 创建一个git仓库

    1.git init 使用git init命令初始化一个git仓库,git仓库会生成一个.git目录 git init 1.使用指定的目录作为我们的git仓库 git init newrepo 2.初 ...