Flink的时间特性和窗口计算

Flink的时间特性和窗口计算

时间特性

在 TableAPI 或者 SQL 要使用基于时间的操作,需要定义相关的时间语义和时 间数据来源的信息。所以,Table 可以提供一个额外的逻辑上的时间字段,用于 在表处理程序中,指示时间和访问相应的时间戳。
时间属性,可以是每个表 schema 的一部分。一旦定义了时间属性,它就 可以作为一个字段引用,并且可以在基于时间的操作中使用。时间属性的行为类 似于常规时间戳,可以访问,并且进行计算。

定义处理时间(Processing Time)

处理时间语义下,允许表处理程序根据机器的本地时间生成结果。它是时间 的最简单概念。它既不需要提取时间戳,也不需要生成 watermark。 定义处理时间属性有两种方法:

val bsEnv = StreamExecutionEnvironment.getExecutionEnvironment
    bsEnv.setParallelism(1)
    val bsSettings = EnvironmentSettings.newInstance().useBlinkPlanner().inStreamingMode().build()
    val bsTableEnv = StreamTableEnvironment.create(bsEnv, bsSettings)


    val dataStream: DataStream[TrainAlarm] = bsEnv.readTextFile("D:\\Note\\Projects\\02\\Flink\\cha01\\file\\train2.txt")
      .map(line => {
        val splits = line.split(",")
        TrainAlarm(splits(0), splits(1).toLong, splits(2).toDouble)
      })

1.在 DataStream 转化为table时直接指定
♥♥注意:只能在 schema 定义的末尾来定义Processing Time

val table1 = bsTableEnv.fromDataStream(dataStream,'id,'ts,'temp,'pt.proctime())

2.在创建表 的 DDL 中指定

val table2: TableResult = bsTableEnv.executeSql(
      """
        create table t_person(
         name string,
         ts bigint,
         salary bigint,
         city string,
         pt AS PROCTIME()
        ) with (
         'connector' = 'filesystem',
         'path'='file:///D:\Note\Projects\02\Flink\cha01\file\flink_person.txt',
         'format' = 'csv'
        )
      """.stripMargin)

定义事件时间(Event Time)

在DataStream转换为Table的时候指定

