建议先看DStream-04 Window函数的原理和源码

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函数的原理和源码的更多相关文章

  1. DStream-04 Window函数的原理和源码

    DStream 中 window 函数有两种,一种是普通 WindowedDStream,另外一种是针对 window聚合 优化的 ReducedWindowedDStream. Demo objec ...

  2. Java并发编程(七)ConcurrentLinkedQueue的实现原理和源码分析

    相关文章 Java并发编程(一)线程定义.状态和属性 Java并发编程(二)同步 Java并发编程(三)volatile域 Java并发编程(四)Java内存模型 Java并发编程(五)Concurr ...

  3. Kubernetes Job Controller 原理和源码分析(二)

    概述程序入口Job controller 的创建Controller 对象NewController()podControlEventHandlerJob AddFunc DeleteFuncJob ...

  4. Kubernetes Job Controller 原理和源码分析(三)

    概述Job controller 的启动processNextWorkItem()核心调谐逻辑入口 - syncJob()Pod 数量管理 - manageJob()小结 概述 源码版本:kubern ...

  5. [Spark内核] 第32课:Spark Worker原理和源码剖析解密:Worker工作流程图、Worker启动Driver源码解密、Worker启动Executor源码解密等

    本課主題 Spark Worker 原理 Worker 启动 Driver 源码鉴赏 Worker 启动 Executor 源码鉴赏 Worker 与 Master 的交互关系 [引言部份:你希望读者 ...

  6. [Spark內核] 第41课:Checkpoint彻底解密:Checkpoint的运行原理和源码实现彻底详解

    本课主题 Checkpoint 运行原理图 Checkpoint 源码解析 引言 Checkpoint 到底是什么和需要用 Checkpoint 解决什么问题: Spark 在生产环境下经常会面临 T ...

  7. Dubbo原理和源码解析之服务引用

    一.框架设计 在官方<Dubbo 开发指南>框架设计部分,给出了引用服务时序图: 另外,在官方<Dubbo 用户指南>集群容错部分,给出了服务引用的各功能组件关系图: 本文将根 ...

  8. Dubbo原理和源码解析之标签解析

    一.Dubbo 配置方式 Dubbo 支持多种配置方式: XML 配置:基于 Spring 的 Schema 和 XML 扩展机制实现 属性配置:加载 classpath 根目录下的 dubbo.pr ...

  9. Dubbo原理和源码解析之“微内核+插件”机制

    github新增仓库 "dubbo-read"(点此查看),集合所有<Dubbo原理和源码解析>系列文章,后续将继续补充该系列,同时将针对Dubbo所做的功能扩展也进行 ...

随机推荐

  1. tensorflow简介、目录

    目前工作为nlp相关的分类及数据治理,之前也使用tensorflow写过一些简单分类的代码,感受到深度学习确实用处较大,想更加系统和全面的学习下tensorflow的相关知识,于是我默默的打开了b站: ...

  2. 第5节 Actor实战:1 - 6

    10.3.   Actor实战 10.3.1.    第一个例子 怎么实现actor并发编程: 1.定义一个class或者是object继承Actor特质,注意导包import scala.actor ...

  3. 浏览器控制台报Cannot read property 'conf' of undefined

    原因:JS中有个变量没有类型导致 解决:加上类型即可(我是少写了var)

  4. 使用mybase、Typora搭配坚果云实现个人云笔记

    如果我们没有使用印象笔记.有道云之类的云笔记,那么就会遇到一个问题,比如我在公司是用的公司的电脑,然后下班回家用的自己的电脑,那么我在公司写的文档,比如markdown 文件,mybase知识管理工具 ...

  5. JPG加入RAR文件原理详解

    在水木看到有人上传了一张图片,说如果将其后缀改为rar,解压后会有别的文件,试了一下,果然如此.用十六进制的编辑器看了看,发现的确有理. 先是,文件头部是以JPG格式起始的,如下: ......JFI ...

  6. iis下发布MVC网站

    1.首先检查有没有安装iis,没有的话先安装iis 2. 3.选择应用程序池的时候看有没有asp.net 4.0 如果没有先安装. 首先以管理员身份打开“运行”输入cd C:\Windows\Micr ...

  7. UI的考核方式之【主题颜色 + 主题字体 + 主题样式】

    首先,项目中的颜色需要怎么管理呢? 宏?常量? 宏的值可以被改变,不用宏.那就用常量.那常量的名字怎么去起名呢? WSFConstants_Color_0xCCCCCC? WSFConstants_C ...

  8. C#调用Win32 的API函数--User32.dll ----转载

    Win32的API函数是微软自己的东西,可以直接在C#中直接调用,在做WinForm时还是很有帮助的.有时候我们之直接调用Win32 的API,可以很高效的实现想要的效果. using System; ...

  9. SSH和screen服务

    SSH是一种能够以安全的方式提供远程登录的协议,目前远程管理的首选方式,sshd是基于SSH协议开发的一款远程管理服务程序,在Linux系统中需要部署sshd服务程序才能使用SSH协议来进行远程管理, ...

  10. HashMap1.8之节点删除分析

    HashMap之节点删除 大家一直关注的都是HashMap如何添加节点,当节点数量大于8的时候转化为红黑树,否则使用链表等等,但大家是否有看过删除节点的处理逻辑呢? 今天来看看HashMap删除节点的 ...