structured-Streaming之watermark水印update和append模式学习

 

 

http://spark.apache.org/docs/2.4.3/structured-streaming-programming-guide.html

建议看官网,官网最权威

注意点

1、该outputMode为update模式,即只会输出那些有更新的数据!!

2、该开窗窗口长度为10min,步长5min,水印为eventtime-10min,(需理解开窗规则)

3、官网案例trigger(Trigger.ProcessingTime("5 minutes")),但是测试的时候不建议使用这个

4、未输出数据不代表已经在内存中被剔除,只是由于update模式的原因

5、建议比对append理解水印

个人测试案例

object WaterMarkUpdate {
  def main(args: Array[String]): Unit = {
   val spark: SparkSession = SparkSession.builder().appName("chenchi").master("local[2]").getOrCreate()
       import  spark.implicits._
       spark.readStream
         .format("socket")
         .option("host", "hadoop102")
         .option("port", "1234")
        // .option("includeTimestamp", true) // 给产生的数据自动添加时间戳
         .load()
         .as[String]
         .map(x=>{
            val split: Array[String] = x.split(",")
             (split(0),Timestamp.valueOf(split(1)))
           })
         .toDF("word", "time")
         .withWatermark("time","10 minutes")
         .groupBy(
           window($"time", "10 minutes", "5 minutes"),
           $"word"
         )
         .count()
         .writeStream
         .format("console")
         .outputMode("update")
         //.trigger(Trigger.ProcessingTime("5 minutes"))
         .option("truncate","false")
         .start()
         .awaitTermination()
  }
}

测试数据和官网一样

dog,2019-09-25 12:07:00
owl,2019-09-25 12:08:00


dog,2019-09-25 12:14:00
cat,2019-09-25 12:09:00

cat,2019-09-25 12:15:00
dog,2019-09-25 12:08:00
owl,2019-09-25 12:13:00
owl,2019-09-25 12:21:00

owl,2019-09-25 12:17:00

第一次输入

dog,2019-09-25 12:07:00
owl,2019-09-25 12:08:00

得到结果

这个主要是因为我输入两条数据的时候两条数据时间有间隔,所以会出现两次,两次结果合起来和官网一样,

batch2输出的是因为update模式,不出输出dog,因为dog中的内容没有更新

第二次输入

 与官网一样

第三次输入数据

cat,2019-09-25 12:15:00
dog,2019-09-25 12:08:00
owl,2019-09-25 12:13:00
owl,2019-09-25 12:21:00

这个又是因为trigger时间没有设置,属于尽快模式,只输出更新内容,官网那里12:20下面那里.....省略了12:21owl这条数据的输出,这个不是我错了,

其实更新模式很简单,都不想写了再坚持一下。

第四次入内容

owl,2019-09-25 12:17:00

这个也是官网省略了一条记录,不是我这里多了一条记录,到这里明白发现我还是错了,就用那个trigger设置一下时间好点,这样显示结果容易观看,

其实个人觉得update模式有弊端,

1、数据已经被剔除,比如原先内存已经存了12:00-12:10 ,dog ,5 ,此时内存里有5个dog,但是到后面水印比如为12:20,根据水印,这个5个dog已经过期会在内存里被剔除,但是我新增一条数据 dog,12:24,结果会显示dog:6,这样根本看不出数据是否过期

当然有可能是我的想法太狭隘,感觉不到这个的好处

————————————————————————————————————————————————————————

下面我将解释下append模式下的 watermark作用

上述代码修改下

.outputMode("append")
.trigger(Trigger.ProcessingTime("3 minutes"))

测试数据

dog,2019-09-25 12:07:00
owl,2019-09-25 12:08:00

dog,2019-09-25 12:14:00
cat,2019-09-25 12:09:00

cat,2019-09-25 12:15:00
dog,2019-09-25 12:08:00
owl,2019-09-25 12:13:00
owl,2019-09-25 12:21:00

donkey,2019-09-25 12:04:00
owl,2019-09-25 12:26:00
owl,2019-09-25 12:17:00

cat,2019-09-25 12:09:00

还是之前的数据

第一次输入

dog,2019-09-25 12:07:00
owl,2019-09-25 12:08:00

就是空数据!!官网也为空

第二次输入

dog,2019-09-25 12:14:00
cat,2019-09-25 12:09:00

没错还是空数据,官网也是空, 这又是为啥,稍后再说

第三次输入

cat,2019-09-25 12:15:00
dog,2019-09-25 12:08:00
owl,2019-09-25 12:13:00
owl,2019-09-25 12:21:00


