00:00
了,其他的步骤其实都非常的简单,包括表的转换,然后进行各种各样的查询,最后写入到外部系统,整个这个流程跟PI的用其实是非常类似的,而里边的具体逻辑呢,我们如果要是对CQ熟悉的话,那是非常简单,直接按照CQ的法把我们想要的逻辑实现出来就可。说有哪些地方比较复杂的话,我们可能会发现表和流的转换,这里反而会有一点麻烦。我们发现了一些之前好像没有接触过的内容,那就是前面我们提到如果把一张表要转换成流,那是需要考虑当前这个表里边是否有更新操作的,那如果说他没有更新操作的话,那么相当于这是一个只在表后边去追加数据,一条一条追加就可以了。那么我们转换过来是一个紧插入流insert on,可以直接调用to date stream方法。
01:07
而如果要是有更新操作的话,那它就必须得是一个更新日志流,要调用tolo STEM方法,那这个过程之前我们好像在任何的地方都没有遇到过,为什么flink会这么别扭,会有这样的一个特殊的要求呢?这个其实是没有办法避免的,主要就是因为本质上我们整个处理的框架是原理是不一样的,诶那就是flink本身,我们说是流式处理,是来一个数据就要处理一次,那自然我们就想到了,对于我们当前的这个每一个任务而言,它是不会去保存之前的所有数据的。那假如说现在我们想要做一个查询的话,很明显我不应该把之前的所有数据都存下来,然后去做这样的一个。做这样的一个批处理,然后得到结果啊,那这样的话我们要存所有的数据,显然对于我们当前的这一个应用而言,代价就太大了,要存放的东西太多了,资源耗费太太大。
02:11
那如果说我们还是这样的流处理,来一个就处理一个的话,很明显它就不适合适用在使用CQ去做表查询的这种场景啊,因为我们知道CQ本身就是出力关系型表,关系型表的话,这样一个二维表结构。它本身不就是有限的数据集吗?诶有了这些这张表,我们才能针对这里面的数据去进行查找嘛,所以我们发现本质上CQ和flink他们是可以说是八字不合,基本理念就不相同。那对于像have Spark这样的工具而言,我们会发现它本身底层就是基于批处理的思路,所以跟CQ可以说就是天然气合在一起的,而flink流处理的框架呢,就会有这样的问题。
03:01
啊,我们这里可以简单的做一个对比,就是关系型表或者是CQ执行的操作,它跟流处理到底有哪些不同。那最简单的区别当然就是处理的数据不一样了,关系表CQ它其实类似于处理。我们处理的是。字段元组的一个有界集合啊,因为这就是我们当前这张表里面的数据,应该是所有数据都到齐了,然后我们才做查询嘛,哎,那所以这张表里边所有行数据。每一行都是一个肉类型,我们说肉可以看作一个特殊的元组类型,哎,那所以这就是很多个肉,很多个元组的有界集合。而对于流处理而言的话,如果说我们把流处理里边每一条数据也看成一个字段元组的组合的话,哎,那我们知道当前我们是来一条处理一条,当前它是无限的。
04:01
我们进行流处理,并不能直接获取到当前所有的数据,这是最大的区有界和无界的区别。另外那就是接下来如果我们想要执行一个类似于CQ的查询的话,诶,那我们就发现了关系表这个有界的范围内去做查询,当然我们可以访问到完整的数据了。而如果我们针对一个理由要去执行一个CQ查询的话。很显然,我们是没有办法访问到当前所有数据的。所以我们只能是持续的等待输入,而且我们的原则也应该是来一个数据就处理一个数据啊,那当前我们就应该是来一个数据,执行当前的这个CQ。在之前所有数据的基础上得到当前的一个结果啊,那那我们知道,那你要不要保存之前所有的历史数据呢?当然不需要,这就要看我当前对应的这个呃,改变是什么样了,如果说我当前当前来了一个数据,只是针对这条数据做了一个改变,那相当于我当前的表里面就是插入了一条新的数据嘛。
05:11
那对应我这条CQ的输出,是不是也是只把插入的这一条数据输出就行了呢?诶,所以当前我的流处理应该是没有办法访问到当前所有的数据,而且也不会去把之前所有的数据保存下来,我就只针对当前的一条数据去进行更新操作。就是对之前的那个结果表进行一个更新操作,所以我们不能做完一次这个查询之后直接就停下来,我必须持续的等待流失输入。而且要。根据收到的数据不停的更新,查询结果永远不停止啊,所以查询的终止条件也是不一样啊,就是之前我们这个关系表里边,那就是一次查询吧,有可能我们数据量很大的话,有可能还有这个表的照影啊,照用起来做查询可能要运行很久,但是只要只要是我们这个机器性能还还可以啊,它总还是能够运行完成的,总有一个结结束的时间点。
06:16
那对于流处理呢?如果输入不停,我们的这个查询就永远不会停止。结果表永远在更新,这就是他两者之间最大的区别。所以接下来我们就要介绍一下在流处理当中,它的表和CQ查询的一些特点,以及一些比较特殊的概念。首先我们要抛出的一个概念是所谓的动态表dynamic table啊,那为什么会说提出一个动态表的概念呢?因为前面我们已经发现了。这个流里边进行表的查询,它的原则其实是什么呢?他还是要来一条数据就处理一下这张表,来一条数据处理一下这张表,那我们知道当前这个流数据流处理里边又不能把历史数据,所有的数据都保存下来,而且我们也不能获取到一下子获取到所有的数据,那怎么办呢?那就只能是不停的更新当前的这张表。
07:17
啊,那有新数据到来的时候,我们的表里边就插入一行嘛,诶,所以这样的一个连续不断的去更新一张表的过程,这个表它就会不停的变化,所以当前的表就不是固定好的静态的一个一张表,而是一个动态变化的表。这种表我们就把它叫做动态表。啊,那动态表其实是flink在进行table API和CQ处理过程当中的一个核心概念啊。如果我们能够真正的理解动态表示什么东西的话,那其实就可以理解为什么之前会出现所谓的changelo STEM这样的一个一种特殊的东西了。
08:04
有了这样一个概念。他就为。一个流式的数据转换成表进行处理,或者说表能够再返回来转换成流,提供了一个底层的支持,因为我们一般熟悉的是表拿来做批处理吧,那现在的话,这个表里面的数据在实时的变化,那我们如果要是有了动态表的概念的话,就可以对它进行。类似于批处理的一个实时的流处理了。多提一句的就是这个动态表的概念,其实我们应该也并不陌生,因为数据库里边的表我们知道啊,从一开始create table,然后把这个table create table,其实只是把这个table的基本架构啊,就是我们所说的STEM定义好了,里边其实一开始是没有任何数据的,所以真正表里边的数据,它其实就是一系列的insert update delete,就是我们所说的增删改查,呃,不需要查,对吧,就是增删改语句执行的结果。
09:10
那对于这个关系型数据库啊,我们一般其实是有这样的一个日志去记录这些所有的操作的,这个日志我们就叫做更新日志啊,那所以这个更新日志流本身在所有的关系数据库里边也有类似的这样一个概念啊,那我们知道很多数据库它去做这个备份,去进行呃,Ha相关的这样一个高可用的配置的时候呢。其实也就是保存着当前数据库的一个更新日志流啊,那当前如果说我们保存下来了某一时刻的一个快照啊,就类似于我们之前说做检查点的时候的那个那个状态啊,只不过当时我们是把状态做一个保存,做一个快照,现在我们就是把某一时刻这张表的所有数据先做一个快照,然后接下来诶,再把所有接下来做的操作这个更新日流得到,那其实我们就可以知道。
10:08
接下来的这张表会怎么样变化,然后最终会变成一个什么样?啊,所以这个在数据库里边啊,它的,呃,包括这个更新,包括回滚,包括这个数据库备份啊,所有的这些操作都是基于更新日志的,而且在很多关系型数据里边啊,比方说这个就高级的这个关系数据里,像DB two Oracle这些数据啊,它里面都有一个物化视图的概念,这个物化视图呢,是可以用来存储CQ查询的中间结果的,是缓存起来的一个结果,那么这个物化视图的更新过程,其实就是一个不停的处理更新日志流的这样的一个过程。所以flink里边的动态表,我们可以认为就是一个类似于物化视图的东西,它就是基于更新日志流构建出来的一张表。
11:05
那有了动态表的概念,接下来顺理成章的我们就要介绍一个持续查询的概念。因为我们知道。正常情况下我们一张表,呃,里边因为它的数据是有借的,那我们执行一条CQ的话。当然就最后可以得到也是得到一个有界的结果集啊,然后当前的这个C查询就结束了,这是我们比较习惯的基于静态表的进行批处理,类似于批处理的查询。那对于动态表,如果我们想要执行一句CQ会变成什么样子呢?啊,因为当前的动态表在不停的有更新操作,有可能是插入,有可能是前面我们说的更新啊,要修改之前的某一条数据,数据在不停的变化,那所以我们当前这个C6查询的结果呢。也在不停的变化,就相当于我们这个CQ不能执行一下就直接完成,而是要不停的执行每一次执行,那就相当于是前面每来一条数据,我们原始的那张表每来一条数据,每更新一次,当前这个CQ就要执行一次,然后就会得到一个新的结果表,哎,那我们就知道了,新的结果表呢,我也不要完整的把它保存下来,也是去做更新操作就可以了。
12:24
啊,这样的话,我们的这个查询就会随着新数据的到来不停的进行,然后不停的更新结果表,这个过程就叫做持续查询。而持续查询的结果,因为这张表也在不停的更新嘛,所以当然也就是一个动态表。一个动态表执行CPU,那么执行起来的就是一个持续查询,得到的还是一个动态表。本质上来说的话,那持续查询我们可以看作是很多个查询连起来的一整套查询的过程,那每一次查询是怎么样触发的呢?其实都是原始的这个输入表里边,诶,我们这里边要执行一个CQ啊,然后得到一个结果表,其实都是输入表里边有数据来了,那么接下来这个CQ就要执行一次啊,那每来一次就执行一次,那执行的时候呢,相当于就是针对当前这个输入表的一个快照当前的样子执行了一个有界的查询。
13:28
得到了最终的这个结果表,当然了,最后我们是对结果表做了一个更新,我们的输出,流逝的输出,只输出这个更新的结果就可以了。最终还是一个动态,那这个过程就相当于这是一个不停的做快照的过程,就像动画一样,每一帧的静静止画面连接起来,最终就拼成了我们完整的一个动态的结果。这就是动态表和持续查询的概念啊,那下面这张图我们就可以看的更加的清楚,就描述了持续查询的全过程,首先一开始我们应该是得到的是一个流,那这个流如果说我们想要调用table API去进行。
14:12
进行这个查询转换的话,那底层会怎么样呢?底层肯定是先把它要转换成一个动态表。注意这里并不是我们显示的啊,就是直接要调那个from data stream,然后直接得到一个table对象,不是这样的,那个是我们在代码里边把data转换成了table,这个是说的flink table API底层要真正意义上做的解析转换,它真的是这样去做的。我们本身拿到的还是流,还是数据流,哎,那首先要把它解析成一个动态表,然后基于这张动态表,我们要去执行CQ,那这个CQ其实就是一个持续查询。持续查询的过程,我们可能中间要保存一些状态,诶,那要注意我们保存的只是状态,并不需要保存之前所有的数据,为什么要保存状态呢?那就是说假如说我们当前是要统计一个count值的话。
15:09
那很显然我就不能是是当前这个初始的数据来一条,我就输出一条追加在后面就完了,哎,那不能只只基于当前数据去做计算了,我要更改之前的那个统计结果,那显然count之前应该有一个聚合的值啊,就是之前的这个CT是有一个值的,我们要把它当成状态保存下。啊,那基于这个状态,我当然就可以输出当前更新的结果,得到一个新的动态表。那最后新的动态表又可以以。更新日志流changelog stream的形式,再把它转换成一个流啊,那这样的话,我们看到从外边看的话还是一个流处理,而内部我们就可以直接执行CQ。这就是整个这个完整的过程,我们调用的table API和flink CQ,其实就是把中间的这一部分完全封装起来,让我们去执行CQ的过程。
16:13
看起来我们好像是直接针对流处理做了一个CQ的查询。
我来说两句