00:00
我们已经了解了connect的所有用法啊,那我们会发现啊,确实是非常非常的强大,它可以灵活的定义K,按照K把两条流数据进行连接匹配,另外呢,还可以在合并之后调用process方法实现对应的处理函数。设置定时器使用状态编程啊,那基本上就可以实现我们所有的需求了,可以说connect就是flink当中最为通用也是最为强大的河流操作。对于我们很多数据分析的场景而言啊,大家可能熟悉的是在关系表里边,哎,我们定义两张表,然后定义了他们里边数据结构啊,每一个字段到底是什么样的,然后呢,诶,可能希望对这两张表做一个draw。那这种操作呢,其实使用connect就可以非常轻松的解决,哎,那这里边我们指定连接的那个K。在connect里边,我们只要K就可以完成了,而且connect还可以定义状态,还可以使用定时器,对于时间的操控也会更加的强大,诶,那不过我们会发现啊,在这个过程当中,Connect是很强大,但是呢,我们实现一个具体需求的时候,可能需要自己定义的逻辑就会非常非常的多,特别是涉及到时间相关操作的时候,就像我们之前在比如check这里边啊,我们涉及到时间相关操作的话,对于状态的控制。
01:31
整个这个逻辑的判断就会特别特别的复杂,我们这里其实已经是一个非常简单的场景了,如果当前的状态更多的话,可能本身对于状态的控制就会把我们的逻辑搞乱。那对于一些常见的跟时间有关的场景,能不能有更加简单易用的接口来直接调用,直接实现呢?哎,当然是有的,所以接下来我们要介绍的就是flink当中另外一类比较特殊的河流操作,那就是基于时间的河流啊,有时候我们把它叫做双流连接操作啊,本质上来讲,这一节我们主要讲的就是所谓的状,那状语在C课里面啊,我们讲这个关型表的时候,一般它就翻译成连接操作了,我们现在是为了区别draw和connect,所以呢把connect叫做连接,而把draw翻译成了连接。好,那后边的话我们就直接说英文啊,说这个connect join就可以了,因为底层的代码里边实现其实就是这两个词,我们只要知道他做的是什么事就可以。
02:39
啊,那首先呢,我们要介绍的就是窗口连接操作window draw,那我们知道基于时间的操作,最经典的当然就是时间窗口操作了,诶,那之前我们都已经介绍过了window API。那现在如果想把window API类似的那些操作应用到两条流的连接操作上,接下来又应该怎么做呢?Link呢,为这种场景就专门提供了一个window draw这样的一个算子啊,那它就可以让两个data stream进行连接操作之后,接下来直接打开一个窗口去对同一个K的所有匹配的数据进行统一处理啊,那这里的所谓的匹配是怎么样去匹配呢?啊,那如果说我们这里有两条流。
03:27
要进行一个连接操作的话,而且还打开了一个时间窗口的话,那就是首先。我们知道开窗的话肯定是要指定K的,首先按同一个K进行分组,然后呢,在所有K的数据里边,按照时间窗口把它做一个划分,那么收入同一个窗口里边的同一个K的所有数据,那就进行两两匹配。这就相当于要做一个笛卡尔基的配对,接下来他们配对的这样一个二元组的形式,就会作为我们接下来处理的标准数据结构,哎,那最终处理完成之后,就得到了一个新的数据流。
04:11
这就是简单来讲啊,Window draw窗口连接的一个基本思路,那接下来呢,我们就看一看它的调用方式到底是怎么调的,这种方式呢,比connect看起来就会复杂一点,但是呢,它的调用方式复杂,事实上呢,给我们省去了很多自定义的麻烦,哎,那所以就是给我们都定死了,这个接口就只能按部就班这么去调,我们看一下到底怎么调呢?基于一个data stream,直接调一个点join方法,那传入的参数当然就是另外一个data stream了,然后接下来只能调一个点where方法啊,那where方法里边指定的是一个key select,那当然了,这个意思就是说where第一条流里的K到底是什么?
05:00
然后equal two。又是一个k select,当然就是键等于什么?哎,那当然就是第一条流里边的键字段等于第二条流里边的键字段啊,那这个操作这就非常像我们写CQ做两张表的连接的时候,那就写一个啊select什么FROM2张表里边,哎,那然后我们后边会定义一个连接的条件,On什么等于什么啊,所以这里边它是where什么,Equal to什么。然后后边呢,上面相当于定义了K了,后边直接开窗点window,然后里边传入的是一个window塞,这就是窗口分配器,那定义了窗口分配器之后,后边当然就是窗口函数了,哎,注意这里的窗口函数呢,只能调用点apply方法。点apply方法里边给的是一个join方式,所以它的所有的这个API的调用和里边传的参数的类型都是定死的,只能按照这种方式去进行使用。
06:08
接下来我们可以到源码当中去看一下,哎,我们直接到data stream这个类里边来。去查看一下当前的状语方法,我们可以看到一个数据流去join引另外一个数据流,他们的数据类型可以不同,得到的数据类型呢?这个叫做join the streams,跟我们之前的connect非常的像,Connect之后得到的是一个connected streams,现在得到的是一个join the streams join the streams能继续调什么方法呢?哎,我们会发现它比connected streams能够调的方法就少太多了,它只能调一个方法,唯一的方法就是这里的where。Where里边传一个当前的K的选择器,一个拉姆达表达式,得到的数据类型是一个叫做where的内部类型啊,然后这个where呢,又只能调一个方法叫e to,这里传入的就是第二个第二条流理的K的选择的这个方法得到的类型呢,又叫做E扣to。
07:09
那接下来的这个子类型,它用能调的方法呢,只有一个window,在当前的基础上做一个开窗操作,定义一个window a sign,然后接下来返回的是一个with window这个类型,那with window最后能够掉的,呃,当然了,这里边我们看到啊with window能调的方法就会多一些,因为相当于我们窗口的可选API在这里就都可以去调用了,Allow the lateness triggeror都可以去调用,那最后真正意义上去实现处理转换计算的这个方法,那就是调点apply,然后里边传入的就是一个drawing function,当然了,我们也可以传入一个longer表达式。本质上就是一个draw方式,那这个draw方式我们点进去可以发现啊,它是一个单一抽象方法的接口,里边呢,只有一个作用方法,抽象方法需要实现,那它的参数印一印二两个数据类型,很显然这就是。
08:11
匹配上的一段数据,第一条流里的一个数据,第二条流里的一个数据,它俩匹配上了,诶,这就会调用这里的作用方法。得到的返回值是一个out类型输出类型的结果,所以整体来讲还是非常简单的,非常容易理解的。刚才我们也看到了,除了状语function之外,呃,Flight方法呢,还可以传别的参数,比如说可以传一个Fla draw语function啊,那flat draw function跟join function又有什么区别呢?很显然,一看这个名字吗?那区别就跟map和flat map的区别一样,那就是我们这里边可以没有返回值,不需要直接返回一个al类型的数据,而是使用一个collect去进行输出数据的定义,也就是说flat装方式更加的灵活,可以输出也可以不输出,可以输出一次也可以输出多次。
09:08
那对应的我们可以在这里看到其他的一些调用方式,那就是可以直接传入一个拉姆达表达式,这就相当于替代了装用方式,那也可以传入一个我们看到三个参数带着的这样一个拉姆达表达式,这就替代了Fla join方式。最终得到的结果,那就又回到了date。接下来我们还是举一个具体的例子来看一看。到底。Window join应该怎么去用吧?创建一个SC的object。现在我们要测的是window test。首先,我们当然还是先要创建执行环境。还是直接叫做env。改成下划线,接下来全局的并行度设成一,方便测试,接下来呢,我们要创建两条流来进行转,这个我们就简单一点啊,就创建还是类似于整数的一些数据吧,关键是我们得指定K,另外呢,还要指定时间戳,因为我们窗口操作显然是跟时间有关的嘛,所以这一部分呢,我们可以设置一个二元组,那就是当前一个字符串类型的K。
10:22
一个字段,然后后边再跟上一个长整型的时间戳,哎,这样的话二元组就可以满足我们这个测试需求啊,这一部分数据的话,我们就直接可以用文档当中。给定的这样一个例子啊,STREAM1我们看到就是AB1000 B1000 a2000B2000啊,那STREAM2的话是AB对应的数据分别在三秒和四秒产生的数据,我们可以直接把它copy过来。那当然了,后边因为涉及到了事件时间的一些操作,那需要去。指定提取时间戳的方法,然后去生成摩曼,我们这里边使用第二个字段作为当前的时间戳,然后接下来就可以直接去做窗口。
11:12
连接操作了啊,那比方说我们现在就定义的这个窗口范围就可以小一点啊,我们就定义一个五秒的窗口吧,因为这个数据本身时间戳都比较小,那我们的调用方式就是STREAM1去draw stream2。然后接下来只能去使用一个where,指定第一条流里的K。那二元组我们用第一个字段作为当前的K,然后只能调e to。第二个流里边同样也是第一个字段是当前的K,然后接下来呢,哎,那就只能调一个window了,我们现在就创建一个。五秒钟的滚动窗口就好了,嗯。Time,这个time我们需要引入window time.time seconds5。
12:01
接下来啊,那就是只能调一个apply操作,如果我们不去用那些window的其他API的话,那接下来就只能使用apply去定义当前的处理操作,那我们现在呢,那就去直接new一个drawing function。当然我们也可以写拉姆达表达式装方式的话,这个看的更加的清楚一点,知道到底我们指定的是什么。那装风呢,它的泛型有三个啊,这跟是非常像的啊,跟Co map function或者Co process function都是非常的类似,所以这里边就是两条流里的数据类型,我们现在的话都是二元组类型S。Strange love。最后的输出类型,哎,那干脆我们还是简单一点,直接输出一个string打印输出就可以了。必须要实现的就是一个join抽象方法,这里边的具体处理逻辑呢,那我们也不用太麻烦了,就把匹配起来配对的两个数据做一个连接输出就完事了。应一。
13:06
加上啊,我们加一个箭头。再加上硬二。这样的话就一目了然,可以看到到底是哪些数据匹配在一起,在窗口当中做了连接,做了匹配,然后得到了输出,然后接下来我们就可以直接点print。指定think任务输出到控制台,最后env execute执行起来,哎,这就是我们整个这个window join窗口连接的测试过程,好,我们可以运行一下看看效果。我们如果是零到五秒的窗口的话,那自然会想到所有的这些数据应该都能连接在一起啊,但是我们看啊,肯定不会是16对儿数据,因为我们想如果要所有数据都匹配的话,那应该就是四乘四了,笛卡耳机嘛,现在呢,只有八条数据输出。那很明显,那就是A只会跟A的数据匹配在一起,B只会跟B的数据匹配在一起,这就是按照K去进行了匹配连接,那我们看到就是第一条流里的A1秒和两秒的数据跟第二条流里A的三秒四秒的数据对应的都有一个连接配对。
14:19
同样,B的数据也是这样。这其实当前我们只有零到五秒一个窗口的数据输出,诶那假如说现在啊,我们改一个数据,比方说我们把这个B2000换成一个6000。最后的这个B4000换成一个B8000,如果我们再来运行一下的话。那就会发现输出跟刚才有所变化。刚才的输出反而更少了一些,诶,这是为什么呢?那是因为零到五秒这个窗口内配对的是有这样的五条数据啊,A的话是有四条数据的,因为A在第一条流里有两条数据落在零到五秒窗口,在第二条流里也有两条数据落在零到五秒窗口啊,K一样,窗口一样,那么就是一个笛卡耳机了,四条数据匹配啊,然后零到五秒窗口里边的B呢,它只有一条数据落在这个窗口里,那当然第二条流里边也只有一条数据,那其实就是一对一,那就只有一条数据了。
15:21
同样道理,五到十秒第二个窗口里的数据呢?在每条流里各自只有一条数据,所以就只有一段数据输出,所以我们会发现,这就是按照相同K相同窗口的原则。我们找到的两条流里的所有数据做一个笛卡尔级的配对,每一个配对的数据都会调用到这里的状语方法来,哎,这就是window状语窗口连接操作它底层的处理流程。这一部分我们就测试完毕了。
我来说两句