FLink 源码分析--(四)Regular Join(普通join)

文章目录

  • 一、概述
  • 1、SQL Join语义介绍
  • 2、FLink Join实现分类
          • A、Regular Join(普通Join)
          • B、Time Window Join
          • C、Join LETERAL
          • D、维表Join
          • E、Join Temporal Table时态表
  • 二、创建Regular Join相关的物理算子(作为了解)
    • 1、规则Rule
    • 2、physical物理算子
  • 三、Regular Join实例及原理架构
    • 1、普通Join实例
    • 2、原理架构
    • 3、Regular Join特性
  • 四、Join state(存储状态数据结构)

一、概述

1、SQL Join语义介绍

FLink 源码分析--(四)Regular Join(普通join)_第1张图片

INNER JOIN - 内连接,返回满足条件的记录;
LEFT OUTER - 返回左表所有行,右表不存在补NULL;
RIGHT OUTER - 返回右表所有行,左边不存在补NULL;
FULL OUTER -  返回左表和右表的并集,不存在一边补NULL;
CROSS JOIN - 交叉连接,计算笛卡儿积,一般来说代价较大;
SELF JOIN - 自连接,将表查询时候命名不同的别名,进行逻辑变换后,重新连接;

FLink 源码分析--(四)Regular Join(普通join)_第2张图片

INNER OUTER CROSS SELF ON WHERE
Apache Flink Y Y N Y 必选 可选
  • Apache Flink目前主要支持INNER JOIN和OUTER JOIN(LEFT/RIGHT/FULL OUTER)
  • 在语义上面Apache Flink严格遵守标准SQL的语义
  • SELF 可以转换为普通的INNER和OUTER。

2、FLink Join实现分类

在遵循标准SQL语义前提下,对于流计算不同的内部场景,Flink具有不同的实现方式,总结Flink Join有以下五种实现类型:

A、Regular Join(普通Join)
  • 左、右侧新记录或回撤记录,都会去对侧,查找匹配的记录,并影响整个连接结果
  • 如果在左侧有一个新记录,那么它将与右侧所有以前和将来的记录连接起来(反之亦然)
  • 不区分condition里面的时间条件,左右两侧流数据可以长时间保存
B、Time Window Join

也叫做Time Interval Join,即Join条件中,带有时间范围的双流Join,例如订单表和付款表进行补全的场景,付款有1小时时效信息(a.ctime > c.ctime - INTERVAL 1 HOUR)

C、Join LETERAL

右表是一个自定义函数TableFunction实现的视图,遍历进行Join

D、维表Join

分同步和异步两种方式,可以查询数据库数据,补全流中字段信息,例如补全订单用户名场景

E、Join Temporal Table时态表

右表是通过registerTemporalTable注册,join的时候,右表返回指定时间范围内,最新的数据,例如计算汇率的场景(功能和维表类似,在Flink Planner中实现,后续可能会废弃)

二、创建Regular Join相关的物理算子(作为了解)

在下一章节介绍真实处理数据前,我们先简单看下Regular Join涉及的物理算子,知道最终StreamingJoinOperator从何而来

  • 由于这一节比较抽象,仅供了解和参考,读者知道双流Join算子(StreamingJoinOperator)从哪里创建即可
  • 感兴趣的同学可以使用源码自带测试用例(JoinITCase)进行Debug测试和深入分析

1、规则Rule

对应StreamExecJoinRule,具有以下功能:

  • 校验子节点不能具有FlinkLogicalSnapshot(即维表FOR SYSTEM_TIME节点)
  • 校验join条件中不能具有时间比较语句(>=,=,<=)
  • 校验join条件中不能有rowtime字段(通过join字段类型判断)

2、physical物理算子

对应StreamExecJoin,由刚才我们介绍的Rule创建,具有以下功能:

  • 设置consumesRetractions属性,表示是否消费回撤数据
  • 设置producesRetractions属性,表示是否产生回撤数据(left outer/right outer/full outer会产生,inner不会产生)
  • KeySelector(按Key分区设置)、Condition代码生成、创建StreamingJoinOperator,真实处理左、右侧数据

三、Regular Join实例及原理架构

1、普通Join实例

我们以商品价格表和商品名称表为例进行数据处理流程说明

应用场景:实时查看商品价格及商品名称:

SELECT id, price, name FROM Price_Table A
Left Outer JOIN Name_Table B
ON A.id = B.id
  • 左侧商品价格随时间会发生变化
  • 右侧商品名称表,可以输入商品修改后名称

2、原理架构

FLink 源码分析--(四)Regular Join(普通join)_第3张图片
输入数据:

  • ①–⑥号输入数据,代表随时间增加,按顺序输入事件到左、右侧流。
  • ①–⑥号输入数据,可以对应到最右侧Join后输出数据,-号代表回撤,+号代表最新数据
  • 输入数据会更新左、右侧状态数据(内部一般都是MapState实现,如果当前侧为Outer,还会存储引用数,用于计算回撤)

处理数据(见图中#processElement这一部分):

  • 通过joinKey,可以关联成AssocitedRecords(每次处理数据前都会执行)
  • 左右侧数据分别更新leftState、rightState(retract表示删除或计数减1,accumulate表示新增或计数加1)
  • 以左侧一个LeftOuter视图为例:
    1、如果输入消息为Accumulate消息(本例子中输入的都是这类):
    > 如果对侧无关联数据,则往下游发Null值
    > 如果对侧有关联数据,则遍历关联数据,将join结果依次发给下游(消息header为+或者- +两条)
    > 如果对侧也是Outer,则需要将对侧对应的数据引用+1
    2、如果输入消息为Retract消息(本例子中输入无这类消息):
    > 如果对侧无关联数据,则往下游发Null值
    > 如果对侧有关联数据,则遍历关联数据,将join结果依次发给下游(消息header均为-)
    > 如果对侧也是Outer,则需要将对侧对应的数据引用-1

3、Regular Join特性

从普通SQL Join看到,Join条件中不带时间限定字段(a.ctime > c.ctime - INTERVAL 5 MINUTE这种类型):

  • 意味着左右侧状态需要长时间保存
  • 如果一个或两个输入表都在不断增长,那么资源的使用也会无限增长

Flink提供了一个不是非常精确的方式,来限制左右侧状态大小:

即配置minRetentionTime毫秒数(例如一天对应的毫秒数,按数据写入、访问时间,lazy方式清理超时数据)

  • minRetentionTime时间属于SQL TableConfig的一个通用配置,最后创建了StateTtlConfig用来清理MapSatate数据,参考Flink State TTL 概述
  • minRetentionTime时间也用于创建window EmitStrategy对应的allowLateness,来控制window容忍的最大延迟时间(这里不再展开,可以参考Window相关的文章)

四、Join state(存储状态数据结构)

上面图示中,我们多次提到左、右侧状态数据,以及引用计数。
可见状态数据存储十分重要,其实现方式也是双流Join且支持回撤的基础。

你可能感兴趣的:(flink)