这里输出了两次

这里要说下,console输出的时候,有时候你输入一次,一下出来两个batch?。我觉得是你输入一次数据(一条数据或者一批),一批数据可能存在时间差,处理的时间不一样,就会出现多个batch,不知道我的猜想对不对

第四次输入

donkey,2019-09-25 12:04:00
owl,2019-09-25 12:26:00
owl,2019-09-25 12:17:00

这里出现数据差异的原因

第五次输入

cat,2019-09-25 12:09:00

batch=null

附上一张统计表,比较直观点

 数据内容此时内存中的数据有控制台输出的结果解析
第一次输入的数据dog,2019-09-25 12:07:00
owl,2019-09-25 12:08:00
12:00-12:10  dog 1
12:00-12:10  owl 1
12:05-12:15  dog 1
12:05-12:15  owl 1
null无内存中的数据剔除
第二次输入的数据dog,2019-09-25 12:14:00
cat,2019-09-25 12:09:00
12:00-12:10  dog 1
12:00-12:10  owl 1
12:00-12:10  cat 1
12:05-12:15  dog 2
12:05-12:15  owl 1
12:05-12:15  cat 1
12:10-12:20  dog 1
null无内存中的数据剔除
第三次输入的数据cat,2019-09-25 12:15:00
dog,2019-09-25 12:08:00
owl,2019-09-25 12:13:00
owl,2019-09-25 12:21:00
12:00-12:10  dog 2
12:00-12:10  owl 1
12:00-12:10  cat 1

12:05-12:15  dog 3
12:05-12:15  owl 2
12:05-12:15  cat 1 注意这个
12:10-12:20  dog 1
12:10-12:20  cat 1
12:10-12:20  owl 1
12:15-12:25  cat 1
12:15-12:25  owl 1
12:20-12:30  owl 1
batch3:null和
Batch: 4

+------------------------------------------+----+-----+
|window                                    |word|count|
+------------------------------------------+----+-----+
|[2019-09-25 12:00:00, 2019-09-25 12:10:00]|dog |2    |
|[2019-09-25 12:00:00, 2019-09-25 12:10:00]|owl |1    |
|[2019-09-25 12:00:00, 2019-09-25 12:10:00]|cat |1    |
+------------------------------------------+----+-----+

此时这里的watermarke为12:21-10=12:11
这里输出了两段一段为空
一段中为小于12:11的所有数据,即表明这个watermark起了作用
第四次输入的数据donkey,2019-09-25 12:04:00
owl,2019-09-25 12:26:00
owl,2019-09-25 12:17:00
数据太多就不写了其中
donkey12:04<第三次的水印12:11
属于过期数据,不参与计算
Batch: 5 null
Batch: 6
|window                                    |word|count|
+------------------------------------------+----+-----+
|[2019-09-25 12:05:00, 2019-09-25 12:15:00]|owl |2    |
|[2019-09-25 12:05:00, 2019-09-25 12:15:00]|dog |3    |
|[2019-09-25 12:05:00, 2019-09-25 12:15:00]|cat |1    |
+------------------------------------------+----+-----+
此时这里的watermark=12::26-10=12:16
batch6输出的内容是第三次输出数据后内存中<12:16的数据
12:00-12:10的已经被剔除了,所以此次剔除的是12:05-12:15中的数据
第四次输入的数据cat,2019-09-25 12:09:00cat同理过期batch7 :null此时没有输出,因为此时水印还是12:16,过期数据已经被删除完了

 

这里主要说明两点

1、我第四次输出结果是 owl 2 dog 3 cat 1 spark 结果是owl 2 dog 3 cat 2

出现差异的原因是,第三次输入的数据cat,2019-09-25 12:15:00这个的开窗出现了差异根据源码
   * The windows are calculated as below:
   * maxNumOverlapping <- ceil(windowDuration / slideDuration)
   * for (i <- 0 until maxNumOverlapping)
   *   windowId <- ceil((timestamp - startTime) / slideDuration)
   *   windowStart <- windowId * slideDuration + (i - maxNumOverlapping) * slideDuration + startTime
   *   windowEnd <- windowStart + windowDuration
   *   return windowStart, windowEnd
 windowStart =12:15-ceil(10/5)*5=12:05  所以应该划分12:05-12:15  12:10-12:20这两个窗口

spark官方应该是划分为12:10-12:20 12:15-12:25,个人猜测.

