00:00
接下来我们再来看一看在table API和linkq里边的其他一些操作。前面我们已经知道了,在这个table API里边,我们可以把一个流,一个data stream stream直接基于它定义的那个字段啊,直接转换成一个table,然后就可以做操作了。那能不能反过来转换,把一个table转换成一个data stream呢?呃,因为这个有什么好处,一个就是说他们彼此之间的数据结构来回转换,我可以非常方便的把table API和data streamam API结合起来用,对吧?啊前面一段我觉得写一个这个CQ比较简单,那我转换成table去做操作,后边呢,我又觉得做这个流处理比较简单,那后边我就再转成流啊,这个过程是就是还是比较容易的啊,就来回可以做切换,然后另外还有一个。就是我们如果要是平常写完这个table代码之后,如果想要table API的代码写完之后啊,如果想要快速的做一个测试,看到它的这个结果的话,诶,大家发现这个table并没有直接的打印输出的这个方法,不能直接print,那怎么办呢?啊,那就需要我们把它先转换成流,然后再打进输出。
01:13
所以呃,整整体上来讲,大家会发现就是table API的调用啊,在做转换这个过程,呃,可能熟悉CQ的写法的话,大家会觉得它更加的方便,但是说输出我们要输出到控制台,这个是稍微有点麻烦的,所以在很多测试场景下,把它转换成data stream还是非常必要的那。对于这个呃API而言啊,Table API而言,它给我们提供了非常简单的方法,呃,可以很容易的转换成data stream或者data set,这样呢,我们自定义的这个流处理或者批处理的程序就可以,诶,直接在我们之前表的那个查询的结果上做转换的那个结果上直接继续运行了啊。这就是两者结合在一起啊,呃,这里边当然就是说你在转换的过程当中需要指定当前的这个数据类型啊,就是我们data stream并之前我们呃引入这个table的时候,大家看到转换的时候啊,它并不需要加一个类型限制,就是一个table对吧?啊实现这接口就可以了,里边并没有泛型,那对于data stream或者data set而言,它必须还要有一个类型的定义啊,所以说这个是需要我们在转换的时候需要注意的,那当然最简单的方式。
02:31
你可以把它定义成元组对吧,甚至还有更简单的,你直接定义成肉啊,就是我们的那个flink自己定义的那个行的类型也是可以的。啊,那表我们这里的这个表作为这个流式查询的结果,大家知道它其实是动态更新的嘛,所以说我们在进行这个转换成流的时候,大家可能想到你既然是动态更新,那转换成流,你就把那个动态更新就是要做的那个改变,对吧?动态所谓的那个动态啊,做一个输出不就完了吗?转换成流输出不就完了啊,但这里面就又涉及到两个问题,就是一个是。
03:07
啊,如果说它只是往后追加的话,这个简单,那如果说你要是呃,里边我们表做了更改,那怎么办呢?哎,所以说这个转换成流的时候,你应该要把它更改的那个操作,要要把它再转换过来,对吧,要把它做一个这个呃,就是描述,然后变成这个流里边的新增的数据。那这里边就又涉及到两种转换模式啊,一种是追加模式,另外一种是撤回retra模式。这个也非常理解,这不就是之前我们讲的那个更新模式吗?呃,只不过就是现在我们要把这个表转换成理由,也涉及到了这个更新模式的这个操作。大家想想为什么呢?呃,因为我我们之前说的这个更新模式是在跟外部系统连接的时候啊,你让外部系统得知道当前是一个什么样的操作,对吧?呃,到底是更新还是插入,还是这个删除,那对于我们转换成流而言,流里边只有一条一条来的数据啊,它并没有一个完整的表,对吧?呃,并没有一个固定好的这样的一个数据结构,所以说你也得告诉这一流里边能够明确的描述出来,到底当前,诶是追加还是说我要去更新啊,所以说我得通过这个流里边的每一条数据得带上这个信息,对吧,告诉他到底是什么。
04:28
啊,所以这里边就呃呃,大家还会想到之前我们在代码里边,其实也非常的明显啊,这部分在之前这个事例里边。我们就看得很明显了啊,这里边其实就是说如果我们直接不做复杂的那个聚合操作,没有做更新的话,那就直接可以to a pen stream,然后它怎么样呢?直接print就可以print出来了,所以大家看到这里这个,因为我们的这个data stream流可以直接print,可以直接打印输出。
05:01
因为大家知道打印到控制台也是一种think操作,对吧?啊,也是一个特殊的S,所以我们可以认为当前的这个转换成流,它本身,呃,就是跟那个外部系统的一个连接,对吧?啊,就只不过这是跟这个控制台的一个连接而已。啊,所以说这里边就应用到了我们之前讲的那个更新模式啊,那当然这里边你如果要是说没有做别的操作的话,那需要呃,只要end stream就可以了,如果做了聚合操作,那就必须得totra stream。啊,这个都是之前我们在代码里边也都已经看到的,这里再给大家把概念详细的再介绍一下。啊,然后这里边大家看到这个写入啊,其实这就是呃,End模式的话,那就是to stream对吧,这里边我可以跟在后边加一个方括号,指定当前的data stream转换之后的本身的这个类型。啊,那这里边这个撤回模式大家要稍微注意一下,我们说这个撤回模式下,是你给这个流里边输出的这个新的数,每每一条数据啊,每一条这个消息,你得让他知道当前到底是做了一个什么什么操作,对吧?那在流里边我们数据都是一样的数据啊,你怎么能表示出来他这个操作是一个是一个更新操作呢。
06:22
这就是在撤回模式里边,他把结果就专门包了一个字段,比方说我们这个啊,Totract stream,我们转换成这个,呃,就是stream long这个二元组类型的时候,它其实返回来的这个data stream是一个什么类型呢?诶是内容是这个二元组,然后前面还还加了一个布尔类型的一个字段,一个标志位,然后它合起来是一个大的二元组,对吧,就里边具体的这个数据类型是,呃,本身就是一个大的二元组类型,然后呢,第一个又是标志位,后面是我们真正的那个数据字段。所以前面这个标志位表示的是什么呢?这就相当于是我们说的那个,哎,它tract模式不是只发两种消息吗?一种是ADD,一种是retract,所以对于一次更新操作而言,相当于我们就要发这样的两条消息。
07:15
一条是追加对吧,一条是这个删除撤回之前的那个老的消息,那怎么表示到底是追加一条消息,新的消息还是撤回老的消息呢?那就是用这个true false,它如果是如果是false表示,诶,这是要删除的老数据对吧?那如果要是true的话,这就是新增的新数据啊,所以对于这个流的转换只提供了这两种方法。啊,因为大家想到了,就是因为你转换成流嘛,那你用这个前面加一个布尔类型,很简单的可以实现这个re mode啊,那你如果要是说想用那个UPS search mode的话,那个就更复杂了,对吧,那个你必须还得指定K,然后去呃,返回去之前的那个数据去做查询,你这个直接表示成流的话,那相当于就是我们还得去这个,呃。
08:07
人肉眼或者说人人工手动去做这个K查询了,嗯,当然他输出key理论上是可以的,呃,但是这里边本身就没有给我们提供这样的一个模式,所以就少了一个upsurd mode,只有to append stream和to retra stream2种方式。这就相当于又是把我们之前讲的这个更新模式给大家做了一个回顾啊,具体到这个转换成流打印的时候,有这样的两种方式。所以通过这个例子大家也可以看到,就是所谓的retra mode啊,对于有一些外部数据库。而言,那是不是相当于你如果要实现这个mode,那就是什么呢?就是哦,我假如说我现在连续收到了两条消息,一条前面带着false,一条带着处,对吧,那我外部系统就能就能够得有这样的能力啊,判断出来就是找到第一条要删除的那条数据的那个位置,然后把它更新成第二条。
09:05
发过来的那个处的那个数据对吧?啊,或者说我就直接就做这个操作,就是我直接看到false的数据,直接把那条删掉,然后第二条数据呢,直接追加上去啊,这样也是可以的,所以外部数据库要有这个读懂这个消息的能力。这就实现了这样的一个mode。好,然后接下来我们再给大家讲一个比较简单的内容,就是说呃,查看执行计划就对于这个table API而言的,呃,大家知道就是最后我们写的这个所有的CQ啊,或者说写的这个table table API的这个转换的操作,最后他其实应该怎么样呢?他其实是要用通过这个planner啊,我们现在不是可以引入老,呃,可以入这个老版本的planner,或者或者是用这个。阿里提供的新版本的blink planner,那不管是哪种planner,都是由他来把我们写的代码解释成一个啊,就是相当于解释成一个执行计划,对吧,生成一个access plan啊,类似于我们数据库里边说的这个执行计划,然后呃,最后会把这个执行计划翻译成我们流处理里边的那个。
10:17
执行图对吧,Execution里边那个execution graph,所以那么这里边有一个很重要的操作,就是我们要把当前的这个CQ或者说table API的链式调用。翻译成或者说解释成一个执行计划啊,那这个执行计划到底是什么样的呢?啊,有时候如果我们对他比较关心的话,可以用一种方法来查看,呃,当前的这个执行计划是什么样的,这个方法也非常简单,直接调用这个表环境table env的explain table这个方法就是传你要看哪个哪个表的那个执行计划,对吧,你就把那个表直接呃传进去,然后调这个explain这个方法。
11:00
那后边就可以直接把这个得到的,大家看得到就是一个string啊,你就可以直接把它打印输出了,它这里边其实就主要包含三个部分啊,它描述了三个计划,一个是什么呢?是就是需要优化的啊,待优化的这个呃,逻辑查询计划,就是我们一开始按照程序结构,按照CQ直接执行,直接生成的那个执行计划,然后后边呢,是一个优化之后的逻辑查询计划啊,也就是说我们要做一些调整,对吧?按照这个某些需求,因为大家知道你直接按CQ构建出来的那个执行计划未必是最优的,有些时候我们的那个,呃,你是先查还是先这个做表连接,对吧?你是按什么样的条件去对这个表做做筛选,呃,这个其实是先后顺序啊,如果调整之后,我们的执行效率会更高啊,这其实是这个关型数据库里边的一个一个优化的要点啊,那所以说这里边还可以直接给我们。
12:00
生成一个优化之后的查询计划,然后最后呢,再基于它实这个生成一个实际的执行计划,对吧?啊大家看这个就有点儿像我们之前讲那个执行图的时候的那个过程,所以说大家会想到就是最后的这个,呃,CQ的这个执行计划,当然就要能翻译成我们的那个执行图,这样的话就一一对应上了。啊,这就是,呃,这个执行计划这一部分。然后讲到这里就给大家再来,呃总结一下啊,啊,就是流处里我们说所说的这个flink,主要是做实时的有状态的流处理计算,那么流处理和我们讲到的就是要用CQ啊,或者说我们讲这个关系数据库对吧?关系表啊,他们有一个统称叫关系代数啊,就这种数据结构,它们的区别在哪里呢?啊,到目前为止,大家其实发现它其实这两种是不同的东西,就是对于表这种东西而言。我们分别从这么几个维度来做一个对比啊,首先我们看一看处理的数据对象是什么样的呢?
13:06
啊,那像这个表,或者说我们平常写的CQ,它处理的其实是字段元组的一个有界集合啊,这里说的字段元组其实就是一行数据嘛,啊,我们的一行数据,一条数据,这不就相当于是一个一个字段的一构成的一个元组嘛,啊就像我们那个样衣类类型一样,对吧?呃,这里边关键在于我们的表操作,或者说写CQ的这种关系数据关系代数的这种操作,它其实。处理的是一个有界集合对吧,我们从表里面去select去查数对吧,或者说我们这个做表连接之后做的任何的这个呃,转换的操作,其实都是针对现成的有限的这个数据去做的操作。所以它是有界的,而对于流处理而言呢,我们要做的操作是无限的,对吧?啊,就是来一个处理一个,来一个处理一个,永远没有截止啊,这就相当于大家一看这个这个定义,这不就是批处理和流处理的一个差别吗?
14:07
啊,所以对于这个表操作啊,写CQ的这种方式,大家就会发现,在我们传统的这个批处理架构里边,它其实是非常顺利非常顺畅的一个概念,因为数据已经都到齐了,都放在那里了嘛,而我们的这个关系代数,它要求的就是一个有限的集合啊,所以当前我们直接执行CQ这个集成非常的容易,这个概念都没有任何的偏差,但是流处理这里边要考虑的就会多一点。啊,然后我们再来看,那现在我们如果要对这个数据要去做查询了。对数据要去做访问,那这个怎么办呢?啊,那对于这个关系代数或者CQ而言。应该是能够访问到完整的数据输入对吧,我们当前写一条CQ,那就是你应应用在这个表上,数据都已经现成了嘛,有借的嘛,那所以说我们就应该要访问到所有的数据,然后得到一个一个结果对吧。
15:02
而这里边我们流处理的时候,是没有办法保证它访问到所有数据的,对吧,你只能是不停的去查询对吧,只能是连续不断的等待这个数据输入,然后我连续不断的按照那个逻辑那个做查询,然后更新之前的结果啊,这是这个流处理的一个一个标准啊,就是假如说我流处理里边要去处理类似于表的这个数据的话,要做表的查询的话,是这样的一个操作。那么这里面就又涉及到这个终止条件了,那对于这个之前大家熟悉的这个CQ操作,其实就是说我写一个CQ1执行,那针对之前确定的一个数据集,有些有界的一个数据集,那最后就相当于访问到他所有的数,然后生成一个固定大小的结果集,对吧,然后就终止了,那这个是很很简单的一个批处理的一个过程。那对于流由处理而言,那就是他永远不会停啊,因为你这里面数据永远没完啊,啊,所以说他是我在不停的查,然后就相当于还是来一个处理一个,来一个处理一个,有点像是来一个啊,就得查一次,然后更新一下之前的那个查询结果,对吧?呃,他得是这样的一种操作方式。
16:14
所以在流处理里边比批处理对于这个呃,CQ的支持啊要难得多,而且大家要考虑一些更多更复杂的一些概念。啊,所以接下来我们给大家说一说在这个流处理里边一些特殊的一些重要的概念啊,啊,那比方说什么概念呢?给大家引入一个概念,动态表dynamic tables。这个表其实是就是这个概念啊,其实是flink里边对于流式的数据输入,做这个table计算和fli,呃和弗link CQ啊CQ支持的一个核心概念,它表示是什么呢?就是说跟我们做批处理的时候,那个表示静态的。不一样对吧,那那个表是静态。
17:02
就数据都到齐了,都放在那里了,你现在执行的这个CQ就是基于这些数据对吧,然后得到一个固定的结果集,就就这样,那现在不是了,现在我的表数据是动态的对吧?这就有点像是我们好像是啊在做一个轮询一样,是不是啊,就像大家想你你这个如果说对于这个,呃,我们一个MYSQL里面的表,或者说HP里边have里面的一张表啊,假如说他的这个数据不停的在改啊,我们不停的有数据新增数据要写入进去,然后我现在如果想要对这个表动态的做一个查询,那怎么查呢?哎,那我们正常的一个想法就是说我要去隔一隔一段时间查一次,对吧,相当于做一个轮询的这个把把一个CQ啊,就是隔一段时间执行一次,做一个轮询的查询。啊,那这里边对于这个流处理而言,它本身的数据来的就是一条一条来的嘛,对吧,数据本身就是进来的,这个过程其实就是连续不断进来的,那所以这里边我后边的这个查询呢,它也是连续不断啊,就是你这里边就不需要去轮询了,我这里边写一条CQ。
18:10
这个对于动态表这个操作,它本身就是一个持续查询啊,所以给大家再引出一个概念叫做continuous。Query对吧,持续查询,所以这个查询它的含义就是说对于我们那个随着时间连续不断变化的这个动态表,呃,它的数据不停的在改,对吧,然后来了之后他不停在变,那么我基于他写的一个CQ。这就不是简简单单的就是只是生成执行一次生成一个结果就完了,对吧,它是像那个流处理一样,直接就挂在那里,等数据输入来一条输入就要,哎,查询一次生成一次结果,更新一次结果,对吧,这样的连续不断的这个处理,然后查询一个动态表。产生的这个查询,这种方式就叫做持续查询。
19:04
那它的这个过程就是永远不会停止,它的结果是什么呢?哎,会基于一张表啊,假如说我们基于一张表,或者是你表联合对吧,撞一起来的表,最后呃,那个select什么的,呃,出来之后得到又得到一个结果表嘛,得到一个结果集,这张表呢,又是另外一个动态表,因为你前面的数据就在不停的变呀,对吧,我现在对它做了一个持续查询生成了,当然也是一个动态的表。那么当前这个持续查询就会不停的随着数据的输入不断的更新,结果得到的这张动态表对吧?呃,它反映的就是我们这个输入表上你更新改了什么东西,我这里边经过查询之后,结果那个动态表也就变了什么东西啊,这就是这样的一个过程。所以大家要把这个呃流处理里边的特殊的这个概念啊,先把它树立起来。然后我们接下来看一看这个具体的过程啊,这个图也是从官网上找到的啊,大家可以看到这个具体的流程,其实就是什么呢?诶我们这里面本来是要做一个比如处理嘛啊,那其实即使我们不不做,大家看之前我们那个第一个事例就就做的操作是先读成一个data stream,然后转换成表,对吧,然后做操作之后又转换成流,然后再输出。
20:24
那假如说我们不做这个表和swim的转换,直接写一个date date swim,呃,这个flink CQ啊调flink CQ,或者说直接写一个table API的程序,那是不是我就真正的直接做的就是表操作没有涉及到留了呢?其实不是的,其实底层本质还是要就是一开始的是流对吧,读进来的还是流,然后呢,是要把它先转换成动态表。然后基于这个转换过来输入进来这个动态表呢,做这个持续查询啊,大家看这个持续查询就会有自己的一些状态,对吧?啊在这里边,这就相当于我们中间的那个有状态的,呃,转换操作,然后得到的是一个哎动态的结果表,然后我们继续可以把这个动态的结果表输出。
21:15
那你要输出的时候还是得转换成流对吧?啊,所以在这个过程当中,其实就类似于我们为什么一开始给大家讲讲那个流的那个转换操作,一方面是它比较好理解,另外一方面就是本身我们写的这个flink SQL的代码,它底层就是这样的一个过程。它是一个动态表跟流的一个不停的转换的一个过程。啊,那所以接下来我们看一看这个,呃,给大家再讲一个具体的例子啊,大家把这个再理解的透彻一点,比方说呃,这里边我们输入了这个数据,大家看,这就是日志数据嘛,我们现在不是流式计算吗?呃,都是提取出来的这个这个数日志数据,比方说这里边大家看,这就是后面带着URL的啊,这就是我们当前这个用户的点击数据URL就是他访问了哪个页面嘛,点击了哪哪个页面。
22:06
啊,所以这这个字段就是哪个用户啊,这个用户的名字,然后呢,后面就是几点钟啊时间戳,然后加一个访问的那个链接URL。非常简单的一个点击对吧,对于很多这个场景,对于这个呃,APP或者网站而言,这个数据都是最基本的啊,点击数据的一个收集好,收集起来之后,哎,那这里面大家注意看啊,这是流式数据,一个一个来,然后如果我们做这个table API的程序计算,或者是写这个flink CQ的话,那首先需要干什么呢?需要读进来之后啊,这个数据我们连接外部系统,读进来之后,首先把它转换成这样一张表。这样一一张表是一个动态表,也就是说这个流数据再进来的话,诶,它会动态更新,这里边的这个更新当然就是直接插入对吧?啊,就是来一条数据直接判到后边,所以对于这个输入表而言非常简单,它不需要有这个所谓的更新模式,前面我们讲更新模式主要就是输出嘛,输入这里边默认肯定就是追加到后边就完事了,这个字段名就跟这里边这个数据的这个名名字啊,就本身的这个含义一一对应,我们这张表就是user,呃,这里边是c time对吧,就是custom time,这个或者说我认为这是一个时间戳,你转换之后一个时间戳字段都是可以的,后面是URL。
23:29
然后就把一条数据一行写进去。然后接下来呢,诶,就要基于它去写一个查询了,比方说我们写一个这个select啊,Select user,然后我们做一个count啊,就是考考虑当前这个user点击数量啊,啊做一个count count了几次,那就是呃,这里边是当前的这个user,我们要按照他的那个URL的数量做一个count,对吧?呃,然后呢,呃,From这张表,这张表我们名字叫做clicks,然后group by user按照user分组。
24:01
统计每一个用户他点击的次数、数量。那我们就会想到这个得到应该是得到一个什么样的表呢?得到一个类似于一个count表,那这张表。它同样还会随着我们数据的输入不停的更新,它的更新的过程又是什么样的呢?啊,之前这个更新的过程我们都不用专门写对吧,直接在后面追加就就完事了,那现在的这个更新它就应该是。就是来了一个Mary第第一条数据,我们这里边来了,对吧,这里边把那个时间字段给给去掉了啊,因为大家想到这里边我们select出来的只只对这两个感兴趣嘛,所以没有加那个时间字段啊,比方说这里边第一条Mary home这个数据来了,然后这里边我会怎么样呢。诶,对应的这个结果表大家看持续执行嘛,每来一条,每来一条数据,这个持续查询就会执行一次,得到的表就是MARY1。然后第二条数据,Bob这条数据来了之后,哎,MARY1BOB1在后面追加对吧,然后后面Mary又来了一条点击数据,现在我一看了之后,发现变成了MARY2BOB1对吧,他做了一次更新,把之前这个MARY1这个数据做了一个更改。
25:17
然后所以说呃,后面这个例子,这个人的数据又来了之后呢,在后面又追加了一条,所以说得到的这个结果表也是一个动态表,随着这个持续查询的进行啊,我们这个数据不停的输入,不停的执行持续查询,这张结果表也在不停的更新,但是这就随着我们这个持续查询里边做的操作不同,这个结果表就有可能哎是单独追加的,也有可能是,哎就是我们这里面做的聚合对吧,就有了这个更新操作。所以这里边就涉及到更新模式了,对吧?啊,所以这里边就再给大家说一下,就是你你后边如果要想再把它输出的时候,我们要把这个动态表还要转成流嘛,对吧?这个说的不是前面我们那个代码里边显示的转换to文end stream to reject stream,这说的是我们底层本身要做的这个操作,那这个操作就是我们之前说的要有这个更新模式的考量,对吧?啊就是三种模式,那转换过来之后有三种不同的流的形式,一种就是颈添加颈椎加啊判的流。
26:23
就如对应我们之前更新模式就是啊这个uppa模式对吧,另外还有就是撤回流啊,对应retra模式,最后还有一个更新插入流,那就是upset模式,对吧?啊所以这里面就是为什么连接到外部系统的时候,你要指定它的更新模式呢?因为这个在底层做这个转换的时候,这个动态表转换成流的时候,就得有这个类似于更新模式的这个定义,转换成不同的流,然后呃,给外部系统发消息,外部系统就知道它到底是一个什么样的操作了,对吧?啊,那所以说你还得指定外部系统跟我们的这个更新模式要对应上。
27:02
同样的这个更新模式,然后把把它转换成这样的流,那外部系统就能读出来对应的数据,做相应的操作了。这就是这个呃,动态表转换的这个过程啊,大家结合之前的这个更新模式,再来把它做一个梳理。啊,那这个过程给大家简单的再说一下,按照图给大家再写一下吧,啊这个过程是怎么做的呢?呃,A就不用说了,就后面追加对吧,那这里边重点对比一下这个retra模式和upset模式。啊,转换成absurd,呃,转换成retract流,这个retract模式下边回撤模式下边是怎么发消息的呢?怎么转换成这样一个retract流呢?啊大家看其实类似于就是有两种不同的消息对吧?啊有一个是insert,有一个是delete啊那这里边就是我们用这个加号表示一条。追加的消息,Ins色的插入的消息,用减号表示一个删除的消息对吧,回撤的消息,那这里边我们的当前的这个表怎么表示它这个操作呢?哎,那就是第一个Mary来了之后,那就加MARY1对吧,我们这里边这个表示要有一个MARY1嘛,所以这里边转换过来的流就是加MAR1,然后后边Bob来了之后又是新增,所以加Bob。
28:19
那后边如果Mary又来了一个之后,要把它改成二了,所以这里边就是减MARY1,然后加MARY2对吧?啊,所以这里边大家看到这个所谓的这个stream。呃,构建成这个moded的这个这种输出啊,这种流式的输出方式,这不就是我们在呃,这个直接转换成流打印输出的时候的那个这个正负号,不就是那个我们一开始那个布尔类型的那个变量嘛,对吧,出OL false表示它到底是老的要删除的数据,还是新增的要添加的数据,这就是这部分。啊,那如果说要是up的模式的话,那大家可能会想到这里边我生成的这个数据就是什么呢?按照K来来确定对吧,那这里边生成这个流里面的数据是什么呢?你就是来一条数据,只要是这个,呃,新增或者是修改,我都是upset对吧。
29:13
如果要是删除的话,明确的删除我再去delete,所以这里边我们所有的数据来了之后,大家看它都是这个用这个星号来表示的,没有delete操作,这里边都是来了一个MARY1,对吧,来了一个BOB1,来了一个MARY2,来了一个例子一,来了一个例子二,就就按照这个一条一条输输入就可以了。啊,所以这里面的要求是我必须默认得知道这里面的K到底是什么才行啊,那看起来这个数据就会比之前那个简洁很多,对吧,你这个消息没有,不需要去发送一次更新发送,发送两条消息了,但是要求就是说必须得知道K。啊,这就是这个底层转换的一个过程。好,那我们这节课就先讲到这里。
我来说两句