spark教程(16)-Streaming 之 DStream 详解
DStream 其实是 RDD 的序列,它的语法与 RDD 类似,分为 transformation(转换) 和 output(输出) 两种操作;
DStream 的转换操作分为 无状态转换 和 有状态转换,且 tansformation 也是惰性的;
DStream 的输出操作请参考 我的博客 Streaming
无状态转换
转换操作只作用于单个 RDD,即单个数据流的 batch;
例如,每次根据采集到的数据流统计单词个数,第一次采集到的是 a 2个 b 1个,第二次采集到的是 a 1个 b 1个,那么第二次的输出也是 a 1 b 1,并不与前面的累计
DStream 的转换操作最终还是会转化成 RDD 的转换操作,这个转化由 spark streaming 完成
本文只介绍部分 API,详细请参考源码 /usr/lib/spark/python/pyspark/streaming/dstream.py
基本转换
为了解释下面的操作,假定输入都一样,如下
hellp spark
hello hadoop hive
map(self, f, preservesPartitioning=False):生成一个新的 DStream,不解释了
[u'hellp', u'spark']
[u'hello', u'hadoop', u'hive']
flatMap(self, f, preservesPartitioning=False):把一个 func 作用于 DStream 的所有元素,并将生成的结果展开
hellp
spark
hello
hadoop
hive
filter(self, f):不解释了
repartition(self, numPartitions):把 DStream 中每个 RDD 进行分区,用于提高并发
union(self, other):在一个 RDD 上再加一个 RDD
聚合转换
count(self):
reduce(self, func):
countByValue(self):返回一个由键值对型 RDD 构成的 DStream
# 输入
a
a
b
# 输出
(u'a', 2)
(u'b', 1)
键值对转换
cogroup(self, other, numPartitions=None):把两个 kv 构成的 DStream 根据 key 进行合并,注意是取 key 的并集
sc = SparkContext() ssc = StreamingContext(sc, 30)
line1 = ssc.socketTextStream('192.168.10.11', 9999)
out1 = line1.map(lambda x: (len(x), x)).groupByKey() # value 没有进行任何操作
out1.pprint() line2 = ssc.socketTextStream('192.168.10.11', 9998)
out2 = line2.map(lambda x: (len(x), x)).groupByKey()
out2.pprint() out3 = out1.cogroup(out2)
out3.pprint() ssc.start()
ssc.awaitTermination()
很遗憾,合并之后,value 是个对象集,不可见
join(self, other, numPartitions=None):把两个 kv 构成的 DStream 连接起来
如 (K,V) 构成的 DStream 和 (K,W) 构成的 DStream 连接后是 (K, (V,W))
同样有 左连接、右连接、全连接
out3 = out1.join(out2) # 内连接 二者都有
out3 = out1.leftOuterJoin(out2) # 左连接 左边有,找对应右边的
out3 = out1.rightOuterJoin(out2) # 右连接 右边有,找对应左边的
out3 = out1.fullOuterJoin(out2) # 全连接 笛卡尔内积
reduceByKey(self, func, numPartitions=None):
groupByKey(self, numPartitions=None):将构成 DStream 的 RDD 中的元素进行 分组
还有很多,不一一解释了,记住本质,这些虽然是 DStream 的 API,但是这些 API 其实是作用于 构成 DStream 的 RDD 上的
transform:这个比较特殊
transform(self, func):
"""
Return a new DStream in which each RDD is generated by applying a function
on each RDD of this DStream. `func` can have one argument of `rdd`, or have two arguments of
(`time`, `rdd`)
"""
输入一个 函数,这个函数作用于 构成 DStream 的每个 RDD ,并返回新的 RDD ,重新构成一个 DStream
transform 用于 机器学习 或者 图计算 时优势明显
示例
from pyspark import SparkContext
from pyspark.streaming import StreamingContext sc = SparkContext()
ssc = StreamingContext(sc, 20)
line1 = ssc.socketTextStream('192.168.10.11', 9999)
out1 = line1.map(lambda x: (len(x), x))
### 输入为
# a
# aaa
# aa
out1.pprint()
# (1, u'a')
# (3, u'aaa')
# (2, u'aa') 这是一个 RDD,被 transform 的 func 作用 out2 = out1.transform(lambda x: x.sortByKey())
out2.pprint()
# (1, u'a')
# (2, u'aa')
# (3, u'aaa') out3 = out1.transform(lambda x: x.mapValues(lambda m: ''))
out3.pprint() ssc.start()
ssc.awaitTermination()
有状态转换
转换操作作用于之前所有的 RDD 上
例如,每次根据采集到的数据流统计单词个数,第一次采集到的是 a 2个 b 1个,第二次采集到的是 a 1个 b 1个,那么第二次的输出也是 a 3 b 2,累计之前的
updateStateByKey(self, updateFunc, numPartitions=None, initialRDD=None):更新当前 RDD 的状态,不好解释,用例子帮助理解
需要设置检查点, 用于保存状态
示例
from pyspark import SparkContext
from pyspark.streaming import StreamingContext def updateFunction(newValues, runningCount):
if runningCount is None:
runningCount = 0
return sum(newValues, runningCount) # add the new values with the previous running count to get the new count sc = SparkContext()
ssc = StreamingContext(sc, 20)
ssc.checkpoint('/usr/lib/spark') # 必须有检查点 line1 = ssc.socketTextStream('192.168.10.11', 9999)
out1 = line1.map(lambda x: (x, 1)).reduceByKey(lambda x, y: x + y) # 对当前 RDD 的处理 runningCounts = out1.updateStateByKey(updateFunction) # 更新状态
runningCounts.pprint() ssc.start()
ssc.awaitTermination()
示例操作
由于统计全局,所以需要checkpoint数据会占用较大的存储。而且效率也不高。所以很多时候不建议使用updateStateByKey
窗口操作
updateStateByKey 也是一种窗口,只是窗口大小不固定;
这里的窗口就是指滑窗,跟 均值滤波里面的滑窗意思一样;
这里的滑窗内的元素是 RDD;
滑窗有 窗口尺寸 和 滑动步长 两个概念
滑窗也是有状态的转换
这里的 尺寸 和 步长 都是用时间来描述;
尺寸 是 采集周期的 N 倍,步长 也是 采集周期的 N 倍;
window(self, windowDuration, slideDuration=None):windowDuration 为 窗口时长,slideDuration 为步长
示例
from pyspark import SparkContext
from pyspark.streaming import StreamingContext sc = SparkContext()
ssc = StreamingContext(sc, 20)
line1 = ssc.socketTextStream('192.168.10.11', 9999) ## 先处理再滑窗
out1 = line1.map(lambda x: (len(x), x))
out2 = out1.window(40)
# out2 = out2.groupByKey() # 滑窗后可继续处理
out2.pprint() ssc.start()
ssc.awaitTermination()
示例操作
可以看到有重复计算的内容
reduceByWindow(self, reduceFunc, invReduceFunc, windowDuration, slideDuration):当 slideDuration < windowDuration 时,计算是有重复的,那么我们可以不用重新获取或者计算,而是通过获取旧信息来更新新的信息,这样可以提高效率
函数解释
window 计算方式如下===
win1 = time1 + time2 + time3
win2 = time3 + time4 + time5
显然 time3 被重复获取并计算
reduceByWindow 计算方式如下====
win1 = time1 + time2 + time3
win2 = win1 + time4 + time5 -time1 -time2
reduceFunc 是对新产生的数据(time4,time5) 进行计算;
invReduceFunc 是对之前的旧数据(time1,time3) 进行计算;
示例
from pyspark import SparkContext
from pyspark.streaming import StreamingContext def func1(x, y):
return x+y def func2(x, y):
return -x-y sc = SparkContext(appName="windowStream", master="local[*]")
# 第二个参数指统计多长时间的数据
ssc = StreamingContext(sc, 10)
ssc.checkpoint("/tmp/window")
lines = ssc.socketTextStream('192.168.10.11', 9999)
# 第一个参数执行指定函数, 第二个参数是窗口长度, 第三个参数是滑动间隔
lines = lines.flatMap(lambda x: x.split(' ')).map(lambda x: (x, 1))
dstream = lines.reduceByWindow(func1, func2, 20, 10)
dstream.pprint() ssc.start()
ssc.awaitTermination()
reduceByWindow 和 window 可实现相同效果;
reduceByWindow 的底层是 reduceByKeyAndWindow,用法也完全相同,reduceByKeyAndWindow 的效率更高
需要设置检查点, 用于保存状态
reduceByKeyAndWindow(self, func, invFunc, windowDuration, slideDuration=None,
numPartitions=None, filterFunc=None):与 reduceByWindow 的区别是 它的输入需要 kv 对
dstream = lines.reduceByKeyAndWindow(func1, func2, 20, 10)
countByWindow(self, windowDuration, slideDuration):计数
需要设置检查点, 用于保存状态
示例
sc = SparkContext()
ssc = StreamingContext(sc, 20)
line1 = ssc.socketTextStream('192.168.10.11', 9999) ssc.checkpoint('/usr/lib/spark') ## 先处理再滑窗
out1 = line1.map(lambda x: x)
out2 = out1.countByWindow(40, 20)
# out2 = out2.groupByKey() # 滑窗后可继续处理
out2.pprint() ssc.start()
ssc.awaitTermination()
countByValueAndWindow(self, windowDuration, slideDuration, numPartitions=None):
groupByKeyAndWindow(self, windowDuration, slideDuration, numPartitions=None):
不一一解释了
总结
1. 凡是带 key 的都需要输入 kv 对
2. 凡是需要记录上个 状态的 都需要设置检查点
参考资料:
《Spark大数据分析核心概念技术及实践OCR-2017》 电子书
https://www.cnblogs.com/libin2015/p/6841177.html
spark教程(16)-Streaming 之 DStream 详解的更多相关文章
- Spark小课堂Week6 启动日志详解
Spark小课堂Week6 启动日志详解 作为分布式系统,Spark程序是非常难以使用传统方法来进行调试的,所以我们主要的武器是日志,今天会对启动日志进行一下详解. 日志详解 今天主要遍历下Strea ...
- 16个PHP设计模式详解
说明:该教程全部截选自实验楼教程[16个PHP设计模式详解]:主要介绍16个常用的设计模式的基础概念和技术要点,通过UML类图帮助理解设计模式中各个类之间的关联关系,针对每种设计模式都使用PHP完成了 ...
- ASP.NET MVC 5 学习教程:生成的代码详解
原文 ASP.NET MVC 5 学习教程:生成的代码详解 起飞网 ASP.NET MVC 5 学习教程目录: 添加控制器 添加视图 修改视图和布局页 控制器传递数据给视图 添加模型 创建连接字符串 ...
- PHP 中 16 个魔术方法详解
PHP 中 16 个魔术方法详解 前言 PHP中把以两个下划线__开头的方法称为魔术方法(Magic methods),这些方法在PHP中充当了举足轻重的作用. 魔术方法包括: __constru ...
- 《吐血整理》保姆级系列教程-玩转Fiddler抓包教程(5)-Fiddler监控面板详解
1.简介 按照从上往下,从左往右的计划,今天就轮到介绍和分享Fiddler的监控面板了.监控面板主要是一些辅助标签工具栏.有了这些就会让你的会话请求和响应时刻处监控中毫无隐私可言.监控面板是fiddl ...
- Python学习入门教程,字符串函数扩充详解
因有用户反映,在基础文章对字符串函数的讲解太过少,故写一篇文章详细讲解一下常用字符串函数.本文章是对:程序员带你十天快速入门Python,玩转电脑软件开发(三)中字符串函数的详解与扩充. 如果您想学习 ...
- Cobalt Strike系列教程第二章:Beacon详解
上周更新了Cobalt Strike系列教程第一章:简介与安装,文章发布后,深受大家的喜爱,遂将该系列教程的其他章节与大家分享,提升更多实用技能! 第二章:Beacon详解 一.Beacon命令 大家 ...
- 《吐血整理》保姆级系列教程-玩转Fiddler抓包教程(6)-Fiddler状态面板详解
1.简介 按照从上往下,从左往右的计划,今天就轮到介绍和分享Fiddler的状态面板了. 2.状态面板概览 Fiddler的状态面板概览,如下图所示: 3.状态面板详解 Fiddler底端状态栏面板详 ...
- spark教程(15)-Streaming
Spark Streaming 是一个分布式数据流处理框架,它可以近乎实时的处理流数据,它易编程,可以处理大量数据,并且能把实时数据与历史数据结合起来处理. Streaming 使得 spark 具有 ...
随机推荐
- jQuery属性操作之DOM属性操作
DOM属性操作是对DOM元素的属性进行读取.设置和移除操作, 比如prop(). removeProp(). 1. prop() 1.1 使用prop()获取返回值 prop() 用于返回属性值时, ...
- Codeforces 55D. Beautiful numbers(数位DP,离散化)
Codeforces 55D. Beautiful numbers 题意 求[L,R]区间内有多少个数满足:该数能被其每一位数字都整除(如12,24,15等). 思路 一开始以为是数位DP的水题,觉得 ...
- SAE上配置Django静态文件
很简单,步骤如下: 1.修改配置文件 setting.py 中的STATIC_ROOT为 '/static/' 2. 运行 python manage.py collectstatic , 将静态文件 ...
- Asyncio之EventLoop笔记
使用事件循环 Python3.4 采用了一个强大的框架来支持代码的并发执行: asyncio.这个框架使用事件循环来编排回调和异步任务. 事件循环位于事件循环策略的上下文中-这是 asyncio 所特 ...
- 整个系统禁用复制功能下,js实现部分数据的复制功能
需求背景:整个系统禁止复制,列表页操作栏新增按钮来复制数据列的手机号功能 感受下是怎么回事?看下效果 (GIF有点点烂)
- 整合spring boot时操作数据库时报错Caused by: java.lang.InstantiationException: tk.mybatis.mapper.provider.base.B
原文:https://blog.csdn.net/u__f_o/article/details/82756701 一般出现这种情况,应该是没有扫描到对应的mapper包,即在启动类下配置MapperS ...
- Qt多线程应用--QRunnable
http://blog.csdn.net/lefttime/article/details/5717349 作为Qt类中少有的基类, QRunnable提供了简洁有效的可运行对象的创建. 用QRun ...
- 性能分析 | MySQL 的慢查分析实例
最近遇见一个 MySQL 的慢查问题,于是排查了下,这里把相关的过程做个总结. 定位原因 我首先查看了 MySQL 的慢查询日志,发现有这样一条 query 耗时非常长(大概在 1 秒多),而且扫描的 ...
- nginx配置, 启动命令, 反向代理配置
2014年1月3日 13:52:07 喜欢这样的风格,干货 http://huoding.com/2013/10/23/290 -----------------下边是我自己的经验(windows)- ...
- JSTL优点
1. 在应用程序服务器之间提供了一致的接口,最大程序地提高了WEB应用在各应用服务器之间的移植. 2. 简化了JSP和WEB应用程序的开发.3. 以一种统一的方式减少了JSP中的scriptlet代码 ...