spark--基于事件时间的延迟数据处理-★

基于事件时间的延迟数据处理-★

说明

  • 之前在引入StructuredStreaming的时候提到
  • StructuredStreaming可以基于事件时间做延迟数据的处理,
  • 那么接下来进行原来说明和代码演示

时间分类

  • 事件时间:event-time:表示数据/数据真正发生的时间–现在用 因为它才能真正反映数据的真实状态
  • 处理时间:process-time:表示数据被处理时的时间–以前用
  • 摄入时间:Ingestion-time:表示数据到达系统的数据–不用
  • 理解
    • 现在假设,你正在去往地下停车场的路上,并且打算用手机点一份外卖。选好了外卖后,你就用在线支付功能付款了,这个时候是11点55分。恰好这时,你走进了地下停车库,而这里并没有手机信号。因此外卖的在线支付并没有立刻成功,而支付系统一直在Retry重试“支付”这个操作。
    • 当你找到自己的车并且开出地下停车场的时候,已经是12点05分了。这个时候手机重新有了信号,手机上的支付数据成功发到了外卖在线支付系统,支付完成。
    • 在上面这个场景中你可以看到,支付数据的事件时间是11点55分,而支付数据的处理时间是12点05分
    • 也就是上面的案例中
      • 事件时间:event-time,事情真正发生的时间为 11点55分
      • 处理时间:process-time,表示事件/数据被系统处理的时间为12点05分
      • 而如果要计算当天上午的订单12点之前的订单,那么就应该考虑使用订单的事件时间来统计
      • 而为了完成这个目标, 之前的技术是不行的得使用Dataflow模型-

实际需求

在这里插入图片描述

  • 到达窗口的最大的事件时间 - 允许延迟的时间 >= 窗口原来的结束时间 就触发该窗口的计算!
  • 否则该窗口就一直等待数据到来(这样的话不就给了迟到的数据一些机会)

API演示

http://spark.apache.org/docs/2.2.0/structured-streaming-programming-guide.html#window-operations-on-event-time
在这里插入图片描述

package cn.hanjiaxiaozhi.structedstream

import java.sql.Timestamp

import org.apache.spark.SparkContext
import org.apache.spark.sql.{
    
    DataFrame, SparkSession}

/**
 * Author hanjiaxiaozhi
 * Date 2020/7/26 16:35
 * Desc 演示StructuredStreaming中的基于事件时间的延迟数据处理
 * 注意这里仅仅演示API,实际中使用都是用Flink中的,因为Flink的该功能更加的完善和强大
*/
object WordCountWithWindowAndWatermakerAndEventTime {
    
    
  def main(args: Array[String]): Unit = {
    
    
    //1.准备StructuredStreaming执行环境
    val spark: SparkSession = SparkSession.builder.appName("wc").master("local[*]").getOrCreate()
    val sc: SparkContext = spark.sparkContext
    sc.setLogLevel("WARN")

    //2.读取node01:9999端口的数据
    val df: DataFrame = spark.readStream//表示使用DataFrame/DataSet做流处理并加载数据
      .option("host", "node01")//指定ip
      .option("port", 9999)//指定端口
      .option("includeTimeStamp",true)//表示将从socket接收到的数据的时间作为事件时间,演示后面的API,Socket不好模拟延迟
      .format("socket")//指定数据源为socket
      .load()//开始加载数据

    //3.做WordCount
    import org.apache.spark.sql.functions._
    import spark.implicits._
    // Dataset[(单词, 时间戳-事件时间)]
    val wordAndTimeDF: DataFrame = df.as[(String, Timestamp)] //给DF添加上类型并转为DS
      .flatMap(line => {
    
    
        line._1.split(" ").map((_, line._2))
      }).toDF("word","timestamp")


    //4.基于事件时间进行窗口聚合并设置最大允许的延迟时间
   val result = wordAndTimeDF
     //以下为关键代码
     //到达窗口的最大的事件时间  -  允许延迟的时间 >= 窗口原来的结束时间 就触发该窗口的计算!
     // ===========================
      .withWatermark("timestamp", "5 seconds")//指定事件时间是哪一列,并设置最大允许的延迟时间为5s
     // ===========================
      .groupBy(//分组时指定时间列,和窗口长度和滑动间隔,以及分组字段
        window($"timestamp", "10 seconds", "5 seconds"), $"word")
      .count()//聚合/计算
      .sort("window")//按照窗口时间进行排序



    //5.输出结果
    result.writeStream
      .format("console")//指定往控制台输出
      .outputMode("complete")//输出模式,complete表示每次将所有数据都输出,必须包含聚合
      .option("truncate",false)
      .start()//开启
      .awaitTermination()//等待结束
  }
}

在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_46893497/article/details/114003984