val dataStream: DataStream[TrainAlarm] = bsEnv.readTextFile("D:\\Note\\Projects\\02\\Flink\\cha01\\file\\train2.txt")
      .map(line => {
        val splits = line.split(",")
        TrainAlarm(splits(0), splits(1).toLong, splits(2).toDouble)
      })
      .assignTimestampsAndWatermarks(
        WatermarkStrategy.forBoundedOutOfOrderness(Duration.ofSeconds(2))
          .withTimestampAssigner(new SerializableTimestampAssigner[TrainAlarm] {
            override def extractTimestamp(element: TrainAlarm, recordTimestamp: Long): Long = {
              element.ts * 1000L
            }
          })
      )

    val table1 = bsTableEnv.fromDataStream(dataStream,'id,'ts.rowtime(),'temp)

在创建表的时候指定

val table2: TableResult = bsTableEnv.executeSql(
      """
        create table t_person(
         name string,
         ts bigint,
         salary bigint,
         city string,
         rt AS TO_TIMESTAMP( FROM_UNIXTIME(ts) ),
         WATERMARK FOR rt AS rt - INTERVAL '1' SECOND
        ) with (
         'connector' = 'filesystem',
         'path'='file:///D:\Note\Projects\02\Flink\cha01\file\flink_person.txt',
         'format' = 'csv'
        )
      """.stripMargin)

窗口计算

在 Table API 和 SQL 中,主要有两种窗口:Group Windows 和 Over Windows

分组窗口Group Windows

分组窗口(Group Windows)会根据时间或行数间隔,将行聚合到有限的组 (Group) 中,并对每个组的数据执行一次聚合函数。
Table API 中的 Group Windows 都是使用.window子句定 义的,并且必须由 as 子句指定一个别名。为了按窗口对表进行分组,窗口的别名必须在 group by 子句中,像常规的分组字段一样引用。

val table = input 
.window([w: GroupWindow] as 'w) // 定义窗口,别名 w 
.groupBy('w, 'a) // 以属性 a 和窗口 w 作为分组的 key 
.select('a, 'b.sum) // 聚合字段 b 的值,求和
1.TableAPI 实现 Group Windows

滚动窗口(Tumbling windows)要用 Tumble 类来定义,另外还有三个方法:
over:定义窗口长度
on:用来分组(按时间间隔)或者排序(按行数)的时间字段
as:别名,必须出现在后面的 groupBy 中

// Tumbling Event-time Window(事件时间字段 rowtime) 
.window(Tumble over 10.minutes on 'rowtime as 'w) 
// Tumbling Processing-time Window(处理时间字段 proctime)
.window(Tumble over 10.minutes on 'proctime as 'w) 
// Tumbling Row-count Window (类似于计数窗口,按处理时间排序,10 行一 组) 
.window(Tumble over 10.rows on 'proctime as 'w)

滑动窗口(Sliding windows)要用 Slide 类来定义,另外还有四个方法: over:定义窗口长度
every:定义滑动步长
on:用来分组(按时间间隔)或者排序(按行数)的时间字段
as:别名,必须出现在后面的 groupBy 中

// Sliding Event-time Window 
.window(Slide over 10.minutes every 5.minutes on 'rowtime as 'w) // Sliding Processing-time window 
.window(Slide over 10.minutes every 5.minutes on 'proctime as 'w) // Sliding Row-count window 
.window(Slide over 10.rows every 5.rows on 'proctime as 'w)

会话窗口(Session windows)要用 Session 类来定义,另外还有三个方法:
withGap:会话时间间隔
on:用来分组(按时间间隔)或者排序(按行数)的时间字段
as:别名,必须出现在后面的 groupBy 中

// Session Event-time Window 
.window(Session withGap 10.minutes on 'rowtime as 'w) 
// Session Processing-time Window 
.window(Session withGap 10.minutes on 'proctime as 'w)

案例:

	val bsEnv = StreamExecutionEnvironment.getExecutionEnvironment
    bsEnv.setParallelism(1)
    val bsSettings = EnvironmentSettings.newInstance().useBlinkPlanner().inStreamingMode().build()
    val bsTableEnv = StreamTableEnvironment.create(bsEnv, bsSettings)



    val dataStream: DataStream[TrainAlarm] = bsEnv.readTextFile("D:\\Note\\Projects\\02\\Flink\\cha01\\file\\train2.txt")
      .map(line => {
        val splits = line.split(",")
        TrainAlarm(splits(0), splits(1).toLong, splits(2).toDouble)
      })
      .assignTimestampsAndWatermarks(
        WatermarkStrategy.forBoundedOutOfOrderness(Duration.ofSeconds(2))
          .withTimestampAssigner(new SerializableTimestampAssigner[TrainAlarm] {
            override def extractTimestamp(element: TrainAlarm, recordTimestamp: Long): Long = {
              element.ts * 1000L
            }
          })
      )
	val table1 = bsTableEnv.fromDataStream(dataStream,'id,'ts.rowtime().as("rt"),'temp)
        .window(Tumble.over(10.seconds()).on('rt).as("w"))
        //.window(Slide.over(10.seconds()).every(2.seconds()).on('rt).as("w"))
        //.window(Session.withGap(10.seconds()).on('rt).as("w"))
        .groupBy('id,'w)
        .select('id,'id.count(),'w.end(),'temp.max())
   bsTableEnv.toAppendStream[Row](table1).print()
   bsEnv.execute()
2.SQL 实现 Group Windows

Group Windows 在 SQL 查询的 Group BY 子句中定义。与使用常规 GROUP BY 子句的查询一样,使用 GROUP BY 子句的查询会计算每个组的单个结果行。
SQL 支持以下 Group 窗口函数:
TUMBLE(time_attr, interval) 定义一个滚动窗口,第一个参数是时间字段,第二个参数是窗口长度。
HOP(time_attr, interval, interval) 定义一个滑动窗口,第一个参数是时间字段,第二个参数是窗口滑动步长,第三个是窗口长度。
SESSION(time_attr, interval) 定义一个会话窗口,第一个参数是时间字段,第二个参数是窗口间隔(Gap)。

TUMBLE_START(time_attr, interval)
TUMBLE_END(time_attr, interval)
TUMBLE_ROWTIME(time_attr, interval)
TUMBLE_PROCTIME(time_attr, interval)

案例:

val table2: TableResult = bsTableEnv.executeSql(
      """
        create table t_person(
         name string,
         ts bigint,
         salary bigint,
         city string,
         rt AS TO_TIMESTAMP( FROM_UNIXTIME(ts) ),
         WATERMARK FOR rt AS rt - INTERVAL '1' SECOND
        ) with (
         'connector' = 'filesystem',
         'path'='file:///D:\\Note\\Projects\\02\\Flink\\cha01\\file\\flink_person.txt',
         'format' = 'csv'
        )
      """.stripMargin)

    val sqlResult = bsTableEnv.sqlQuery(
      """
        select
          name,
          count(name) cnts,
          tumble_end(rt,interval '10' second) win_end,
          max(salary)
        from t_person
        group by name,tumble(rt,interval '10' second)
      """.stripMargin)

    bsTableEnv.toAppendStream[Row](sqlResult).print()

    bsEnv.execute()
Over Windows

Over window 聚合是标准 SQL 中已有的(Over 子句),可以在查询的 SELECT 子句中定义。 Over window 聚合,会针对每个输入行,计算相邻行范围内的聚 合。Over windows 使用.window子句定义,并在 select() 方法中通过别名来引用。

TableAPI 实现 Over Windows
val bsEnv = StreamExecutionEnvironment.getExecutionEnvironment
    bsEnv.setParallelism(1)
    val bsSettings = EnvironmentSettings.newInstance().useBlinkPlanner().inStreamingMode().build()
    val bsTableEnv = StreamTableEnvironment.create(bsEnv, bsSettings)


    val dataStream: DataStream[TrainAlarm] = bsEnv.readTextFile("D:\\Note\\Projects\\02\\Flink\\cha01\\file\\train2.txt")
      .map(line => {
        val splits = line.split(",")
        TrainAlarm(splits(0), splits(1).toLong, splits(2).toDouble)
      })
      .assignTimestampsAndWatermarks(
        WatermarkStrategy.forBoundedOutOfOrderness(Duration.ofSeconds(2))
          .withTimestampAssigner(new SerializableTimestampAssigner[TrainAlarm] {
            override def extractTimestamp(element: TrainAlarm, recordTimestamp: Long): Long = {
              element.ts * 1000L
            }
          })
      )
val table1 = bsTableEnv.fromDataStream(dataStream,'id,'ts.rowtime().as("rt"),'temp)
      .window(Over.partitionBy('id).orderBy('rt).preceding(2.rows).as("ow"))
      .select('id,'temp.avg() over 'ow)

     bsTableEnv.toAppendStream[Row](table1).print()
     bsEnv.execute()
SQL 实现 Over Windows
 val table2: TableResult = bsTableEnv.executeSql(
      """
        create table t_person(
         name string,
         ts bigint,
         salary bigint,
         city string,
         rt AS TO_TIMESTAMP( FROM_UNIXTIME(ts) ),
         WATERMARK FOR rt AS rt - INTERVAL '1' SECOND
        ) with (
         'connector' = 'filesystem',
         'path'='file:///D:\\Note\\Projects\\02\\Flink\\cha01\\file\\flink_person.txt',
         'format' = 'csv'
        )
      """.stripMargin)

    val sqlResult = bsTableEnv.sqlQuery(
      """
        select
          name,
          avg(salary) over ow,
          max(salary) over ow
        from t_person
        window ow as (
          partition by name
          order by rt
          rows between 2 preceding and current row
        )
      """.stripMargin)

    bsTableEnv.toAppendStream[Row](sqlResult).print()

    bsEnv.execute()

你可能感兴趣的:(flink,sql,数据库)