FlinkSQL之Flink SQL Join二三事,HR的话扎心了

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新大数据全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注大数据)
img

正文

​ 在正式进入FlinkSQL Join场景研究之前,首先我们先介绍一下在FlinkSQL场景下常见的Kafka数据流分类。截止到Flink1.18为止,目前常见的Kafka数据流包括不含键更新的普通Kafka数据流(即Kafka SQL Connector数据流)和包含键更新的Kafka数据流(即Upsert-Kafka SQL Connector数据流)两种。

1 Regular Join

​ Regular join 是最通用的 join 类型。在这种 join 下,join 两侧表的任何新记录或变更都是可见的,并会影响整个 join 的结果。对于流式查询,regular join 的语法是最灵活的,允许任何类型的更新(插入、更新、删除)输入表。 然而,这种操作具有重要的操作意义:Flink 需要将 Join 输入的两边数据永远保持在状态中。 因此,计算查询结果所需的状态可能会无限增长,这取决于所有输入表的输入数据量。你可以提供一个合适的状态 time-to-live (TTL) 配置来防止状态过大。注意:这样做可能会影响查询的正确性。

​ 左右两边流数据都能驱动join,左侧流新加入数据会和右侧流状态中所有匹配记录join上;同理,右侧流新增数据会和左侧流所有匹配记录join上,外连接不会等待,即使Join不上也会即及时输出,待对侧数据到来通过回撤修复数据。

  • Inner Join

根据 join 限制条件返回一个简单的笛卡尔积。目前只支持 equi-joins,即:至少有一个等值条件。不支持任意的 cross join 和 theta join。

select 
	t1.order_id    as order_id,
	t2.product_id  as product_id,
	t1.create_time as create_time
from tbl_order t1 
join tbl_order_product t2 
	 on t1.order_id = t2.order_id 
;

Inner join不会产生回撤流,source端可以是Kafka SQL Connector也可以试Upsert-kafka SQL Connector,也可以是混合模式,sink端理论均可以是Kafka Connector,但如果输入端有重复输入,输出端可以设置成Upsert-Kafka SQL Connector接收数据。Upsert-Kafka SQL Connector注意设置主键。

  • outer join

返回所有符合条件的笛卡尔积(即:所有通过 join 条件连接的行),加上所有外表没有匹配到的行。Flink 支持 LEFT、RIGHT 和 FULL outer joins。目前只支持 equi-joins,即:至少有一个等值条件。不支持任意的 cross join 和 theta join。

select 
	t1.order_id    as order_id,
	t2.product_id  as product_id,
	t1.create_time as create_time
from tbl_order t1 
left join tbl_order_product t2 
	 on t1.order_id = t2.order_id 
;

select 
	t1.order_id    as order_id,
	t2.product_id  as product_id,
	t1.create_time as create_time
from tbl_order t1 
right join tbl_order_product t2 
	 on t1.order_id = t2.order_id 
;

select 
	t1.order_id    as order_id,
	t2.product_id  as product_id,
	t1.create_time as create_time
from tbl_order t1 
full join tbl_order_product t2 
	 on t1.order_id = t2.order_id 
;

Outer Join会产生回撤流,source端可以是Kafka SQL Connector也可以是Upsert-kafka SQL Connector,也可以是混合模式,sink端理仅支持设置成Upsert-Kafka SQL Connector接收数据。Upsert-Kafka SQL Connector注意设置主键。

  • Regular Join总结应用模式如下(a代表Append-Only流,u代表Upsert-Kafka流):
  • a join a => a|u
  • u join u => a|u
  • a join u => a|u
  • a left join a => u
  • u left join u => u
  • a left join u => u

2 Interval Join

​ 返回一个符合 join 条件和时间限制的简单笛卡尔积。Interval join 需要至少一个 equi-join 条件和一个 join 两边都包含的时间限定 join 条件。范围判断可以定义成就像一个条件(<, <=, >=, >),也可以是一个 BETWEEN 条件,或者两边表的一个相同类型(即:处理时间 或 事件时间)的时间属性 的等式判断。

​ 下面列举了一些有效的 interval join 时间条件:

  • ltime = rtime
  • ltime >= rtime AND ltime < rtime + INTERVAL '10' MINUTE
  • ltime BETWEEN rtime - INTERVAL '10' SECOND AND rtime + INTERVAL '5' SECOND

​ 对于流式查询,对比 regular join,interval join 只支持有时间属性的Append-Only表。 由于时间属性是递增的,Flink 从状态中移除旧值也不会影响结果的正确性,即interval join会根据间隔自动维护状态大小,不丢弃状态也不会让状态无限增长。

  • Inner join
select * 
from tbl_order t1 
join tbl_shopment t2 
	 on t1.order_id = t2.order_id 
	and t1.create_time between t2.create_time - interval '4' hour and t2.create_time
;

​ 输入源只支持Kafka SQL Connector,不支持任何一方回撤流,这也可以理解,因为Interval Join是有时间属性参与Join的。输出数据可以是Kafka SQL Connector也可以试Upsert-kafka SQL Connector。Upsert-kafka SQL Connector要注意键设计。

  • Outer join
