DStream-05 updateStateByKey函数的原理和源码
Demo
updateState 可以到达将每次 word count 计算的结果进行累加。
val conf = new SparkConf().setMaster("local[2]").setAppName("NetworkWordCount")
val ssc = new StreamingContext(conf, Seconds(1))
ssc.sparkContext.setLogLevel("WARN")
val lines = ssc.socketTextStream("localhost", 9999)
ssc.checkpoint("/Users/chouc/Work/IdeaProjects/learning/learning/spark/src/main/resources/checkpoint/SocketDstream")
val wordCounts = lines.flatMap(_.split(" ")).map((_,1)).updateStateByKey[Int]((seq:Seq[Int],total:Option[Int])=>{
total match {
case Some(value) => Option(seq.sum + value)
case None => Option(seq.sum)
}
})
wordCounts.print()
ssc.start()
ssc.awaitTermination()
源码
其实想要达到累加还是比较简单。
只要将本次计算的结果 + 上一次计算结果就可以了。
入口就是 updateStateByKey
PairDStreamFunctions
def updateStateByKey[S: ClassTag](
updateFunc: (Iterator[(K, Seq[V], Option[S])]) => Iterator[(K, S)],
partitioner: Partitioner,
rememberPartitioner: Boolean): DStream[(K, S)] = ssc.withScope {
val cleanedFunc = ssc.sc.clean(updateFunc)
val newUpdateFunc = (_: Time, it: Iterator[(K, Seq[V], Option[S])]) => {
cleanedFunc(it)
}
new StateDStream(self, newUpdateFunc, partitioner, rememberPartitioner, None)
}
文章 DStream-04 window 函数时候,提到了。每次计算后,每个DStream 都会将上一次的RDD 放入内存中,以供下一次使用,这样一来也就更简单。如果获取上一次的RDD呢 ,也就是当前batch time 减去 slideDuration 就等于上一个批次的时间戳,可以通过getOrCompute 得到。
slideDuration 默认情况就是 batchInterval 批次间隔时间。在window 中也是批次时间。
StateDStream
class StateDStream[K: ClassTag, V: ClassTag, S: ClassTag](
parent: DStream[(K, V)],
updateFunc: (Time, Iterator[(K, Seq[V], Option[S])]) => Iterator[(K, S)],
partitioner: Partitioner,
preservePartitioning: Boolean,
initialRDD: Option[RDD[(K, S)]]
) extends DStream[(K, S)](parent.ssc) {
// 这边注意,这个StateDStream 需要设置checkpoint 地址 来保存数据。
super.persist(StorageLevel.MEMORY_ONLY_SER)
override val mustCheckpoint = true
// 这个方法就是将 前一个batch RDD 的结果和当前计算的结果合并
private [this] def computeUsingPreviousRDD(
batchTime: Time,
parentRDD: RDD[(K, V)],
prevStateRDD: RDD[(K, S)]) = {
// Define the function for the mapPartition operation on cogrouped RDD;
// first map the cogrouped tuple to tuples of required type,
// and then apply the update function
val updateFuncLocal = updateFunc
val finalFunc = (iterator: Iterator[(K, (Iterable[V], Iterable[S]))]) => {
val i = iterator.map { t =>
val itr = t._2._2.iterator
val headOption = if (itr.hasNext) Some(itr.next()) else None
(t._1, t._2._1.toSeq, headOption)
}
updateFuncLocal(batchTime, i)
}
// cogroup 合并
val cogroupedRDD = parentRDD.cogroup(prevStateRDD, partitioner)
// 然后将合并后的结果计算
val stateRDD = cogroupedRDD.mapPartitions(finalFunc, preservePartitioning)
Some(stateRDD)
}
override def compute(validTime: Time): Option[RDD[(K, S)]] = {
// Try to get the previous state RDD
// 算出上一个batch time 来获取上一个batch的RDD。
getOrCompute(validTime - slideDuration) match {
//如果有就说明之前有RDD,如果没有则当前是第一个batch
case Some(prevStateRDD) => // If previous state RDD exists
// Try to get the parent RDD
// 获取当前这个批次来的数据 。这边理解有点绕,parent.getOrCompute(validTime) 就是前一个DStream 计算的结果,可以看下MappedDStream 的 方法就比较清楚了。
parent.getOrCompute(validTime) match {
case Some(parentRDD) => // If parent RDD exists, then compute as usual
// 见两个RDD 的数据。
computeUsingPreviousRDD (validTime, parentRDD, prevStateRDD)
case None => // If parent RDD does not exist
// Re-apply the update function to the old state RDD
val updateFuncLocal = updateFunc
val finalFunc = (iterator: Iterator[(K, S)]) => {
val i = iterator.map(t => (t._1, Seq.empty[V], Option(t._2)))
updateFuncLocal(validTime, i)
}
val stateRDD = prevStateRDD.mapPartitions(finalFunc, preservePartitioning)
Some(stateRDD)
}
case None => // If previous session RDD does not exist (first input data)
// Try to get the parent RDD
parent.getOrCompute(validTime) match {
case Some(parentRDD) => // If parent RDD exists, then compute as usual
initialRDD match {
case None =>
// Define the function for the mapPartition operation on grouped RDD;
// first map the grouped tuple to tuples of required type,
// and then apply the update function
val updateFuncLocal = updateFunc
val finalFunc = (iterator: Iterator[(K, Iterable[V])]) => {
updateFuncLocal (validTime,
iterator.map (tuple => (tuple._1, tuple._2.toSeq, None)))
}
val groupedRDD = parentRDD.groupByKey(partitioner)
val sessionRDD = groupedRDD.mapPartitions(finalFunc, preservePartitioning)
// logDebug("Generating state RDD for time " + validTime + " (first)")
Some (sessionRDD)
case Some (initialStateRDD) =>
computeUsingPreviousRDD(validTime, parentRDD, initialStateRDD)
}
case None => // If parent RDD does not exist, then nothing to do!
// logDebug("Not generating state RDD (no previous state, no parent)")
None
}
}
}
}
DStream-05 updateStateByKey函数的原理和源码的更多相关文章
- DStream-04 Window函数的原理和源码
DStream 中 window 函数有两种,一种是普通 WindowedDStream,另外一种是针对 window聚合 优化的 ReducedWindowedDStream. Demo objec ...
- Java并发编程(七)ConcurrentLinkedQueue的实现原理和源码分析
相关文章 Java并发编程(一)线程定义.状态和属性 Java并发编程(二)同步 Java并发编程(三)volatile域 Java并发编程(四)Java内存模型 Java并发编程(五)Concurr ...
- Kubernetes Job Controller 原理和源码分析(二)
概述程序入口Job controller 的创建Controller 对象NewController()podControlEventHandlerJob AddFunc DeleteFuncJob ...
- Kubernetes Job Controller 原理和源码分析(三)
概述Job controller 的启动processNextWorkItem()核心调谐逻辑入口 - syncJob()Pod 数量管理 - manageJob()小结 概述 源码版本:kubern ...
- [Spark内核] 第32课:Spark Worker原理和源码剖析解密:Worker工作流程图、Worker启动Driver源码解密、Worker启动Executor源码解密等
本課主題 Spark Worker 原理 Worker 启动 Driver 源码鉴赏 Worker 启动 Executor 源码鉴赏 Worker 与 Master 的交互关系 [引言部份:你希望读者 ...
- [Spark內核] 第41课:Checkpoint彻底解密:Checkpoint的运行原理和源码实现彻底详解
本课主题 Checkpoint 运行原理图 Checkpoint 源码解析 引言 Checkpoint 到底是什么和需要用 Checkpoint 解决什么问题: Spark 在生产环境下经常会面临 T ...
- Dubbo原理和源码解析之服务引用
一.框架设计 在官方<Dubbo 开发指南>框架设计部分,给出了引用服务时序图: 另外,在官方<Dubbo 用户指南>集群容错部分,给出了服务引用的各功能组件关系图: 本文将根 ...
- Dubbo原理和源码解析之标签解析
一.Dubbo 配置方式 Dubbo 支持多种配置方式: XML 配置:基于 Spring 的 Schema 和 XML 扩展机制实现 属性配置:加载 classpath 根目录下的 dubbo.pr ...
- Dubbo原理和源码解析之“微内核+插件”机制
github新增仓库 "dubbo-read"(点此查看),集合所有<Dubbo原理和源码解析>系列文章,后续将继续补充该系列,同时将针对Dubbo所做的功能扩展也进行 ...
随机推荐
- tensorflow简介、目录
目前工作为nlp相关的分类及数据治理,之前也使用tensorflow写过一些简单分类的代码,感受到深度学习确实用处较大,想更加系统和全面的学习下tensorflow的相关知识,于是我默默的打开了b站: ...
- 第5节 Actor实战:1 - 6
10.3. Actor实战 10.3.1. 第一个例子 怎么实现actor并发编程: 1.定义一个class或者是object继承Actor特质,注意导包import scala.actor ...
- 浏览器控制台报Cannot read property 'conf' of undefined
原因:JS中有个变量没有类型导致 解决:加上类型即可(我是少写了var)
- 使用mybase、Typora搭配坚果云实现个人云笔记
如果我们没有使用印象笔记.有道云之类的云笔记,那么就会遇到一个问题,比如我在公司是用的公司的电脑,然后下班回家用的自己的电脑,那么我在公司写的文档,比如markdown 文件,mybase知识管理工具 ...
- JPG加入RAR文件原理详解
在水木看到有人上传了一张图片,说如果将其后缀改为rar,解压后会有别的文件,试了一下,果然如此.用十六进制的编辑器看了看,发现的确有理. 先是,文件头部是以JPG格式起始的,如下: ......JFI ...
- iis下发布MVC网站
1.首先检查有没有安装iis,没有的话先安装iis 2. 3.选择应用程序池的时候看有没有asp.net 4.0 如果没有先安装. 首先以管理员身份打开“运行”输入cd C:\Windows\Micr ...
- UI的考核方式之【主题颜色 + 主题字体 + 主题样式】
首先,项目中的颜色需要怎么管理呢? 宏?常量? 宏的值可以被改变,不用宏.那就用常量.那常量的名字怎么去起名呢? WSFConstants_Color_0xCCCCCC? WSFConstants_C ...
- C#调用Win32 的API函数--User32.dll ----转载
Win32的API函数是微软自己的东西,可以直接在C#中直接调用,在做WinForm时还是很有帮助的.有时候我们之直接调用Win32 的API,可以很高效的实现想要的效果. using System; ...
- SSH和screen服务
SSH是一种能够以安全的方式提供远程登录的协议,目前远程管理的首选方式,sshd是基于SSH协议开发的一款远程管理服务程序,在Linux系统中需要部署sshd服务程序才能使用SSH协议来进行远程管理, ...
- HashMap1.8之节点删除分析
HashMap之节点删除 大家一直关注的都是HashMap如何添加节点,当节点数量大于8的时候转化为红黑树,否则使用链表等等,但大家是否有看过删除节点的处理逻辑呢? 今天来看看HashMap删除节点的 ...