00:00
我们现在其实想要的就是这两大拈,一个是啊,非个性化的基于统计的离线推荐拈,另外还有一个是个性化的基于的是盈语一模型的协同过滤,对不对啊,这两部分要去做离这这两部分实现一个离线推荐,好,那么首先我们会想到这个离线统计推荐服务里边,那我们首先还是一样,大家对于这个整体项目而言,我们是不是应该在recommender下边,这就跟data loader不一样了,对吧?我们是不是不应该放在这个下面啊,那我们当然是另建一个新的子模块对不对啊,就是还是父子项目的这个架构啊,然后这里我们这个art artifact ID就叫做statistics,这是统计的意思,对不对,Recommender。
01:00
我们就加上这个名字吧,同样这里大家注意一下这个路径啊,好好我们新建这样的一个子拈,呃,那么大家会发现其实在在这个所有的拈里边,我们的主要的程序是不是相当于相当于都只有一个,呃,这个skyla文件啊,本身大家知道skyla程序里边一个文件里边可以有多个类,所以说我们不需要像Java的项目那样,就是弄的呃结构非常复杂,我们是不是代码也不是特别复杂的情况下,直接一个目录下边一个文件,然后里边把该实现的功能实现就可以了,对吧?所以现这是我们现在的整体的一个想法,那我们已经创建了这个呃,Stat statistics recommend这样的一个项目,子项目,大家会想到,首先我们要来写一下对应的依赖了。大家想一想,这。
02:00
这个统计推荐里边我们需要哪些依赖呢?大家想一下,那首先我们跟这个data loader这边来来比对一下吧,我们data loader的那个POM文件呢,我们data loader里边是不是Spark号引入了,那统计推荐需要吗?需要Spark,呃,大家觉得不需要是吗?呃,应该也是需要的,对不对,对吧?呃,大家用到这个,呃,Spark核心组件,你一开始肯定还是得创建Spark session对不对?然后这些基本的操作肯定都是要有的,所以Spark肯定是需要,大家其实可以预见到之后我们只要是用这一套框架,其实Spark应该都得要,对不对?然后Spark cle要吗?啊,这个肯定要,对不对啊,我们肯定是要写CQ的啊,然后scalela library要吗?啊,对,这个也肯定要,接下来那monggo相关的这些驱动和mongo Spark连接器这些要吗?
03:09
大家觉得不要是吗?要吗?要还是不要,因为我们现在涉及到的一个问题是什么?是不是要从mango里边,对,现在不是往里写了,我们是不是要从里边读数据啊,因为现在核心的数据是不是都在mango里边,所以我们现在操作是要从mango里面读数据,那是不是还是得要mango的驱动和它的这个连接器啊,所以这部分是需要的,那最后这一部分以ES驱动和连接器,这个要吗?啊,这个就不需要了,对不对啊,因为大家发现这个ES其实我们前面写入进去之后,只是方便一个模糊查询,一个复复杂查询而已,对于这个统计推荐显然是没什么用的,所以。啊,其实这个很直观啊,我们是不是就把前边,那么大家再多想一下,我们还需要别的一些东西吗?Red统计这一部分大家觉得需要存到这个缓存里面去吗?好像也不需要什么东东西,对吧?我们之前设计架构的时候想的就是统计算出来之后,这也是一个离线计算,算出来之后是不是对应的存到芒果里边一张表就完事啊,诶所以看起来的话好像就需要这些,别的都不需要了,所以我把这些copy过来,里边的这个ES相关的东西删掉,这是不是就完事啊?诶这个倒是比较简单啊,所以大家看我们一开始的代码,基本的有有这样一个框架之后,其实后面代码可能写起来就会非踌,因为大部分的代码都是抄过来的,对吧?呃,但是这就是说啊,就是天下文章一大抄,天下代码也是一大抄,呃,但是关键就是说我们看对怎么抄,你知不知道到底。
04:54
哪些东西是自己要的,哪些东西抄过来,哪些东西扔掉,这个是比较关键的,呃,所以我比较建议大家的是,当然这个POM文件,呃,不一定非得全手敲一遍啊,这个无所谓,在我们其他地方的代码,我建议就是一开始的第一次实现的这部分代码肯定是都要手敲一遍的,对不对?后边如果涉及到类似的内容,或者说完全重复的内容,大家可以去抄啊,当然我们更好的方式是可能把它再抽象出来,封装出来,对不对,这可能是代码更好的一种实现方式,那大家如果要是从功能上去考虑的话,直接copy抄过来没问题,这个是肯定是可以的,但是你抄的前提是知道哪些该抄,哪些不该抄,对吧?啊,千万不要就是,呃,大家养成了,有有时候我们这个写代码程序员养成了一个坏习惯,就是什么呢?就是不管什么代码,一通先全抄过来再说,然后先运行,只要能跑出结果好,没事了,放在那儿不管了,对吧,呃,这个。
05:54
这是一个坏习惯,因为你如果养成这种习惯的话,那你就没有办法去对整个的框架,对整个的架构有更深刻的了解,对吧?你就没有办法去重构代码,让自己的代码变得更优雅,更简洁,那如果说你能够把这些东西都做好的话,其实程序员就可以进阶成一个架构师了啊,架构师跟程序员的区别在哪里啊,他就是可以看到我们平成可能只是把代码堆过来,能跑起来就完事儿,那架构师他是能看到更深深层次的东西,对吧?你这个地方为什么要用这些东西呢?是不是可以删掉呢?是不是可以重构呢?呃,大家如果从这个角度去考虑问题,这个思路整个看问题的角度就会更高一些。好,那接下来我们继续看,就是现在这个统计拈应该怎么做对吧,那既然依赖该该引入的已经引入了,接下来我们就码代码了,同样首先我们还是看一眼,看着这个Java不太爽,对不对。
06:54
呃,删直接删掉嘛啊,直接删掉也可以,删掉得重新建对不对,我这里重命名是不是最简单啊,因为大家如果删掉重新建文件夹的话,那有可能是不是还得到这个project structure这里来改一下这个source folds啊对吧?呃,这个源代码的目录要要不然呢?呃,对,大家可以去右击,或者说那个我这里直接双击就可以直接把这个打开对吧?呃,所以这个都是比较简单的一些操作,然后我们这里边resources里边不需要原始数据了,但是还需要一个,哎,对,这个log for g的这个properties是不是还需要啊,所以我们这个简单啊,直接把它copy过来完事。
07:38
好,这些东西应该都没问题啊,接下来我们是不是可以去new一个sky class啊,同样大家会想到我们这里应该是一个什么样的class啊,是class object还是?我们这里边是不是还是,哎,对,用一个单立对象,一个object直接离线的把它跑一遍main函数执行完,跑一遍完事儿,对不对啊,其实我们不需要任何别的多余的操作,所以我们还是一个单立对象,好,那接下来我们的这个名字还是加上这个,加上这个包名啊,com.at硅谷点这个前面我们就叫statistics吧,然后他的名字叫statistics recommend,对吧?好,我们创建了这样的一个单列对象,首先我们接下来是不是还是想要按照我们之前的这个路数,先去考虑建立一些case class对不对啊,考虑我们想要用到的一些数据结构,我们先把它包装封装出来,那大家可以参考一下data。
08:53
二我们我们又准备抄代码了,那大家会想到我们在这个统计推荐这一部分用到的这个数据,用到的样例类应该有哪些呢?Movie大家觉得要吗?统计推荐哎,大家想一下我们当时提出来的这个统计推荐,推荐是有哪几个统计推荐来着?大家看一眼这里的目录,历史热门,最近热门电影平均得分,诶看到这些平均得分什么的,这个是不是肯定评分数据要有啊,所以reading肯定要有对不对啊,这个就不用说了,然后大家看最后一个是不是还有一个每个类别的优质电影啊,Top就是每个类别里边的top ten对不对,这个是不是就跟类别相关,那是不是也得知道每个电影的基本信息啊,至少得知道类别信息对不对?所以是不是电影本身movie的信息也得有啊,啊,因为我们RA里边是只有评分信息,没有别的信息的,那我们类别信。
09:53
其是不是在这个,呃,Rogers这个这个这个字段里面保存着啊,所以大家想到这两个都是需要的,那另外一个这个taag需要吗?呃,Tag用户打的标签,这个好像就不用了,对吧?做统计的时候,如果说我们统计热门把这个也包含进去的话,当然是也可以,就是大家也应该把这个加进去,对不对?我们这里就简单实现,我们就按照评分的多少来评价这个热门,那我们是不是就这个tag就不需要了,所以我这里很简单把这两个直接copy过来,所以代码是一大抄,抄什么,怎么抄,这个大家还是需要自己考量好的啊。呃,然后接下来我们再看看还有什么,诶还有这个封装好的配置样例类,这里边我们要吗?
10:43
按照标准的这种方式,如果我们用到mango,是不是这里边也应该把这个mongo config封装过来啊,啊,这里边就是我们已经实现好的东西都不用实现了,所以这个也超过了,呃,还有一个是ES的类,这个配置类需要吗?啊,这个就不需要了,对不对?这里边既然没有ES,那当然就不需要了,然后我们继续来想,还需要什么东西呢?
11:12
还可能用到什么东西呢?哎,还需要的有可能就是我们最后推荐出来的结果,是不是要再写回到mango里面去啊,那写回去的这个数据结构如果比较复杂的话,我们还是应该再单独给它定义一个样例类,包装起来会比较呃,代码上会比较容易理解一些,对不对?呃,那大家会想到这是不是应该有四个表啊好,那我们回过头来看一眼啊,这四个表是不是一个是历史热门统计,那历史热门统计我们最终写进去的应该是一个什么什么表啊,那大家会想到这个其实是不是就应该是一个mid对应一个count就完事了呀?啊,当然我们也可以把这个再包装成一个样粒类,对吧?但是我们感觉这个好像有点太简单了,就好像就没必要再包装了,对不对,就干脆把它当成一个元组放进去就完事,对吧。
12:12
啊,这是这个历史热门,那最近热门呢,是不是后面加一个time吗?好像也没有复杂到哪去对吧?呃,那我们想到就是我我还是就是如果要是很复杂的这个数据结构,我再把它包装好了,这种的话,我们就用一次你就直接存就完事嘛,那平均得分是不是也很简单,大家会想到平均得分应该是一个什么样的样子呢?应该就只有mid和哎平均得分average,对吧?啊,这个也是非常简单,所以这部分我们也不做考虑,那最后我们考虑一下这个每个类别的top ten,这个最后存进去的样子应该是一个什么样子呢?那是不是首先它的这个K应该是一个电影的类别啊,某个类别作为K,然后后面跟着的是一个什么呢?
13:08
是一个top ten的电影啊,大家可能觉得是一个电影名对不对,那我们这里是不是有mid就够了呀,Mid是这里边电影的这个,呃,本身它自己的这一个ID值对吧,这个主键,那么大家会考虑我们这里边选出来的优质是按什么评价的优质呢?是不是按评分啊,那评分多少是不是本身还是有一个排序的,所以我们应该把评分的大小是不是也放在这个数据结构里面给出来啊,按照这个来排序对吧?那我们最后想到这个数据结构应该是一个什么样的状态,应该是最外边是一个类别。里边应该是一个列表对吧,列表里边每一个元素是不是又是一个mid和一个平分这样的一个元组啊,哎,所以大家想到其实这样的一个数据练习,这个看起来就比较复杂一点了,对吧?啊,那我们现在可以把这个定义成一个样例类放在这里来,好那么我们这里定义电影类别top ten推荐。
14:29
呃,样例类,呃,对象吧,就叫其实大家知道我这里说是对象,其实样例类对吧,Case plus,呃,我们这个叫什么叫类别,叫recommendation recommend。Station啊,这就是类别推荐对不对,这样一个阳离类,那大家会想到前面应该有一个什么,是不是它的类别啊,啊类别我们就还按照之前的这个都叫runs吧,然后string,这是一个字符串,后边应该是一个什么东西,后面是不是应该是一个列表啊,首先是对吧,是一个对,大家会想到是一个sequence啊,然后我们就把它叫做res recommendations对不对,推荐啊,推荐列表它应该是一个。
15:24
C,对吧,那么这里边的内容应该是个什么东西呢?是不是应该是一个mid和score的一个这样的一个组合啊,哎,所以我我这里因为这个相对来讲又特殊一点,我把它单独的放出来吧,啊,因为后边大家会想到这样的一个对象,是不是有可能在别的推荐里面也要用到啊,我把它单独的列出来叫做就叫做recommendation。大家会想到它里边应该有一个mid,是一个int,还应该有一个score评分,对不对?呃,然后它应该是一个double对吧?当然了,这是定义了一个,呃,我们叫基准推荐对象对象啊。
16:21
所以这里边我们的这个序列里边是不是就它的数据类型放的是recommendation啊,诶这样是不是就符合我们的这个要求了,这就是为了我们最后这个复杂的类别推荐专门创立出来的一个样例类,对吧?啊,大家知道这个要做什么事情就可以了,然后接下来我们就进入到真正的这个对象里边去,我们一开始按照之前的套路,是不是还是先定义一些常量啊,哎,我们当时的常量首先是定义了这个读取文件的路径,这个也不需要,对不对?然后接下来大家看一眼,诶,我们先接下来这个man里边的表名,这个要吗?这个肯定要,对不对,因为我们要从这里边读数,对吧?那我们要哪几个呢?啊,大家会想到是不是movie和RA这两个都需要啊,因为我们跟这两个表都有关系,对不对?好把这两个copy过来,这里边定义表名。
17:21
然后大家想一下,这是我们要读的数据,另外我们还有什么,还有要写的数据对不对?要写的数据我们最后是不是每一项推荐都写入到芒果里面是一张表啊,所以我们是不是应该定有四四种推荐方式的话,那我们是不是要定义四个表啊,诶,所以这里边我就直接参考这个这个代码里面写的东西了啊,诶是在哪里写着。应该是在最外层,哎,这里大家看到统计表的名称,哎,这里边是不是给了这样四项啊,当然这里边这个本身的英文的这个名字可能给的不是特别好啊,大家知道大概是什么意思就可以啊,比方说这个RI more movies,就是就是评分比较多的,打分比较多的,对不对?那所以对于我们而言,这是不是就是一个热门统计啊,对应后面还有一个more recently,这是不是近期评分多的,这是一个近近期热门统计对不对,上面就是一个历史热门统计啊,最后还后面还有一个average movies,这相当于是平均评分统计,对不对啊,大家知道什么意思就可以,尽管这个表达不太不太好啊,然后这个runs top movies,大家就知道它是,哎,按照类别的top对吧,这样的一个对应的统计,好,哎哟好,我们把它直接复制过来,我们要的是这几个表,最后写入数据写进去就可。
18:52
可以了,呃,把这些预先都定义好之后,接下来就是main函数了,对吧,我们在main函数里边一开始是不是还是先定义一个什么来着,诶是不是定义这样的一一些配置相关的东西啊,我就直接先把这个先拷过来吧,这里边我们要什么不要什么Spark course要嘛,啊,这个肯定要对吧,因为我们一开始是不是创建这个Spark的时候肯定要啊,然后mongo UI mongo DB mongo相关要对吧,因为我们对mongo有操作,然后ES相关的这四项,诶这是不是就删了,对这个没什么用,好,这一部分已经定义好,接下来大家会想到是不是要做哎,创建sparknig,然后创建Spark Spark session对不对,然后引入相关的一些包,然后我们是不是就可以把数据加载进来了,诶,那前面的这些步骤大家会想到是不是还是一。
19:52
一大抄啊,至少我可以抄到这儿对不对,我创建一个Spark con,然后创建一个Spark session,然后是不是引入这个影视的包啊,我把这个Spark session和span都引入进来,然后接下来大家看到还有哪些东西能抄呢?我们先看这个能抄哪些代码,对吧。
20:13
还还可以抄哪些东西,呃,加载数据,这个加载数据的过程,可能我们处理这这个显然就不一样了,对吧,我们这个是从文件里面加载,现在我们是从mango里边读取了,这个显然不一样,呃,那后边还有什么可以抄呢?诶大家想那那这个mongo config这个是不是也可以抄过来啊,啊对,大家可以想到这个还是一样的啊,所以我把这个也抄过来啊,这里边。我我不要放在这个,因为我上边本身这个类就已经定义了mon,对不对,就不要引入这个别的这个类了,好我把这些能抄的都抄过来之后,接下来是不是就可以加载数据了,从mongo里边加载数据。
21:04
呃,这里边我们的加载数据大家会想到,我们也可以先去创建一个,呃,到这个mongo DB的连接,然后用标准的这个mon client大家去做操作,对吧,后面就是DB,然后collection name,然后做这个操作,或者我们还有一种方式,是不是用之前讲过的这个比较快捷的方式,用这个monggo Spark connector这个连接器,是不是可可以之前我们是直接点save,直接把这个数据存进去,那同样对应的大家可以想到我们是不是可以有很快捷的读取数据的操作呢?呃,那这里边同样我们可以用这个方式啊。我们定义一个啊,首先大家想到我们这个rating数据非常重要,对吧?前面的这些评分,相关的这些统计是不是都跟RA有关系啊,所以我们先加载这个RA数据,加载成一个data frame吧,呃,那我们调用这个Spark session里边的点read方法,大家看到这个里边是读数据,肯定就不是调这个呃,Data frame的writer了,对吧?我们这里就是直接调这个Spark session的read方法,然后它read可以加什么参数呢?对,是不是可以加这个options啊啊,Option,那么这里同样跟之前其实大家看到写法是很类似的,Monggo config里边是不是有UI,然后option。
22:35
是不是还可以有collection表名对不对?我们现在要从哪个里边去读呢?我们现在要读的是评分表对吧?那是monggo reading collection对不对?前面定义好的大大家回忆一下啊,这里定义好的是不是mongo RA collection对吧?啊,这里可能因为大量的代码从那边copy过来的话,可能过的会稍微有点快,大家就是如果这会儿就是有一点细节不太了解的话,大家先把整体的思路跟上,知道每一步做什么就可以。接下接下来细节大家可以敲代码的时候自己再去琢磨琢磨好,那呃,然后我们是不是有了基本的这个配置之后,我们可以form ma了,对不对?大家想这里边就没有那个overri那个mode了,因为这不是写入,对不对啊,就不需要用那个mode了,那这里的format用什么呢?跟之前一样,是不是call?
23:36
com.mongo db.spark CQ啊这样的一个form对不对?然后之前我们写入的时候是点save,现在我们读取怎么样呢?大家看有一个是不是load的方法啊,对,我们直接点load就可以把它加载进来啊,就是这样的一个操作,呃,那当然了,Load进来我们可能还需要把它做一个转换,我们load进来的这个数据是不是对应到就是对大家会想到哎,Case,对,Case class对吧,哪个case class呢?是不是就是reading啊,我们这里定义好的RA,所以我们是不是可以把它as rating,这是不是转成了这样的一个data set啊,对吧?那当然我们如果想要的是这个data frame的话,当然大家直接习惯用data data set做操作的话,Data set也可以,对吧?啊,我我的习惯是喜欢把它转成data frame,所以呃,就是大家把这个转也可以。
24:36
不转其实也行,因为大家知道data set对应的一些操作是一样的啊好,呃,那这里我们是先把rating数据加载进来了,那大家会想到我们还有一个什么数据要加载来着,是不是还有movie啊?那其实这个好说已经实现了,我们就不详细敲了啊,这里是不是再去定义一个movie df啊,同样还是Spark session的read方法,然后对表名得改对不对?大家只要知道哪些哪些得改,哪些不能不能改就可以了。那接下来这个as是不是也得改啊,As什么对我们的case class里面定义好的as movie,最后再转成data frame,对吧?这就是我们想要做的事情,然后这里边大家会想到我要把这些东西都已经拿到之后,呃,然后我们是不是就可以去写CQ了,做做对应的这个统计查询对不对,然后拿到不同的统计结果。在做这个操作之。
25:36
前大家回忆一下,我们在这个当时给大家讲写那个PPT里边是不是讲到了我们写的那个CQ啊,我们我们写的CQ是不是得从一个一个表里边去取当前的一些内内容啊,那大家会想到我是不是应该对于这个呃Spark程序来讲,是不是应该创建一个临时表啊,对吧?我我在这里是不是应该创建一个呃,Temple view啊呃,大家应该之前也熟悉这种操作对吧?那我们把这个前面用data frame的话,这个是不是就非常的简单,可以调它的这个create or replace temple view方法对不对?这个大家之前用过吧,创建一个我们就叫ratings,创建一个这个。
26:25
好,创建呃,名为ratings的临时表啊,当然这个其实应该叫视图对吧,VI应该叫视图,大家认为它是一张表就可以。接下来大家会想到是不是就可以从这个表里边查数据,然后去把我们想要的东西全拿出来了啊,当然这里我们给一个todo吧,等一下我们再说啊,就是呃,不同的统计推荐结果,好呃,那当然这里边大家会想到我们主要是有哪几个呢?我这里面写出来,第一个是按照我们这里定义好的来啊,还是看这个文档吧,第一个是不是历史热门电影统计啊,好,所以我们这里是历史热门统计,我们用的是什么呢?是不是历史评分最多啊,对吧,评分数据最多。
27:44
然后第二项我们讲的是近期热门统计对不对?我们的主要的想法算法是什么呢?是不是就是按照时间戳,然后把它提取出来,然后写成一个按照年月排序的一个这样的一个字段,对不对啊,把它转成这样的一个字段,然后根据年月做一个呃,做一个group by对不对,然后把它聚合起来之后再去评价,评分最多的,所以我们是按照呃这里给大家写出来啊,当时我们讲PPT的时候这种格式对吧?
28:28
筛选选取。最近的评分数据。统计评分个数,所以本质上我们这个都是按照评分个数的多少来算的,对不对,好,然后接下来还有第三个,第三个做什么事情呢?啊,是要看一眼啊平均得分对吧,所以就是优质电影推荐。
29:03
那么这是统计电影的平均评分,大家会想到这个应该是最简单的一项了啊,平均评分最后还有一项,这个可能会最复杂,对不对啊,这个是个类别电影top统计。所以这一部分的话,哎,我们可可以用CQ去写,当然会比较复杂,对不对,我们也可以去用这个Spark CQ里边的一些算子去给他做一些操作,到时候我们用算子的形式给大家做一个呃处理啊好,那这一部分东西如果都做完之后,呃,那当然了,我们这一部分统计结果最后是不是要把它写入到对应的表里边啊,如果写入的表都已经都已经写到mango里边去之后,最后我们这里就可以,呃,Spark Spark stop直接关掉就可以了,整个内容结束对不对,这就是我们整个的这个程序框架。
我来说两句