2、就是输出时间的问题,我是在第三次和第四次输入数据后,控制台就打印了结果,spark官方图上显示的是第四次和第五次输出的结果 先来段spark官方原话

The engine waits for “10 mins” for late date to be counted, then drops intermediate state of a window < watermark, and appends the final counts to the Result Table/sink. For example, the final counts of window 12:00 - 12:10 is appended to the Result Table only after the watermark is updated to 12:11.

翻译:只有(只要)当水印=12:11的时候,之前的12:00 - 12:10 窗口数据就会被追加到结果表  即输出到控制台

是只有还是只要?第三次输入数据后水印已经到达12:11,然后就把12:00-12:10的数据输出了,同时这里有两个batch,个人感觉是只要

当一个批次的数据的时候,structured-streaming 先获得最大的水印,然后排除那些同批次的过期数据,然后会把一个批次的数据全部加载进内存计算出结果后,再剔除过期的内存数据

如果划分到一条条数据,有个疑问,是此条最大水印的数据输入后,立马开始清理内存,还是在下一条数据来临的时候再清理

欢迎大家探讨,这个只是自己学习时的一点想法,不一定正确,欢迎批评,但别太严厉。。。。。。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数据分析职业是一个多金的职业,数据分析职位是一个金饭碗的职位,前景美好,但是要全面掌握大数据分析技术,非常困难,大部分学员的痛点是不能快速找到入门要点,精准快速上手。本课程采用项目驱动的方式,以Spark3和Clickhouse技术为突破口,带领学员快速入门Spark3+Clickhouse数据分析,促使学员成为一名高效且优秀的大数据分析人才。学员通过本课程的学习,不仅可以掌握使用Python3进行Spark3数据分析,还会掌握利用Scala/java进行Spark数据分析,多语言并进,力求全面掌握;另外通过项目驱动,掌握Spark框架的精髓,教导Spark源码查看的技巧;会学到Spark性能优化的核心要点,成为企业急缺的数据分析人才;更会通过Clickhouse和Spark搭建OLAP引擎,使学员对大数据生态圈有一个更加全面的认识和能力的综合提升。真实的数据分析项目,学完即可拿来作为自己的项目经验,增加面试谈薪筹码。课程涉及内容:Ø  Spark内核原理(RDD、DataFrame、Dataset、Structed Stream、SparkML、SparkSQL)Ø  Spark离线数据分析(千万简历数据分析、雪花模型离线数仓构建)Ø  Spark特征处理及模型预测Ø  Spark实时数据分析(Structed Stream)原理及实战Ø  Spark+Hive构建离线数据仓库(数仓概念ODS/DWD/DWS/ADS)Ø  Clickhouse核心原理及实战Ø  Clickhouse engine详解Ø  Spark向Clickhouse导入简历数据,进行数据聚合分析Ø  catboost训练房价预测机器学习模型Ø  基于Clickhouse构建机器学习模型利用SQL进行房价预测Ø  Clickhouse集群监控,Nginx反向代理Grafana+Prometheus+Clickhouse+node_exporterØ  Spark性能优化Ø  Spark工程师面试宝典       课程组件:集群监控:福利:本课程凡是消费满359的学员,一律送出价值109元的实体书籍.
Spark Structured Streaming 中的 Append、Complete、Update 三种输出模式与前面所提到的 AI 对话系统中的输出模式有类似之处,但是在具体实现和使用上有所不同。 1. Append 模式:该模式下,只有新增的数据才会被输出,已有数据不会被更新。在这种模式下,输出结果只包含新的数据,不包含历史数据。该模式适用于数据不需要更新的场景,比如说对于一组计算的结果,每次只需要使用最新的结果即可。 2. Complete 模式:该模式下,所有的数据都会被输出,而且输出结果会包含历史数据和新数据的计算结果。在这种模式下,Spark会全部计算完所有数据后进行输出。该模式适用于需要输出完整结果的场景,比如说需要输出各个时间段的交易总额。 3. Update 模式:该模式下,只有更新的数据会被输出,历史数据不会被输出。在这种模式下,Spark会在每个批次之间进行数据的增量计算,并且只输出新增的和修改过的数据。该模式适用于需要实时更新结果的场景,比如说需要实时监控某个指标的变化。 总的来说,三种模式各有优缺点,可以根据具体的场景和需求来选择使用。Append 模式适用于数据无需更新的情况,Complete 模式适用于需要输出完整结果的场景,Update 模式适用于需要实时监控变化的场景。同时,不同的输出模式对计算性能和资源消耗也有所不同,需要综合考虑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值