select \* 
from tbl_order t1 
left join tbl_shopment t2 
	 on t1.order_id = t2.order_id 
	and t1.create_time between t2.create_time - interval '4' hour and t2.create_time
;

select \* 
from tbl_order t1 
right join tbl_shopment t2 
	 on t1.order_id = t2.order_id 
	and t1.create_time between t2.create_time - interval '4' hour and t2.create_time
;

select \* 
from tbl_order t1 
full join tbl_shopment t2 
	 on t1.order_id = t2.order_id 
	and t1.create_time between t2.create_time - interval '4' hour and t2.create_time
;

​ 输入端仅至此Kafka SQL Connector,不支持任何一方回撤流,这也可以理解,因为Interval Join是有时间属性参与Outer Join的。输出数据可以是Kafka SQL Connector也可以试Upsert-kafka SQL Connector。Upsert-kafka SQL Connector要注意键设计。

  • 注意点

    • 测试要配置并行度为1,否则右表关联不上数据因为水位线识别不到会而不超时输出;
    executionEnvironment.setParallelism(1);
    
    
    • left join右表关联不上输出条件

      • 右表关联数据出现触发输出
      • 超时触发器输出关联不上数据
  • Interval Join总结应用模式如下(a代表Append-Only流,u代表Upsert-Kafka流):

  • a join a => a|u
  • a left join a => a|u

3 Temporal Join(Snapshot Join)

​ 时态表(Temporal table)是一个随时间变化的表:在 Flink 中被称为动态表。时态表中的行与一个或多个时间段相关联,所有 Flink 中的表都是时态的(Temporal)。 时态表包含一个或多个版本的表快照,它可以是一个变化的历史表,跟踪变化(例如,数据库变化日志,包含所有快照)或一个变化的维度表,也可以是一个将变更物化的维表(例如,存放最终快照的数据表)。

  • Inner join
select 
	t1.order_id    as order_id,
	t1.user_id     as user_id,
	t2.user_name   as user_name,
	t1.create_time as create_time
from tbl_order t1 
join tbl_user for system_time as of t1.create_time t2 on t1.user_id = t2.user_id 
;

特点:

+ 左右两边事件时间属性,标识两侧流join场景,如果处理时间请参考Lookup join;
+ 只支持event-time,如果是processing-time那么就变成join最新版本数据,同Lookup Join;
+ 左表支持append流和upsert流;
+ 右表只支持upsert流;
+ 输出可以是append流或者upsert流;
+ 左表触发计算,右表更新不触发计算;
+ 设置超时时间:`tableEnvironment.getConfig().set("table.exec.source.idle-timeout","3s");`;
  • Left join
select 
	t1.order_id    as order_id,
	t1.user_id     as user_id,
	t2.user_name   as user_name,
	t1.create_time as create_time
from tbl_order t1 
left join tbl_user for system_time as of t1.create_time t2 on t1.user_id = t2.user_id 
;

特点:

+ 左右两边事件时间属性,标识两侧流join场景,如果处理时间请参考Lookup join;
+ 只支持event-time,如果是processing-time那么就变成join最新版本数据,同Lookup Join;
+ 左表支持append流和upsert流;
+ 右表只支持upsert流;
+ 输出可以是append流或者upsert流;
+ 左表触发计算,右表更新不触发计算;
+ 设置超时时间:`tableEnvironment.getConfig().set("table.exec.source.idle-timeout","3s");`;
  • Snapshot Join总结应用模式如下(a代表Append-Only流,u代表Upsert-Kafka流):
  • a join u => a|u
  • u join u => u
  • a left join u => a|u
  • u left join u => u

4 Window Join

​ 窗口关联就是增加时间维度到关联条件中。在此过程中,窗口关联将两个流中在同一窗口且符合 join 条件的元素 join 起来。窗口关联的语义和DataStream window join相同。

​ 在流式查询中,与其他连续表上的关联不同,窗口关联不产生中间结果,只在窗口结束产生一个最终的结果。另外,窗口关联会清除不需要的中间状态。

​ 通常,窗口关联和窗口表值函数一起使用。而且,窗口关联可以在其他基于窗口表值函数的操作后使用,例如窗口聚合,窗口 Top-N和窗口关联。

​ 目前,窗口关联需要在 join on 条件中包含两个输入表的 window_start 等值条件和 window_end 等值条件。

​ 窗口关联支持 INNER/LEFT/RIGHT/FULL OUTER/ANTI/SEMI JOIN。

  • 语法
select ...
from l [left|right|full outer] join r -- l and r are relations applied windowing TVF
on l.window_start = r.window_start and l.window_end = r.window_end and ...

  • 注意

    • 当前版本窗口Join必须同时指定window_start和window_end等值条件
    • 窗口Join不支持源是upsert流的情况
  • 限制

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注大数据)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 窗口Join不支持源是upsert流的情况
  • 限制

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注大数据)
[外链图片转存中…(img-2Eg2WCY3-1713123113670)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 9
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值