00:00
好,同学们,我们之前的RD的内容啊,咱们基本上已经讲不了啊,基本的实一些概念,还包括一些我们的API的这些操作,咱们都讲的差不多了啊呃,我们接下来要给大家讲10SPARK核心编程当中三大数据结构的后面两个啊,这个叫累加器和广播变量,那么累加器呢,这边呢叫分布式的共享止写变量,这个广播变量呢,叫分布式的共享只读变量,所以啊,从这个角度来讲的话,我们说不好理解,为什么呢?什么叫只写,什么叫只读,为什么叫共享,这个不好理解。所以接下来呢,我们准备呢,给大家通过我们的小例子,咱们来演示一下啊来,那我这里呢,咱们点击啊咱们的new,首先咱们创建一个package,我们叫ACC啊,后面我们解释什么意思啊,点击OK,然后我们在这里呢,点击new创建一个它叫SPARK01,咱们叫ACC啊。
01:04
好了,然后呢,我们在这里面给他一个叫做main啊,然后把基本的这个,诶代码呢拷贝过来。拷贝过来以后,那么我们继续啊,同学们,咱们叫SC,咱们叫做stop,那咱们放到这边啊,呃,放到这边以后,那接下来咱们要做一个什么功能呢?就是很简单的一个聚合功能啊,咱们ac.make r DD list啊,我们叫1234,然后呢,我们RDD,哎,咱们这么写,那么你这么写了以后,咱们以前呢,咱们的RDD点啊,咱们叫做reduce啊,Reduce的话就是下划线加下划线对不对,然后点VAR回车,你的这个时候的结果呀,咱们来直接print写上一个I,我相信这个很简单嘛,同学们对不对,两两聚合,那么我们有这里记住啊,咱们的reduce你看着很简单,但是两两聚合,但是它包括什么?分区内的计算,还有分区间的这个计算对不对?所以我们运行一下,看结果运行。
02:10
好了啊,看一看它的执行结果,那肯定是很简单的十嘛,一加二加三加四,应该结果等于十对不对,嗯,就是这样啊。好了,同学们看结果出来了,但是呀,我就觉得呀,你这个太复杂了,你就计算这么个东西,你居然是什么呢,什么分区内计算分区间,还要给它合并计算,就感觉有点复杂了,所以我能不能简单一点呢?对不对,你别这么复杂对吧,那好,那我怎么办呢?把这个做掉。把它做掉,做掉以后我干什么呀?我们写上一个for循环,For循环去了,我们叫RDD点,我们叫for it,这个for it什么意思呢?就是把里面的每个数据我挨个遍历,那这样的话,同学们看我写上一个叫做什么呢?我们叫some,它等于零,然后呢,我把每个数据number,诶给它放过来,然后呢,我的sum给它拿过来啊加,然后呢,它等于咱们的number,诶这么写,你这么写了以后,就意味着呀,我要把每个值给它加到sum当中,循环一个加一个,循环一个加一个,那这样的话,循环之后1234不都加进去了吗?对不对?所以在这种情况下,那么我们这里呢,来打印它的结果,哎,写上some,那等于,然后呢,再加上我们的some,诶这样的话不就OK了吗?
03:34
好了,同学们看,你会发现这种方式是不是要比这个要好一些啊,它哪有什么分区内分区间这个概念,是不是就挨个变利就完事了,哎,1234给我直接相加,所以在某些情况下你会发现呢,可能不需要那么复杂也能实现我的功能啊,所以咱们来运行一下看结果啊,结果应该是不是十啊,那应该就是这样啊。诶,同学们有没有发现我们这不对,我们刚才分析了半天呀,咱们觉得它应该是十呀,可是我们这就是零,那这个是为什么呢?首先我们先给大家解释一下,就是我们之前分析它是十这个事儿本身就不靠谱,为什么说本身是不靠谱的呢?是因为啊同学们看你的for each,它没有分区内分区间的这个概念,就会导致它出现这么一个问题。
04:24
它是一个分布式的循环,对不对?那就意味着这个sum加上number这个值,它就直接改它了吧,那么就有可能变成一了,也有可能变成二了,还有可能变成三了,还可能变成四了,对不对?所以呀,它可能不是十,这个事儿你要知道,就是它是分布式的,就是这个sum呢,可能被改了好几回,对不对,有没有可能你这个也改,什么叫分布式的,就是你有多个我们的线程,你这个改sum,我这个也改sum,他也改sum,他也改sum的话,这个sum的值就可能被多次修改吧,那么这个时候这个sum其实到底是多少,应该是不确定的,对不对?
05:03
所以啊,我们的这个地方就会感觉它确实有可能不是十。但是为什么又是零呢?对不对,这个时候我们需要给大家分析一下啊,那么这个分析咱们就要涉及到一个非常关键的地方了,什么呢?就是我们前面讲的那个driver和我们的嗯。来同学们看,我现在把这个呢写上啊,咱们的driver,诶咱们想driver啊,然后呢,用一个我们的红色来表示,然后呢,我在这边再来啊,把这个放的稍微的,诶放过来咱们叫做什么呢?叫做execu,嗯,好,然后颜色呢,给它来标识一下啊,咱们叫做绿色,嗯,好,然后呢,放过来啊,咱们叫做它。好了,那么如果是我们的executor的话,那么咱们现在来分析一下啊,同学们看,嗯,分析一下代码,我们的这个some是不是在我们for意之外,那么是不是在driver端这个代码会做一个初始化呀,所以说大家来看啊,在我们当前的这个地方,诶,咱们就会有一个sum,这个some怎么了?它应该等于零对不对,同学们应该是这个样子吧,好,然后往下看,往下看的话,你的for each呢,是不是意味着怎么了?应该是在一个Q端来实现这个sum的一个相加吧,所以说咱们这边拷贝,拷贝的时候大家看一下是不是应该是加等number啊,哎,就是这样,同样道理,你是分布式执行,那是不是意味着这个计算在下面的E也会被执行啊?
06:36
可是问题来了,什么问题啊,你的这个sum在这儿,可是我这用到sum,你该怎么办?那我是不是应该想办法把这个sum给他传过来呀?这个咱们之前讲过,有一个叫B包检测对不对?它会检测咱们B包的效果,要想办法把咱们B包的数据给他传给equor,那这个时候就要求它必须能够序列化,还有印象吗?同学们,所以啊,这是我们之前呢,其实是给大家说过的啊。
07:06
那我的这个sum等于零,这个事儿是不是就要传过来了,所以它就往下来了啊,然后呢,这个呢也往下来了,这个sum呢,就给它放过来了啊放到这儿来了,好,那么你放过来了以后,咱们回过头来,你挨个遍利,这是1234 1234的话,你这个number如果有两个已口头的话,是不是有可能一和二在这,我们的三和四在这儿啊,所以这个计算没有任何的问题,这是完全可以计算的。问题就在于,你计算完了怎么办?就是当你的这个equ把整个计算处理完了,你该怎么办?那我是不是应该将我的number的计算的返回结果给我们的driver啊?所以你应该干嘛将我的计算结果你返回给我们的driver对不对?可是大家想一想,咱们有返回的这个操作吗?
08:00
没有,如果你没有返回的操作,那就意味着你的每一次增加,其实只是对他自己的这个sum进行了我们的什么操作吧?那我问你这个sum它变过吗?这个sum从来就没有变过,对不对?它会变,为什么呢?每次加number,比方说一和二乘以它,那么一,那么再加上二不就是三吗?同样道理,它是三和四,那么三和四不就是七吗?所以这里面的上次肯定会变的,但是我们这儿的上会变吗?不会,为什么,因为这根箭头是没有的。咱们使SPA由于B包的功能,他知道你的上面要传过来,他是知道的,但是他不知道的是你的上面的结果要往回返吧,他不知道,那如果不知道的情况下,当你计算完毕之后,你往下看干嘛呢?在打印sum对不对,那么是不是意味着在后面的这个操作当中干嘛呢?我们叫。咱们叫print sum,诶就是这样,那么你print sum的时候,大家想想是不是一直没变过,就还是零啊,所以结果呢,它就是零,诶就是这个意思,哎,老师,那这怎么办呀,我现在就想实现这样的功能,但是我发现呢,由于我能把这个B包的数据我传给E,但是你的计算结果我返不回来,那该怎么办?
09:21
对不对,这个时候就需要我们的特殊结构出场了,因为这个特殊的结构,我们的Spark可以把它从driver传给equ,当它计算完毕之后怎么办?它可以将结果返回给谁,我们的driver,诶是这个意思,所以大家看啊,我们来拷贝,诶拷贝。拷贝以后,诶,我们放过来啊,咱们放到咱们的这个地方,我们记住这个时候我们的sum就不是一个普通的变量了,它应该是一个我们的叫采集器,或者叫累加器啊,咱们叫累加器或者咱们叫ACC吧,啊咱们一会儿解释一下ACC啊,这个就叫ACC,那么这个ACC它有什么作用呢?它的作用很简单,就是说让咱们的Spark知道把它计算完毕之后要返回来,所以这个时候大家看啊,当我们计算的时候,会把它传给谁呢?传给咱们的这边,所以拷贝,诶拷贝传过来,你传过来以后传道理这个它也会传过来呀,所以copy贝啊,传过来,传过来以后,那么这个时候呢,我们的一和二发给这个equ,三和四发给这个equ,一和二相加,那么这个它就变成几了,变成三了,同样道理,这个就变成七了啊,它变成七了,它变成三,它变成七。当我们计。
10:44
转完毕之后怎么办?他需要将结果返回来,将结果返回来那咋反呀,很简单,就是直接返呗,这是我们这个equ的对不对,这个是我们这个equ的。
11:00
大家有没有发现它就会有多个我们的结果吧,那你这个是我最终的吗?不是,你该怎么办?我们是不是应该把多个计算的结果再去做合并啊,所以说你最后的这个sum的值,大家想想是不是应该是三和七相加,应该是什么呀?打印出十来吧,哎,所以应该是这样的一个结果,所以呢,如果你能实现这样的功能的话,那么OK,我们应该是没有问题的,所以累加器的主要目的就是将计算结果可以返回到driver端,所以咱们回过头来,咱们看一看咱们的这个东西啊,来。看一看咱们的累加器啊,累加器他说了,累加器是用来把ex端变量的信息聚合到driver端,在driver程序中定义的变量,在ex端的每个task都会得到这个变量的一个新的副本,那么这些新的副本它更新之后,它会传回给driver进行合并操作,咱们刚才是不是画图了,这会有多个结果吧?把它们合并在一起,这就是累加器的一个实现原理啊。
12:10
拿过来我放在这儿啊,咱们写上叫做累加器,嗯,可是说了半天他咋用呢,这个呢,我们来给大家看一个啊来,我们回过去把这个拿过来,咱们拷贝,拷贝以后写上一个零二啊,写上一个零二。然后呢,我们点击OK,嗯,放过来,放过来以后大家看啊,我别的咱们都给它去掉,咱们不要了,然后呢,我们来写上来,写上我们叫做什么呢?叫创建啊或者获取吧,获取我们叫系统的累加器。嗯,这句话是什么意思呢?是因为咱们Spark呀,啊,Spark它默认啊,默认就提供了简单啊,咱们写上叫简单数据聚合的累加器啊,就是这个数据结构啊,默认就提供了那么几个,你可以在嗯简单的这个场景下去使用,没问题啊,那怎么来呢?咱们叫SC,咱们叫做DR,它有一个叫做long accumulator。
13:14
这个为什么叫ACC,咱们的起名就是它叫IQ mill,它叫做累加器,也称之为叫采集,对吧?嗯,好了,那么这个地方我们给它起个名,就是你这个累加器啊,有的时候我们需要在UI界面当中去监控一下,给它起个名咱们就叫sum,诶好了,然后在这边呢,我们就起名叫做sum,就没有任何问题,所以啊,你现在把这个累加器就拿到了,那么你拿到了以后啊,我为了准确起见,我起个名叫some ACC吧。那么你累加器的目的是什么?它的目的是累加数据,将数据的值啊进行更新,所以说那么我们前面RDD的点for each,那么我们的每个number就可以做累加了,那么可以做累加的时候呢,把这个呢放过来,咱们叫做点,咱们叫ADD。
14:03
把咱们的这个我们的number传进去,你传进去以后记住了,它的这个是个浪的一个累加器,它会自动的数值累加,诶没有问题,那好,那你现在是我们的什么,咱们就写上来,咱们叫使用。累加器,那我接下来呢干嘛呢,你得把最终结果拿到呀,所以获取累加器的值,那这个呢,就是打印了,咱们叫print,因为你前面循环遍历,挨个遍历嘛,遍历完了这个累加器的值就变了,那我现在可以获取它的值了,其实说白了就是它的一个结果,所以点它有一个叫做Y6,这个Y6呢,我们现在呢,可以来运行啊运行。运行以后看结果。大家有会不会发现这就是我们的最终的结果,对吗?诶,没有任何问题,之前就不行,之前是零,但我们累加器就可以实现这个功能,哎,老师,那么我们的累加器难道只能用浪吗?其实不是啊,同学们看我们的SC点,我们除了浪以外还有什么东西啊,咱们叫double accumulator,还有SC点,我们这里呢,写上叫collection accumulator,所以啊,它的这个累加器的类型呢,其实有浮点类型啊,有整形啊,还有我们的集合类型,不过这个集合类型啊,这个咱们稍微的说一下,咱们点一下点点完以后呢,点一下它里面是什么呢?是YouTube.list是这样的一个集合类型,那也就意味着如果想用map之类的话,可能还需要稍微的变一变,这个咱们另说啊,先不管它,就说明我们系统呢,其实自带了一些累加器,Long double和collection,好吧,同学们。
我来说两句