![86089c4ff05e9f1f57aaf41b3086c94f.png](https://i-blog.csdnimg.cn/blog_migrate/f2b2146b16c51c7e70899703374b1731.jpeg)
JOIN
自从Stream pipeline解决方案地成熟,流操作和关系型表结构操作的差距越来越小了。我们通过Flink这样的框架,可以进行高吞吐量的数据流执行非常密集的数据处理,例如:join、filter、aggregation。所以,接下来我们就来看看Flink的Stream join。
在介绍Stream join之前,我们先来回顾一下关系型数据的Join、以及数仓维度建模的Join。
RDBMS Join
在学习关系型数据库时,就对关系型数据库的JOIN非常熟悉。RDBMS中,一般有很多表,而为了满足范式设计,我们会将数据分开在不同的表中存储。而我们获取数据的时候,需要将这些表的数据集中起来,这时候,我们就要使用JOIN了。
MySQL支持多种JOIN,例如:LEFT JOIN、RIGHT JOIN、INNER JOIN。而每一种JOIN具备不同特点。
数仓维度建模Join
在数据仓库设计中,我们一般会采用维度建模方式,而事实表中有大量的维表外键ID以及大量指标。通过维度表外键ID,我们可以和维度表进行关联,然后通过不同维度来统计计算指标。
流Join
在实时处理中,事实数据(Event)源源不断地流入到Kafka中,这些事实数据可能是来自于网页中的用户访问日志、也有可能是MySQL中进行操作的binlog日志,但基本上可以确认的是,在这个事件流中,不是所有的数据都是完整的。绝大多数场景,原始日志数据需要和外部存储系统中的一些数据进行关联之后,才能得到更完整的数据。
为了进行数据的实时处理,我们需要在流处理系统将数据进行关联处理,才能得到最完整的数据。我们怎么样关联呢?假设,我们需要在Flink中进行实时指标统计,也就是我们需要用事件流中的数据与存储在MySQL中的维表在Flink流处理系统中进行关联。如何处理?
这里有三种方式:
- 使用DataStream的API,我们可以使用connect操作,然后再使用RichFlatMapFunction或者是CoProcessFunction来手动实现Join,它们可以将数据保持在state中,在CoProcessFunction中可以使用计时器,定时进行数据的关联,然后定期清理过期的state。
2、使用Table API,我们自己实现一个UDTF来访问维表
3、使用流JOIN来实现
我们这里,重点就来讲讲Flink中非常重要的流JOIN操作。在Flink中,流Join主要有两种,一种是Window Join,还有一种是Interval Join。我们先来看看Window Join。
Window JOIN
Window Join将流中两个key相同的元素联结在一起。这种联结方式看起来非常像inner join,两个元素必须都存在,才会出现在结果中。
在Flink中,分为有三种不同类型的典型窗口:滚动窗口、滑动窗口、会话窗口。我们以窗口的类型分开讲解。
在执行窗口join时,会将所有key能够匹配上、且处在同一个滚动窗口的事件进行join,join之后传递到JoinFunction或者FlatJoinFunction。这种join看起来就像是INNER JOIN,滚动窗口operator不会将一个在某个流中,而在另一个流中不存在的元素发送到下游。
![92cffe732b12e9690e5642290571d5ed.png](https://i-blog.csdnimg.cn/blog_migrate/85908464195a54cfbae2acab14314e9c.jpeg)
上述图,表示两个流进行滚动窗口join,我们发现,只要是两个流中都有的元素,才发生了join操作。
来做个案例:
使用两个指定Source模拟数据,一个Source是订单明细,一个Source是商品数据。我们通过window join,将数据关联到一起。
1、先将Flink的依赖导入进来
<repositories>
<repository>
<id>aliyunmaven</id>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</repository>
</repositories>
<properties>
<flink-version>1.12.0</flink-version>
<scala-version>2.12</scala-version>
<mysql-version>5.1.47</mysql-version>
&l