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所做的功能扩展也进行 ...
随机推荐
- EOS主网搭建教程--&&--搭建节点--&&--搭建mongodb数据库
EOS主网搭建教程: 1.git clone https://github.com/EOS-Mainnet/eos.git --recursive 2.cd eos 3.git tag (查看有哪些分 ...
- Python数据类型-3 布尔类型
布尔类型 对于错.0和1.正与反,都是传统意义上的布尔类型. 但在Python语言中,布尔类型只有两个值,True与False.请注意,是英文单词的对与错,并且首字母要大写,不能其它花式变型. 布尔值 ...
- SWD学习笔记
SWD其实和JTAG类似,是一种调试串口. JTAG大致了解了一下.JTAG(Joint Test Action Group)主要4 lines:TMS(模式选择),TCK(时钟),TDI(数据输入) ...
- 「国家集训队」Crash的数字表格
题目描述 求(对 \(20101009\) 取模,\(n,m\le10^7\) ) \[\sum_{i=1}^n\sum_{j=1}^m\operatorname{lcm}(i,j)\] 大体思路 推 ...
- Python语法速查: 20. 线程与并发
返回目录 本篇索引 (1)线程基本概念 (2)threading模块 (3)线程间同步原语资源 (4)queue (1)线程基本概念 当应用程序需要并发执行多个任务时,可以使用线程.多个线程(thre ...
- python中提取位图信息(AttributeError: module 'struct' has no attribute 'unstack')
前言 今天这篇博文有点意思,它是从一个例子出发,从而体现出在编程中的种种细节和一些知识点的运用.和从前一样,我是人,离成神还有几十万里,所以无可避免的出现不严谨的地方甚至错误,请酌情阅读. 0x00 ...
- 吴裕雄--天生自然HADOOP操作实验学习笔记:安装zookeeper集群
实验目的 了解zookeeper的概念和原理 学会安装zookeeper集群并验证 掌握zookeeper命令使用 实验原理 1.Zookeeper介绍 ZooKeeper是一个分布式的,开放源码的分 ...
- 【剑指Offer面试编程题】题目1510:替换空格--九度OJ
题目描述: 请实现一个函数,将一个字符串中的空格替换成"%20".例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy. 输入: 每个 ...
- 利用SSH在本机和远程服务器之间传输文件或文件夹
1.从远程服务器上下载文件到本机 scp <服务器用户名>@<服务器地址>:<服务器中要下载的文件路径> <下载到本机的绝对路径> 2.从本机上传本地文 ...
- 《算法技术手册》George T. Heineman(作者)epub+mobi+azw3
内容简介 开发健壮的软件需要高效的算法,然后程序员们往往直至问题发生之时,才会去求助于算法.<算法技术手册>讲解了许多现有的算法,可用于解决各种问题.通过阅读它,可以使您学会如何选择和实现 ...