Flink-SQL源码解读(一)window算子的创建的源码分析

本文详细介绍了Apache Flink 1.9版本中,针对流处理的WindowOperator算子的创建架构,包括逻辑计划、物理计划的生成以及WindowAssigner和Trigger的使用。内容涵盖windowOperator算子的创建、StreamExecGroupWindowAggregateRule的匹配过程,以及WindowOperator如何处理数据和触发计算。
摘要由CSDN通过智能技术生成

本文大体框架参考 https://blog.csdn.net/LS_ice/article/details/90711744

flink版本:1.9

Intro

作为无限流的核心机制,流可以分割为大小有限的窗口,通过在窗口内进行聚合。把源源不断产生的数据根据不同的条件划分成一段一段有边界的数据区间,使用户能够利用窗口功能实现很多复杂的统计分析需求。

windowOperator算子的创建架构

window语法主要是在group by语句中使用,calcite创建WindowOperator算子伴随着聚合策略的实现,包括聚合规则匹配(StreamExecGroupWindowAggregateRule),以及生成聚合physical算子StreamExecGroupWindowAggregate两个子流程

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

上图内部流程分析:
应用层SQL:
1.1 window分类及配置,包括滑动、翻转、会话类型窗口
1.2 window时间类型配置,默认待字段名的EventTime,也可以通过PROCTIME()配置为ProcessingTime
Calcite解析引擎:
2.1 Calcite SQL解析,包括逻辑、优化、物理计划和算子绑定(#translateToPlanInternal),在本文特指StreamExecGroupWindowAggregateRule和StreamExecGroupWindowAggregate物理计划
WindowOperator算子创建相关:
3.1 StreamExecGroupWindowAggregate#createWindowOperator创建算子
3.2 WindowAssigner的创建,根据输入的数据,和窗口类型,生成多个窗口
3.3 processElement()真实处理数据,包括聚合运算,生成窗口,更新缓存,提交数据等功能
3.4 Trigger根据数据或时间,来决定窗口触发

StreamExecGroupWindowAggregateRule

/home/graviti/flink/flink-table/flink-table-planner-blink/src/main/scala/org/apache/flink/table/planner/plan/rules/physical/stream/StreamExecGroupWindowAggregateRule.scala

会对window进行提前匹配,生成的WindowEmitStrategy内部具有:是否为EventTime表标识、是否为SessionWindow、early fire和late fire配置、延迟毫秒数(窗口结束时间加上这个毫秒数即数据清理时间)获取聚合逻辑计划中,window配置的时间字段,记录时间字段index信息,window的触发和清理都会用到这个时间

2.1 match匹配是否是group by 语句

  override def matches(call: RelOptRuleCall): Boolean = {
    val agg: FlinkLogicalWindowAggregate = call.rel(0)

    // check if we have grouping sets
    val groupSets = agg.getGroupType != Group.SIMPLE
    if (groupSets || agg.indicator) {
      throw new TableException("GROUPING SETS are currently not supported.")
    }

    true
  }

2.2 生成WindowEmitStrategy 包含window的一些配置属性

/home/graviti/flink/flink-table/flink-table-planner-blink/src/main/scala/org/apache/flink/table/planner/plan/utils/WindowEmitStrategy.scala

object WindowEmitStrategy {
  /**是否为EventTime表标识、
   * 是否为SessionWindow、
   * early fire和late fire配置、
   * 延迟毫秒数(窗口结束时间加上这个毫秒数即数据清理时间)
   * 是否允许延迟
   * @param tableConfig
   * @param window
   * @return
   */
  def apply(tableConfig: TableConfig, window: LogicalWindow): WindowEmitStrategy = {
    val isEventTime = isRowtimeAttribute(window.timeAttribute)
    val isSessionWindow = window.isInstanceOf[SessionGroupWindow]

    val allowLateness = if (isSessionWindow) {
      // ignore allow lateness in session window because retraction is not supported
      0L
    } else if (tableConfig.getMinIdleStateRetentionTime < 0) {
      // min idle state retention time is not set, use 0L as default which means not allow lateness
      0L
    } else {
      // use min idle state retention time as allow lateness
      tableConfig.getMinIdleStateRetentionTime
    }
    val enableEarlyFireDelay = tableConfig.getConfiguration.getBoolean(
      TABLE_EXEC_EMIT_EARLY_FIRE_ENABLED)
    val earlyFireDelay = getMillisecondFromConfigDuration(
      tableConfig, TABLE_EXEC_EMIT_EARLY_FIRE_DELAY)
    val enableLateFireDelay = tableConfig.getConfiguration.getBoolean(
      TABLE_EXEC_EMIT_LATE_FIRE_ENABLED)
    val lateFireDelay = getMillisecondFromConfigDuration(
      tableConfig, TABLE_EXEC_EMIT_LATE_FIRE_DELAY)

    new WindowEmitStrategy(
      isEventTime,
      isSessionWindow,
      earlyFireDelay,
      enableEarlyFireDelay,
      lateFireDelay,
      enableLateFireDelay,
      allowLateness)
  }

下面是convert函数的完整实现

大概分为三个部分:

  • 生成WindowEmitStrategy
  • 生成时间字段index信息,window的触发与清理都会用到这个时间
  • 调用StreamExecGroupWindowAggregate,创建算子
override def convert(rel: RelNode): RelNode = {
    val agg = rel.asInstanceOf[Fl
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值