00:00
接下来我们真正要做的就是呃里边的这四步了,那么这四部的话,大家想一下,呃,我们简单来讲还是把它提成就是封装成不同的函数吧,这个可能我们会看起来舒服一点。我们先定义一下,比方说这里我们定义一个最近的case评分,我们叫user recentlys,它应该等于等于什么呢?我们叫get user。大家不要嫌这个名字长,因为我们这里定义的长之后回顾代码的时候好理解对不对?那么这里边大家想一下,我需要传入什么数据呢?K4评分是不是先得把这个K传进去啊,对吧?那我们这里的K是什么?K是之前定义好的那个常量,对不对?我们是不是定义了一个max,是不是有一个user ratings number啊,哎,我们定义了一个二二十,把这个传进来,然后接下来大家想到还应该传什么呢?Red里边获取当前用户的评分,大家会想到我是不是应该用当前的UID去查啊,所以这个UID我们race里边肯定是根据这个UID去做存储的,所以要把当前的UID存进去,那然后还有什么东西呢需要呢?
01:20
哎,是不是要把那个red的连接要传进去啊,对吧?那这个是不是就是connect helper里边的,现在就可以派上用场了,对吧?这是我们获取评分的这个过程,等下我们再解决这个报错的,然后大家会想到接下来我们获取这个备选电备选电影列表,我们是不是应该得到一个candidate movies,对吧?大家想象一下,这里边我们定义一个函数,那这里边get candidate,我们其实的做法是不是找出最相似的N个电影啊,所以这有点像我们那个top n的那个选取对不对?所以我这里就叫get top seem最相似。
02:07
然后movies定义这样的一个函数,那大家想这里边需要传输什么参数呢?还是一样的,你这里前面是K4评分,这里是N个电影,我这里是不是还有一个N需要先传入啊,啊,这里边需要需要传入的是也是定义好的是不是max c movies啊这就是我们说你到底选多少个对吧?然后大家想到哎,我们是不是要根据当前电影的mid去选啊,所以要把mid放进去,然后还需要什么呢?呃呃,连接,大家想这个需要连接吗?我们是数已经现成了呀,都在哪里了?数是不是都已经放到了我们的广量里面啊,是不是那个相似度矩阵都放到广播广广播变量里面去了,对吧?那这里边广播变量我们是不是应该传进去啊,把这个broadcast它的值传进去就可以了,对不对?点VALUE6传进去,另外大家回忆一下,我们当时说还需要什么东西来着,我们取那个当前相似电影的时候,备选电影我们是不是就应该做一个筛选啊过滤,过滤掉什么呢?我已经看过的电影是不是你就不要再给我推出来了呀?对吧?那备选的时候我是不是就应该先过滤掉就可以了啊,当然我也可以全选出来之后,后面过滤都一样,对吧?这一部过滤的话,那大家会想到我是不是应该。
03:41
对,把UID传进去啊,要不然我怎么知道跟谁,就是这到底是谁看过的电影呢,对不对,所以把UID传进去,大家想到这个UID相当于我们到时候就还要去干什么事情了。根据这个UID就要做什么事情了。
04:04
根据它过滤对吧?怎么过滤呢?是不是先要查出来他历史已经评分过的电影啊,那么查历史已经评分过的电影这一部要怎么做啊,大家就会想到这是不是就得到mongo里边用mango连接,然后用我们那个find的方法对吧?然后加上查询条件对不对?哎,UID是什么?就应该等于这里的UID全部都都拿出来对不对?然后我们可能做一些数据转换,就是这样的一种方法,那这里大家就会想到我们是不是其实还应该用mango的连接也要传进去啊,啊,这里边我们先想到,那大家会想有一个好处是我们之前mango是不是定义了这个影视参数啊,所以到时候我是不是可以啊对,大家用那种类似于客比化的那种形式,我们把后面定义一个影视函,这个函数定义一个影视参数,就可以直接把mango的这个配置它的。
05:04
这个呃,传输进去了对不对,然后我们可以在里边根据它的配置再去建立连接也是可以的,所以这里我们就不直接传连接了,好接下来还有一项是这个根据这个来算推荐优先级,那我们得到的其实是不是就是一个最后的实时推荐列表啊,所以我们就叫。Stream,我们最后要写的数据不是就叫那个,那个表名不是就叫streams吗?啊,所以这里我们要得到的其实就是这个列表,这个列表里边大家会想到我是不是定义一个方法,比方说叫compute movie scores,这里边需要穿什么,大家再想一下,哎,那家就会想到,那是不是上边我算出来的备选,我是不是要针对每一个备选电影去算啊,那是不是上边得到的这个candy类要传进去啊,然后他跟谁去做加权计算呢?是不是最近的K评分啊,对,这个是不是也要传进去啊,User recently ratings,那另外我们还需要传什么呢?啊,大家会想到在这个过程当中,计算的过程当中,是不是要找每一个备选电影跟他评分过电影的相似度啊。
06:28
大家想一下,我们当时的那个公式是怎么怎么做的,这公式里边是不是有评分,这个评分我们从redis里面拿到了,然后是不是还得有,就是这个备选电影跟当前评分电影的这个相似度啊,这个相似度是不是我们还得去查,从哪里去查?从dbgo DB里面查是吗?我们GODB里边的数据相似度证的数据不是都已经读进来了吗?哦,所以对我们这里是不是像上面一样,把这一串,把这个广播变量的value传进来,也就有这个矩阵类啊,而且大家会发现这个矩阵的形式里边我们已经做了改装了,是不是已经变成了map呀,查起来是不是会特别的方便诶,所以这就是我们前面做那么复杂的转变的一个原因,这里把这个value传进去,好,最后一步把它保存到这个mango DB啊,那当当然了,大家可以说我们也可以根据这相当于是一个re,对吧,我们可以把这个Rex和当前的UID是不是可以封装成一个这样的user Rex对象啊,或者如果说我们想要把这个样例类直接就不用的。
07:50
的话,其实也可以,对不对,我直接就把UID和mid直接传给一个方法,然后根据这个u ID mid直接去存是不是就可以了,好,那么我们这里就是,呃,因为大家想到我们在存存储过程当中,其实是应该要找到对应的那个UID去做存储的,对吧。
08:12
所以说这个时候我们还是直接把它传进去就好了,这里定义一个方法叫save data to mon monggo DB,里边要传入两个参数,是不是UID,然后还有前面得到的strings推荐列表,对不对?这样存进去就完事了。好,那接下来大家看,我们就要把这个变红的这四个函数一一实现,就完成了我们的任务。我们现在要实现的是这个从release里边选取用户最近K4评分的这一个函数,那大家已经把这个对应的参数写进来,返回值是一个瑞,对吧,里边的是int mid和score的一个这样的一个元组。那么我们从。
09:06
它里边会去读取当前的这个用户的评分,对不对,那么大家会想到这个red red里边的数据是什么样子的一个结构呢。我们这里边业务系统是有定义的,在redis里边,我们对用户的这个评分,它存在一个叫做大家看啊,UID冒号后边跟UID这样的一个队列里边。大家看啊用户呃,评分数据保存在UID,哎,呃,就是UID后边跟着这个UID,这是表示一个变量对吧,假如我们当前的UID是一的话,那就是UID冒号一对不对就是。叫做这个名字为名为为K值的对吧,为K的。
10:05
呃,这个队列。队列里,那么它里边的值是什么呢?里边的值,哎,那就是我们的一组平分对不对,那里边的value。是每一个mid,然后再冒号score,所以大家想到就本身它这个队列名字就叫做UID冒号一,比方说对吧,第一个用户它对应的这一个评分数据就保存在UID冒号一里边,这整个这个是一个它的名字,对对不对,在red里边,我们是不是经常这么去做啊,经常去用这种方式去做存储,然后它里边的value是什么呢?这是一个队列,这是一个列表,里边每一个元素的值是mid,然后SC是这样的一个形式,好,那所以我们这里边读取的时候是不是jeice,呃,那大家知道我们现在是不是要做这个list的操作啊,队列的操作对不对,那list的操作大家知道是是可以怎么样去筛选它里边的值呢?查询里边的值怎么样去取呢?
11:20
Red操作大家还记得吗?我看一下我这里面起不起red啊,我这里面起着red的,大家看一眼起了一个red之后,我们如果直接看一下这个case,其实里边是不是能看到这样的一个,呃,就是看到我们当前所有的这个key对不对?呃,所以整个red大家认为是一个大内存,那就是一个k value的一个存储,那大家看我这里边就已经有这样的一个列表了,对吧?那UID冒号一,这是一个K对不对?它里边存着值,那么它本身是一个是一个例子的一个队列,那它里边的值是什么样的形式呢?我们想看这里边的值是不是可以用L这个这个命令啊,那后面跟KK是UID冒号一,那start,比方说从零开始我们取五个,大家会想到,诶,拿出来的值是不是就是这样的一个类型。
12:16
那每一个值是不是都是一个mid对应后面一个评分这样的一个数据啊,哎,所以大家看其实就是这样的一个状态啊,所以这个还是。啊,还是比较简单的对不对,但大家只要知道我们这里边存的数据的形式就可以了,所以我们这里用这个je,有了这个red连接之后,我们去做操作,是不是也是同样调用它这个有L命令对不对?它的这个方法我们用这个接口来做操作,那里边它是不是第一个也是K啊,大家看第一个参数是不是就是KK是不是可以是一个string。啊,所以我们这里边string应该是什么?是不是UUID冒号再加上,哎加上啊加上我们的UID呀,对不对,这是第一个参数,那第二个参数刚才大家看到了,是不是有一个start有一个and呀,我们的start是不是从零开始,And是不是就是直接选几个and是几就可以了,因为它刚才大家看到啊,我是不是选的时候零五是不是选出来,哎,大家看我这里边给的这个值啊,其实是。
13:29
就是start and是不是完整按照这个数量去取的啊,所以如果我从零开始取的话,取到五是不是相当于取了六个啊啊,所以是这样的,那大家这里如果要是更严谨一些的话,那其实得去看这个它本身的这个实线到底是什么样子对不对?这里大家如果不较真的话,我们多一个少一个是不是没太大区别啊,对吧?如果要是较真的话,那我们可能得点到这个red的L方法里面去看看它到底的这个and到底包含,就是得看这个L运具体的实现它的那个and到底包含不包含我们最后一个值对不对啊,当然了,就是我们调用一下,大家如果呃能够就是看到结果的话,其实也很容易能能能知道他这个状态啊。
14:17
哎,我们现在是不是这里的这个程序还起着啊,啊没起着是吧。好,所以这里我们就不给大家详细说了,这里我们就直接把这个number放进去就可以,大家如果要是觉得他可能应该是number减一的话,按照这个数量,那我们就给一个number减一对不对?好,我们就按number减一吧,然后接下来取出来的东西,这是不是就是这里大家看到的这样一个列表啊,啊,所以相当于是一个数组对不对?那我们其实想把它是不是还要做一个转化,它是冒号分割的对吧?所以对这个数据去做一个处理,做一个转换,那么map对每一项做一个操作,什么操作呢?呃,那大家会想到是不是还是可以做一个切分的操作啊,按照冒号去做切分item点。
15:20
诶,大家看到这里边不能,诶大家看这里边没有这个map方法对吧?L range出来的这个数据我们看,因为它是一个这是Java代码对不对,所以它返回的是一个Java的list对象对不对啊,那大家会想到这里边如果我们在SKY代码里边直接对它要做转换的话,可能就不行了,对不对?呃,这里边我们需要去引入一个东西。引入一个什么东西呢。之前大家讲过这个Java和SKY互相之间数据结构转换的这这些东西吗?大家看啊,skyla.collection里边有一个叫做。
16:01
JA Java conversions的这样的一个一个类,对吧,我们把它里边的东西都引入,然后大家看现在是不是就可以用这个点map方法了,对吧?所以本身这个呃,Red也是基于Java的嘛,所以它返回的东西里边的底层代码实现都是Java代码,我们这里要调它的Mac操作的话,得引入这个Java conversions好,这里还是注释一下啊,大家可能为了呃这个red操作返回的是Java类,为了用map操作。需要引入。转换类好转转换包吧,啊就就就那就好了,大家知道他是做什么事情就好,这里我们可以split了,对吧,那我们现在是根据什么去做split呢?是不是应该根据冒号去做SPT呀,因为大家知道。
17:12
具体每一条每每个评分又是。以冒号分割的。呃,两个值对吧,所以我们以冒号做分割。那大家会同样会想到冒号在我们这里正则里边是不是也要做转移啊?呃,所以又是两个反斜杠,接下来我们真正要返回的是不是就是取出来的ATTRIBUTE0,分割之后大家想到这里边我们是mid score对吧?那分割之后的ATTRIBUTE0是不是就应该是mid啊,对吧?所以这里大家可以想到,呃,字符串我先做一个tri,然后是不是可以把它to int转换过来,这就是我们的mid对不对?那后边还有ATTRIBUTE1是不是对应到这里就是一个score,同样我们可以把这个字符串做一个tri操作,然后to,它就不是tot了,Score是不是to double啊,这样做一个转换就拿到了我们呃想要的数据结构,我们现在只是把这个做了一个,这样的操作。
18:41
哦,那大家会想到,呃,最后我们返回的应该是这样的一个数组啊瑞对不对,所以我们在这个map操作完成之后,是不是再把它拓瑞做一次转换啊,啊,这最后返回的数据结构是不是就跟我们定义的完全一样了,里边一个int double对不对?哎,然后外面是一个array,好,这就是我们的这个操作那。
19:09
大家会看到就是在我们这个整个的这个函数里面,方法里面,呃。只有这么一句,那它的返回值是不是就是我们整个函数的返回值啊,所以我们最后突完瑞之后返回就可以了,这是我们第一步操作,看一看上面有没有报错了,没有了对吧?好,第二步我们接下来要取的是。哎,这是在相似度矩阵里边取出最相似的N个作为备选列表,我们要定义get top。这有点慢啊,See movies对吧,我们要把这个定义出来啊,那这里大家想到我,我这里边给的参数分别是什么呢?第一个参数大家看一下是什么,这是不是又是一个number啊,就是到底选多少个对不对,还是给一个number?第二个参数是什么呢?
20:06
M mid UID对吧,所以后边的两个我们定义成mid和UID,第一个应该是m mid啊,最后一个这是不是我们的那个相似度矩阵广播变量啊,里边的值对不对,所以我们这里边把它定义成就叫相似度矩阵吧,Same movies,好,那么大家看关键是后面这个它的它的类型是什么呢?哎,我们如果这样去定义好的话,大家看一下这里还是报错的对不对,大家看报什么错。大家看type Miss missmach对不对,呃,那他需要的这个类型是什么呢?我们这里给的。大家看啊,我们这里本身这里它的实际的类型是不是应该是skyla collection里边的map啊,外面的这个map是collection里面的map,里边的这个map是一个collection里边的immutable.map对不对啊,是是不可变的一个一个map类型,所以它的数据类型应该是这样,而我们这里如果要什么都不指定的话,它是不是默认里边的这个skyla里边的map是一个prefer DeFine下面的map呀?
21:23
所以这里大家要稍微注意一下,我们要针对这个做一个数据类型的转换啊,那这里的话,我们就只好把这个完整的这个写过来了,对不对?大家如果要嫌烦的话,也可以直接从这个我们的大家想collection.map对吧?呃,这是外层的这个map,里层的这个map的话,它应该是在sc.collections.imutable里边的map对吧。我们把这个定义好,现在看上面是不是就没有错了啊,所以这是大家需要注意的一点,大家如果觉得这个写的很烦的话,可以直接从文档里面copy啊。
22:06
呃,然后大家想他有没有返回值呢?有没有返回值,大家一看这么多这个这个东西已经已经晕了是吧?肯定有返回值,对我们当时是不是已经定义好了后,不要返回所有备选列表mid的一个array啊,哎,所以这个其实这返回值倒简单啊,就是array里边是不是一个int啊啊,所以就是这样的一个值,然后我们把它实现出来就可以了啊,那这里边大家如果想写的话,我们可以把这个对应的注释写进来,对不对,那这里边本身是做了一个什么操作啊,做了一个呃,获取备选电影对不对。呃,跟这是这是当前电影最相似的,呃,Number电影对吧,作为备选电影,这是它的这个。
23:18
我们想要达到一个目的,那这个是数量对不对?呃,相似电影的数量,然后这个呢,Mid对吧,当前电影ID都很简单啊,Mid对吧?啊,我们就叫ID吧,大家知道就可以,呃,当前评分用户IDID对吧?最后还有一个啊,是不是相似度矩阵啊,相似度矩阵当然这是我们从广播变量里面拿出来的,那最后return的是什么东西呢?我们应该是一个过滤之后的。
24:04
是不是备选电影列表啊,是不是这样,这里大家就注意,我们既然是根据这个当前用户ID,是不是要做他看过的那个过滤啊,那我们过滤的时候是不是想到这里用到mango对不对,那你这里面没有mango的配置呢?哦,那我们把这里是不是可以再加一个影视参数啊,这个有点东西多了,对吧,我们把它放下来吧,是不是可以implicit定义一个mango。Configig,对吧?啊,把对应的这个mongo conig拿过来啊,那当然了,这里边我们就不写了,对吧?Mongo config,这是mongo的这个配置项,对不对,我们直接把它放在这里就可以了,好,所以大家可以看到就是整个的这个过程看起来代码还是有点绕,有点复杂的,但是如果我们梳理的思路很清晰的话,呃,也就还好,对吧?那接下来在里边我们是不是就是应该呃拿到所有的这个呃相似的电影,然后一个一个去,然后再获取这个,我把这这里面的几部给大家写出来啊,第一步是不是呃。
25:18
从相似度矩阵中拿到所有相似的电影,对不对,相似的电影,然后第二部是不是我们要从mango?中查询。这个用户已看过的电影,对吧,那最后一部是不是就是过滤啊对吧?呃把。看过的电影过滤,看过的过滤得到呃,这个输出列表,这就是我们的三步。
我来说两句