00:00
要开启的是另外一个崭新的内容,那就是第七章处理函数,之前我讲到的data stream API呢,都基于data stream进行转换,转来转去,最后都是基于它去定义的一系列的算子operator啊,那这些算子呢,就会提炼成一个一个的任务,最后就会转化成任务,然后就会由task manager去执行,这是整个link的最基本的程序,到最终呃,执行过程线程的一个转化架构的流程啊。那如果说我们想要做更多的事情的话,那只能用data stream API吗?呃,当然不仅仅是啊,之前一开始我们就讲过,Flink给我们提供了灵活性非常高的多层API,我们再回忆一下这张图中间核心层API那就是data stream data set,当然data set要被弃用了啊,主要就是data stream API现在批流一体啊,那上层的话,那是大家更加熟悉的那个CQ,这个我们到后边再去讲,这一般就是高级的功能,就是其实我们就是只要会写CQ,然后知道,呃,整个这个程序架构怎么搭啊,那这个其实就不成问题,那另外还有一类API是更加底层的API。
01:14
他操作的呢,就是直接针对有状态的流直接进行处理,所以这个API就叫做处理函数process方式,在函数的定义里面,之前我们data stream API调的是map filter或者K之后聚合,嗯,你去reduce,或者我们开窗之后啊,Aggregate或者这个apply,那现在呢,现在我们根本不考虑它到底是要干什么,因为map你是有一个映射嘛,一一映射的感觉在里边,Filter啊,那你是过滤啊,Window那就更明显了,或者说聚合,对吧,你这个就一看就知道你要干什么操作,现在。根本把这些操作全部抹去,就像泛型擦除一样,完全提炼出来,我就叫他处理操作process。
02:02
啊,所以也就是说基于data stream或者是其他的很多stream都可以调,这个方法就是直接调一个点process。是不是想起之前我们用那个process window function了,基于一个window stream直接调点process。它没有任何具体的含义,他就说处理对吧,我也不知道你要要怎么处理,反正都是所有的逻辑,你自己去定义去吧,啊那所以基于data stream也可以直接调一个点process。而基于K。也可以直接调一个access啊,所以很多的这个流里面都提供了这样的一个接口啊,这样的一个方法,然后呢,里边要传入的不是一个所谓的物理函数,整个这一层接口呢,尽管它也是主要是基于data stream去做转换的,但是呢,它更加底层一些,你像这个window stream,它没有继承自data stream,但是它同样也有这样的方法,所以它是一个更底层的统一的操作,我们把它叫做处理函数process function。
03:07
那这里给大家先说一下,就是处理函数的一些用法和种类吧。啊首先我们先介绍一下最基本的process function处理函数,基本处理函数啊,为什么叫它基本处理函数呢?因为这个函数它本身是个抽象类啊,这个类类名本身就叫process function就叫这个名。啊,那它主要定义的呢?呃,那其实就是说定义了一个统一化抽象出来的一个处理操作,然后呢,呃,就是把所有能拿到的东西都提供给你,你想怎么做,自己去定义吧。所以它灵活度最高,也最底层。那处理函数主要用来干什么呢?简单来讲就是他能够拿到别的API拿不到的东西。哪些东西是我们拿不到的呢?我们回忆一下啊,之前如果说我们想基于时间去做操作的话。现在我们知道的就只有窗口,只能是定义各种各样的窗口来做操作啊,当然了,窗口操作在实际应用当中肯定也是应用最广的,但是假如说我就有特别特殊的需求。
04:12
啊,就是我不是说一定要划分,划分这个窗口,把它画出来,然后去做某些操作,我就是想要单独的去设定一个,比方说九点钟给我去干一个什么事。啊,或者说我来了一个数据之后,我看到某个数据之后,我要求你过几秒钟之后,几分钟之后,然后给我去做一件什么事,我就想设一个闹钟,这怎么办呢。或者说我在这个流处理的过程当中,我就想先知道当前的water mark到底是到什么程度了,到底进展到哪里了。那我想知道现在的时间,那那大家知道,如果说我想拿到现在的系统时间的话,这个我们有接口,有这个Java直接给我们提供的东西,那如果说我想拿到flink里边的事件时间,又该怎么拿呢?之前没有任何一个地方能够告诉我们啊,当然之前我们是在window在做process处理的时候啊,Process window function能拿到water的这种方式,其实那就是属于一个处理函数了,所以这里面处理函数的一个最大的特点就是它能够拿到所有的东西。
05:16
包括。所有的流里边的事件,也就是数据,还有时间戳水位线啊,Watermark啊,还可以注册定时事件啊,整体来讲呢,这个是通过一个所谓的定时服务。来提供的啊这个服务,这个接口就叫做timer service。啊,所以这个是比较特殊的一个东西啊,只有处理函数里面才有啊,然后另外呢,就是处理函数它还继承自abstract rich function抽象类,所以它本身也是一个抽象类了,而且它是一个负函数。那之前大家还记得负函数有什么特点吗?负函数是一个富有的扩展出功能来的一个函数类,它除了一般的函数类里边那些方法之外,它还能够有一些生命周期方法,它还可以获取运行时上下文啊,它可可以运行上下文里边可以获取状态对吧?诶可以自定义状态,可以去访问各种各样的东西,所以。
06:17
负函数可以做的事情,处理函数都能做,除了这些之外,还能够提供定时服务啊,去做这个,获取当前的时间,戳水位线,注册这个定时事件,定闹钟。所以他能做的事情就特别特别多,另外还有一个就是他可以做测输出流,之前我们接触到的输出侧输出流只有在。窗口处理迟到数据的时候,其他API里边有一个特殊处理啊,那大家可能就会想到了,那我一般情况下在一个data stream里边,我能直接去分出一个特殊出流来吗?能直接把它岔开吗?一般情况是不能的啊,那什么情况下可以呢?那就只有在调用了处理函数的时候,Process function里面可以做。
07:03
所以一句话吧,这就是我们写link程序的大招。一般情况可能用不到它啊,因为它这个太底层了,它没有任何的具体的功能全得你自己去定义啊,就是它是完全是一个抽象的东西,但是呢,他把所有你能需要的信息全能获取到,呃,所以那你就是看你的本事了,你的这个各种业务逻辑,你定义的复杂一点,所有事情都能够做到。这就是process function的含义和它的功能啊,那这里给大家稍微的说一下,调用的过程当中呢,就是基于一个data stream,因为我们当前是基本处理函数嘛啊,我们当前讲的就是这个process方式啊,它基于什么去调呢?就是基于data stream去调的data调一个点process方法,然后里边传进来的就是一个process function啊。目前是data stream扮演他的process方法。
08:02
大家看到里边传的就是一个process方式,就是这个最一般化的处理函数。它是一个抽象类啊,然后呢,它还继承了负函数啊,所以里边有很多特别的特性啊,然后里边最核心的方法是一个process element。啊,这个process element呀,从字面上理解就是处理元素,也就是说每个数据来了之后都会掉一下这个方法。啊,那这个自然就想到了,那跟我们那个map flat map对吧?呃,跟跟一般的这种这种调用都一样嘛,啊,那这里面的数据是什么样呢?诶,Input类型的一个value,这就是当前数据了,然后有一个上下文,这个上下文里面东西就多了,另外还有一个用于做输出的collector。别的都很熟悉,就是这个上下文啊,我们看一眼上下文里边有什么呢?可以直接获取当前的时间戳还可以,诶,Outut这个大家熟悉对吧?哎,这不是output tag吗?
09:04
可以做特殊出流。另外还有一个就是timer service,这个timer service啊,看到本身是一个接口,这个里边有几个方法,一个是current processing time。一个是current water mark,这其实就是获取当前时间嘛,处理时间或者是事件时间,事件时间不就是water water mark吗?除了这两个方法之外,另外还有。可以注册定时器,还记得之前我们在那个讲trigger的时候,里边可以注册定时器吗?啊,这里边我们process function可以注册,也在这儿也可以注册啊,这里边就是register processing time timer,那当然了,也就还有register even time timer,它就是决定了你的触发的条件,到底是看处理时间到点还是水位线到点啊,那另外还有就是既然可以注册,那就还可以删除。可以delete这个timer主要就是这六种方法啊,啊,这是这个timer service的用法,Function里面除了我们前面提到的这个process element之外,还有一个特别的方法叫做。
10:12
On timer。呃,这个on timer啊,跟我们之前讲到的这个on event,像这个on time on processing time都很像,所以它也是类似于一个回调事件触发回调这样的一个机制,那它是什么呢?这不就是定时器的回调吗?啊,所以它就是我们那个闹钟,闹钟的处理方法,它是。也就是说这个timer service不是可以注册闹钟吗?当我们注册了一个闹钟之后,注册了一个某个时间点的闹钟,如果真的到点了,那到时候要执行什么操作呢?那边只是定了一个闹钟而已,真正要执行的操作是在这里定义的。啊,所以当一个注册的闹钟,一个注册的定时器被触发的时候,就会调用这里的on timer方法。
11:01
啊,这就是目前这个处理函数里边比较特殊的这些用法。这里需要注意的是,你尽管在process function里面看到了这个on方法。但是这里需要注意一下,但是我们直接在data stream基础上啊,data.process然后定义这样一个process function。你是没有办法定义这个定时器的,没有办法定闹钟的,什么地方才可以定呢?只有在。迪拜之后,只有在k stream上才能去做这个定时器的相关操作。啊,所以这个还是稍微有点麻烦的啊,这个定义稍微会有一点困惑啊,但是只要知道就可以了,既然我们知道了,就是它还要基于这个pit stream处理函数的调用才能够使用定时器,那我们自然就想到了应该处理函数不仅仅只有这么一种,不仅仅是基于data stream去能定义这样的一个process function。接下来我们说一下它的分类啊,处理函数在flink里边确实是个大家族啊,我们前面讲的这个process function,这确实是最基本的一个,就是它是基于data stream调process方法传的,就是它那基于不同的啊data stream转换成不同的stream之后,然后直接调process方法呢,就可以传不同的process方式。
12:20
简单来讲就是这样啊,比如我们基于一个data stream掉了一个KY,那大家知道得到的是一个k stream,那假如说。一败之后。到了一个kid stream kid stream上,如果再直接调process方法的话,要传的是什么呢?啊,大家看到这传的就不是刚才我们那个process function了,这个叫key的process function,因为它有键的定义了嘛,当然之前的那个process function就要稍微的复杂一点,而且我们看到它跟之前那个process function抽象类没有继承关系,他们都是直接继承自abstract function的。抽象的函数,所以它们其实是不同的处理函数。
13:04
那前面我们说的这个定闹钟设定时器的话,就是在这个k process方式里边才能够定这个定时器。那另外就是说像我们这个k the stream上面,如果要是掉了点window,不就又生成了一个window stream吗?那前面我们说过了,Window stream上是不是也可以直接到一个process方法呀?然后里边传的这个就是一个全窗口函数process window方式啊,前面我们已经讲了,它其实是处理函数家族里边的一员,当然它也是。它也是一个全窗口函数,从命名上大家可以看得出来,它更像窗口函数一点啊,大家看,因为一般前缀是不太重要的嘛,越往后应该越本质嘛啊,所以这里面就是它是更像一个像process function的一个window function。所以它是本质应该还是一个全窗口函数,但有时候给大家归类的话,还是也会把它归到这个处理函数加速里面的一员,它可以认为它是一个杂交的结果啊,那除了这些之外,同样我们还可以基于data stream直接开窗,大家记得哎,那个直接开窗是window or window or的话,得到的是一个or window stream。
14:16
他也可以直接调process。那里边要传的就不是process window function了,而是process or window function跟这个基本上是一样的,我们就不专门讲了,然后另外还有几个比较特殊的处理函数啊。首先一个叫做Co process function。这个大家看到了,它是处理函数,前面加了一个扣,扣是什么意思呢?啊,其实是connect,两条流合并连接,两条流连接在一起之后,合并成一条流,得到了一个connected streams。这个流,然后再去调process方法,那么要传入的这个处理函数就是Co process方式,所以它要处理原先的两条流,相当于是啊,所以这个就稍微的会复杂一些啊,后面我们讲到多流转换会给大家讲,然后还有一个process draw function,这个也是啊,两条流做draw的时候,而且是做这个间隔连接啊,这个关于这个我们后面也会讲啊,多流转换的时候会给大家讲,就是做这个间隔连接interval join的时候,会基于一个interval drawing的这个类型调一个process方法,这个时候传入的就是一个process draw方式啊。当然了,从字面理解,字面上看,我们也说它的本质更像一个draw function,只不过是跟process function沾点边而已啊,一般这种命名的都是本质,它其实不太像一个process function。
15:41
然后另外还有就是这个broadcast process方式,这个字面理解就是广播处理函数啊,那什么叫广播处理函数呢?它主要就是首先要基于一个广播流。如果我们已经创建了一个广播连接流的话,那么接下来你再调点process方法,这个要传的就是。
16:03
这个广播处理函数,那什么叫做广播连接流呢?它也是做了一个connect操作,也是两条流连接起来的,是一个普通的data stream和一个所谓的广播流连接在一起。得到的产物啊,那广播流呢,当然就是用到了这个广播了啊,就是broadcast,它会把一个状态直接广播出去,是这样的一种特殊的流,然后它可以跟另外一个流做连接,这里我们就不详细展开讲了,然后另外还有就是k broadcast process function,跟上面这个比的话,那就是KBY之后的产物,你之前是一个data stream和就是没有KBY的data stream跟广播流做连接的产物,那现在呢,就是K之后的啊,K stream连接之后的产物。所以我们的重点呢,啊,前面也说了process function受限制,我们的重点其实就是kid process function,这就是我后面我们接下来要讲的重点。
我来说两句