00:00
呃,先看这个从相似度矩阵里面拿到所有的相似矩阵,那我们先,呃,就是所有的相似的电影,我们先给一个这样的名字叫all same movies吧,所有相似的电影对吧?呃,那么这个从哪里拿,是不是相似度矩阵已经在前边,是不是传过来了,我们我们这里是不是就是定义的这个参数啊,Same movies,所以从这里呢,怎么拿呢?跟当前电影相似的所有电影,大家会想到是不是诶直接就一个mid传进去,是不是就拿出来了呀?啊这里大家注意一下我们拿到的东西是什么呢?对,大家注意后边是不是我们也把它的那个rap本来是个列表,现在是不转成map了,大家想到后边我们是不是还想对它去做过滤做排序啊,啊,当然map做过滤是还可以,但是如果大家想如果你这里想要直接去salt一下,是不是就没办法salt了,哎,所以我们考虑是不是把它再转回到。
01:07
数组转成一个AR啊,呃,所以大家看这些操作其实都是有我们自己的一些考量,有一些想法的啊,这一步很简单,一行搞定,然后接下来我们要从mongo里边去查已经看过的电影对不对?好,那我们就看这个叫看过啊,我们就叫那个RA exist吧,因为大家想我们这就是找它已经存在的评分对不对?那么已经存在的评分怎么去查呢?我们是不是要用当创建一个monggo client对吧?那monggo client我们之前是不是已经在连接助手里边有monggo client了,现在是不是要把它调用起来,所以connect helper里边的monggo client现在就用起来了,当时我们是懒加载的,现在呃,真正用到的时候它才创建出来,那大家还记得我们当时这个Mo client怎么用吗?是不是里边要传入D。
02:07
D,对吧,Monggo config DB,然后后边啊,它这个也也有点像是这种客体化的这种形式,对不对啊,当然大家感兴趣可以看看它里边到底源码是怎么实现的,我们这里就直接会用就可以,那后边是不是要把那个表名要传进去啊,相当于我们在命令行里边,前面是前面这个操作相当于是DB,后面是DR,我们的表名对不对?那这个表名是哪个表啊,我们要查哪个表,对已经评分过的电影,那应该是monggo rating对吧?诶后边大家知道要做什么操作,是不是要find点啊,是不是从这个表里边要去做find的操作,就像我们在命令行里边find的一样,对不对啊,这里find的什么呢?大家会想到这里,我们因因为这里要给一个查询条件,这里我们传入的都应该是一个monggo DB object,对不对啊,所有在这个client里边做操作的时候,传入的数据都是这样的一个对象,那里边它应该又是什么内容呢?这是不是就是我们要指定按照哪个K哪个值来查对不对,就相当于我们在前面给的筛选条件里边是不是有一个KY6对啊啊,我们现在要的是UID,这个K对应的值就是我们的UID对不对?
03:35
所以大家看这里边的写法是把它写成一个。Map的这样的一个元素形式。然后把它转成一个monggo DB object传进来就可以做筛选了,呃,就就这么简单,当然了,这一步我们就必须得有这个mon mongol client才能做,对不对?呃,这样的这个命令行类似于命令行的这种命令,必须得用它来做查询,那接下来大家会想到这个查完了之后,我们是不是就得到了一个。
04:11
当前用户所有的评分啊,好,我们同样还是把它转成一个瑞,转成一个数组,接下来我们最后想要的是什么东西呢?做一个外部操作对吧,这里边的每一项大家想到我们最终主要是要要什么东西啊。大家会想到这里边选出来已经评分的项目,是不是应该是有一个mid,然后还有一个评分的SPA,我们最后想要的是什么呢?我们想要的是不是他已经看过的电影啊,只要是他看过的,是不是就应该从上面要筛掉,那大家想那个评分我们是不是并不关心啊,我们最关心的其实就是要拿出一个mid是不是就搞定了呀,所以我们把它直接做一个转换,那么就是不是get大家想到这个mid对不对?呃,因为这里我们本来返回来的这个find出来之后还是这样的一个,呃,我们保存成了一个数组,Get出来之后呢,大家会想到我应该去把它to int对不对,但大家看到诶这个盖子之后,好像它返回的这个这个东西我们不能直接去to,对吧,那这怎么办呢?
05:37
呃,大家会想到它至少是可以to string的,对不对?那我们拿到这个数,我们先去做一个to string,然后再把它to是不是就可以了啊,这个大家注意一下,因为在skyla里边强数据类型大家一定要考虑清楚我们最后要的是什么,那之后我们要去做处理的时候,Mid对应的类型是int,所以我们要做转换对不对啊,相当是做了一个强制数据类型转换好,我们把它转成in之后,最后得到的这个数组是不是就是一个所有已经看过的mid的一个列表啊,这样的一个数组对吧?啊,这就已经达到我们的目标了,接下来我们要做的就是做一个过滤,过滤的话是不是直接用all movies点。
06:26
这个我。大家会想到这里边它的我们在这个all movies里边,它的元素我们拿出来之后。本身是不是就是一组mid和score这样这样的一个一个元组构成的一个数组啊,那么我们在filter的时候是按照它的什么去filter,是按照mid还是按照score,是不是要按照mid score,呃,Mid去做filter,对吧?我们是不是要看m mid是它的第一个元素对不对?那是不是要看它的第一个元素在不在这个列表里边啊,对不对?所以我们是不是可以直接用在不在这个列表里边,我们是不是可以用RA exist直接看它。
07:23
大家看是不是有contains方法,是不是contains了,我们后边的这个。第一个元素,也就是当前的这个m mid是不是就可以判断出来它在不在我们已经看过电影列表里边对不对,如果这个是表示它在里边,呃,我们是不是想要它不在里边才把它筛选出来啊,所以前面是不是还要加上一个取反对吧,取飞,所以这是我们的筛选条件好,然后大家会想到筛选出来之后,我们是不是还想做一个呃,排序啊排序输出对不对,那么呃,我们这里就T就可以了,对吧T。
08:07
Salt的时候,我们就不应该根据它的第一个元素mid做salt了,而是根据SC做salt,那是不是第二个元素啊,我们一项的写法是不是这样啊,是不是第二个元素大于这表示一个降序排列对吧?那后边同样我们的思路是可以take它的前numberg,这是不是就是我们返回number前numberg这样的一个列表里边的电影啊,作为我们的这个候选项对吧?那当然了,这里边是不是既包括电影又包括评分,哎,大家会发现其实我们最后我们只想要的就是一个电影mid的一个数据就完事,对不对?我们只用作备选,它的评分暂时不考虑,所以我们这里边再map一下啊,当然这里就不用我们是不是直接把X map成它的下划线1MID拿出来map过来。
09:07
哎,是不是就完事了,哎,所以这就是我们整个的这个操作得到了,最后得到的是我们的最相似的。几个电影number的电影,那么而且我们做了一个这个过滤,已经看过的把它筛掉,这相当于就是我们当前的一个备选电影列表,对不对?哎,我们现在是做完这一步了,好,继续看,拿到了备选电影,而且前面我们已经得到了最近的K4评分,按照我们的公式,是不是该有的东西都有了呀?大家回忆一下这个实时推荐的算法公式里边是不是该有的东西都有了,每一次评分这个是不是在我们的最近评分里边有啊,然后相似度,我们要算的是不是最近K4评分和每个备选电影的相似度,那备选电影有了,这个我们的最近评分的电影也有了,我们是不是根据他们的mid到相似度矩阵里面去找,就能找到这个相似度啊啊,当然了,这个个数很容易统计出来,我们除以这个个数,得到他们这样的一个加权平均数,然后再根据它当前这个评分的高低,我们统计一下高分和低分的数量,对不对,统计出来之后,是不是后面就有了这个偏移向啊。
10:25
呃,奖励和惩罚,最后就可以算出每一个备选电影的推荐优先级,或者说推荐评分,对吧?那么这一部分我们显然就可以带公式去做了啊,接下来我们要做的就是第三部分内容计算推荐优先级啊,我们DeFine前面我们写的是一个compute,对吧,Compute movie scores,那大家看到这里边要传入的元素,第一个是什么?A ret,我们当时定义的是不是要把这个candidate movie全传进去啊,所以这里我们还是定义一下啊,Candidate movies,然后第二个这个array是一个int double类型的一个array,我们当时定义的是什么?是不是最近的评分啊,User recently ratings,好,我们把它还是直接传进去,这个名字还是叫这个啊,大家方便考虑一些。
11:25
然后还有一个参数,这个参数有点多了,我们直接把它回车下来吧,最后还有一个参数,是不是我们要传的这个相似度矩阵啊啊,那这个数据类型我们还得改对不对?大家看上面还有那个Miss match呢,所以这里我把它直接copy改过来。好,现在我们看一眼。诶,看起来没问题了,对不对,现在的类型是对的了,所以我们接下来要把它做一个实现,它有返回吗?大家想一下这肯定是有返回的,对不对,最后得到的希望得到一个,诶是不是就是当前的这个推荐列表啊,对吧?所以得到的应该是一个mid score这样的一个数组,那大家想到这个类型应该是int double,对吧,所以。
12:15
我们后边,呃,这里就在这里写啊,返回值应该是一个array类型。那么里边是一个int double的一个元组,对不对啊,那当然后边我们把这个实现出来。呃,但大家这个参数我还需要再给大家把这个就是像这样一个一个列出来吗?应该不用了吧,这个含义很明显,对不对?所有上面求出来的这个candidate movies,然后呃,我们这个最近的用户评分recently,呃,Rating,还有我们这个相似度矩阵最长的这一串,尽管看着比较恐怖,但其实还比较简单,对吧?呃,就是我们前面已经讲过的这些内容,好了,那接下来我们就需要去看,呃,我们的步骤应该是做什么呢?大家会想到我们是不是有三项,呃,就是最后的那个公式里边有三项啊,首先有一个基本的一个一个评分,然后后边还有两个偏移项,那大家可以想象到我们做统计的时候也分开统计,对不对?分开去把它做一个统计处理,那我们用什么样的数据结构去存这个,呃,这个这一项呢,大家会想到我们肯定是不是要对每一个推备选电影每一次。
13:39
评分去做一个便利啊,肯定是个for循环对吧,而且大家会想到这两个我们都要去做一个for,那肯定是不是需要有一个变量去保存一下我们当前,诶到底这个东西它的那个评分是多少对不对,一开始的基数得分是多少,然后后边后边是不是相当于就是个计数器啊,大家想统计一下当前你这个分数是不是大于三,那我就算在那个count里边对不对,如果要是小于三,我们算在那个d count里边啊,所以大家会看到这其实就是要定义两个计数器,然后再定义一个基础评分的一个。
14:16
一个数组对不对啊,这里边我们给大家做的一个定义是,呃,首先定义一个score基础,基础得分对吧,定义一个。呃,这里大家注注意啊,我们想定义一个数组,但是它里边还需要不停的变化,我们是不是每遍历一次,后面可能就会追加一些东西啊,哎,所以我们现在就不能用array,我们用的是a buffer,大家知道a buffer跟arra的区别对不对?好,那么定义一个a buffer,用于保存每一个备选电影的。
15:08
呃,就是基础得分对不对,基础得分好,那么这里的这个score大家会想到我们要用的是这个SKY里边的,Collection里边的。Muable,这里边是不是有这个re buffer啊,对吧?啊,当然我们也可以在上面去引入啊,这里我把这个完整的写出来,这里要创建它的类型是什么呢?大家会想到里边我们是不是还是应该一个mid,然后对应的一个技术得分啊,所以里边还是int double这个类型对吧?呃,这个强数据类型,所以大家把这些数据格式,数据类型都都搞清楚啊,那么呃,要创建它,那么我们后边直接加一个括号,表示我们创建一个空的对不对?呃,这样的话,我们如果来了一个。
16:03
便利的时候来了一组新评分,大家想到是不是我直接添加到这个buffer里面就可以了,诶大家想这个会有什么好处呢?因为我们在做便利的时候。我我们是不是如果说不想就是这个双重放循环,挨个去循环的话,我们可能就把它俩放在一个放循环里边啊,就是分别遍历对不对,然后直接放在里边了,那大家会想到我们这里用这种方式把它存起来之后,这个瑞buffer,我们是是不是之后就可以用一些算子,根据它的那个IE,呃,这个mid。对,它做group by,然后把后边的这个score,我们非常简单的就可以算它的平均数啊,哎,这种过程应该是比较简单的对不对啊,或者说我们不不直接算平均数的话,我们算一个sum也是非常简单的,所以我们就不需要非常死板的一步一步去加了,对不对啊,这是给大家用这种实现,所以大家知道思路就可以。接下来我们定义一个啊,大家看啊,我们下面的这个计数器是用了一个哈希map来表示的,因为大家会想到是不是每一个电影对应应该就有一个呃,它当前的这个,呃,所有评分的数据里边,它那个好评的数量是多少和差评数量是多少,对不对,就是说大家会想到每一个,呃,这个我们当前的这个candidate备选电影,它对应到我们的这个,呃,就是。
17:44
呃,已经评分过的电影里边去之后都会有一组这样的值,对吧?所以我们这里的想法是用哈希map来做存储,方便我们到时候去查询保存。每一个。
18:02
备选电影的。呃,就是增强减弱因子对不对。我们这是个一增强减弱。还会想到本身那个,我们一开始做计算就是一个计数器,所以我们这里可以定义一个,比方说叫呃,Increase increase map,我们就increase map吧。等于,呃,这里当然要用到skyla里边,大家想到它也应该是一个可变的数据类型,我们用一个collection里边multipleable下边的哈,Map,呃,那么这里它的k value是不是一个mid,对应着一个计数的那个值对不对,那是不是后边也是一个int啊,大家想到是不是这样的一个一个map,所以就是说我们每一个备选电影看它后边出出现过好评的电影,已经评分过相关的出现好评的电影有多少个对不对?哎,把它统计在这里,那当然了,我们创建的时候还是空的,后面加上啊啊,然后同样的我们这个减弱因子叫re map啊,这个我就直接直接copy过来好了,是不是都一样啊,都是一个哈希map。
19:28
好,接下来大家会想到我怎么样去做呢?是不是要去便利每一个候选电影,然后还要同时便利每一个已经打打过的分,打过分数的电影,对不对,然后把它匹配起来,按照我们的公式去做,计算算当前的这个推荐优先级,所以是一个for循环,里边是什么呢?对,大家会想到我是不是应该拿到一个candidate movie啊,呃,那我们可以有这样的写法,对吧,Candidate movie从candidate movies里边取,对不对,每一个这就相当于这个,呃,对,For,每每一个candidate是不是in这个candidate movies啊,好,然后后边大家会想到还应该从user recently ratings里边这个里边取出来,是不是要取出来每一个这个啊啊,所以我们就把还是这个变量名,就把后面这个S去掉,我们把它拿出来,这样就可以了,对吧?啊,接下来做便利。
20:43
我们会想到首先我们要去拿什么,是呃取取到什么东西呢?便利出来之后,现在就对应的一个candidate,然后我们可以针对一个最近打过的分数对吧,来做计算了,那大家想在我们的公式里边是不是先要找它们的相似度啊,然后还要拿到当前它的评分对不对,然后这两个一成,哎,到后面我们就可以做计算,所以这里我们关键的还是要先拿到它的相似度。
21:17
呃,拿到。备选电影和呃这个最近评分电影的相似度。好,呃,那这一步大家可能会想到这个就是一个same score,呃,这这一步或许还会有一点复杂,稍微有一点绕,那我们呃,先给大家把这个放出来啊,就是叫get movie the。Score,我们还是定义一个新的函数吧,啊,大家其实可以想象到就是从那个,呃,就是相似度矩阵里面去取对不对,呃,其实就是从相似度矩阵里面去取,这相当于就是给一个m mid,给给两个m mid,然后要找到它对应的那个相似度,相似度的那个值对不对?大家会想到其实就是从map里边两重筛选就可以,但是这个map里面大家会想到是不是我得考虑一些异常的情况啊,假如说那个map没有对应的那个值怎么办呢?那是不是里边还应该有啊,有些默认值对吧,可能要去给一个零或者怎么样,我们这里先把它放在这里,其实实现是非常简单的,Candidate movie,对,然后是user recently RA,大家注意这个RA本身是不是应该是一个mid,一个score啊,我们这里是不是只要把它的mid传进去就可以了,大家想是不是我只要。
22:58
到mid啊,大家还记得这个是什么数据结构吧?是不是一个array里边是int double啊,所以这样的最近的评分是一个mid跟着一个评分的,我们现在是不是只要MID2个mid传进去,在相似度矩阵里面就能找到它们的相似度啊,所以我这里是不是只取它的第一个元素就可以mid对吧?呃,然后后边是不是还是要把这个same movies像素矩阵传进去啊啊,这个函数我们先放着啊,后面再再做具体的计算。
23:35
然后拿到这个之后,我们可能就能判断一下了,呃呃,大家这里可以做要求啊,我们之前其实存的时候已经要求了,它必须要大于0.6对不对,如果我这里还有筛选条件的话啊,那可能我要求它必须要大于0.7,或者说大于多少对不对啊,我这里可以给一个这样的一个判断,然后接下来大家会想到就可以去计算,呃,这个。
24:10
呃,基本得分对吧?后候选备选电影的基础推荐得分,那我们得到的这个基础得分是不是应该存到一开始定义好的这个scores里边啊,这里大家注意scores是一个什么,是一个buffer对吧?所以这里我们存的时候,是不是相当于只是把每一项都添加在里边了呀,其实就是把它后边这个buffer一个数组,我们相当于每来一组这个比对一,一个candidate,加上一个这个最近评分的电影,是不是就把它那个算出来之后,把对应的midd和midd和得到的那个基础得分放跟在后边就可以了,我们还没有求和对不对?哎,这里边我们只是把它跟在后边就可以,大家看我这里的写法啊,Scores加等于。
25:12
这等于什么呢?我们现在是不是要把前面的这个mid,这里要存的是这个mid对不对?Mid和double,我们这是谁的这个基础得分呢?是不是应该是candidate movie的技术得分啊。那么后边的这个基础得分是不是应该candidate,不是candidate啊,大家会想到是我们前面求得的这个相似性,这个same score。是不是要乘以一个,看公式是什么?我们当前备选电影和已经评分过电影的这个相似度,这是不是我们算出来的SIM score啊,然后后边是不是要乘以哎,当前它的评分啊,这个评分是从哪里去取啊,是不是也是在user recently里面去取啊?
26:09
是它的,注意它是一个int double类型,是不是它的这个后边这个double,这个score就是它的评分,所以我们这里要拿的是它的第二个元素,对不对啊,做了这样一个操作,这里大家要稍微注意一下,注意什么呢?我们尽管是用了这个就是加等于这个操作,但是其实score这里的scores并不是一个数,对不对,它是一个buffer,那大家想它怎么去加等于呢?那是不是这个加等于肯定是做了,大家看里面是做了这个。运算符重载的对不对,做了做了这样的相当于是我们定义的一个函数对吧?自定义的一个函数,那大家会想到,如果我们这里去掉这个加等于的话,那后边这个括号是不是相当于是就是我们函数后面跟着的那个括号啊,哎,所以那我们真正里边要传的参数是什么呢?是这个函数它里边要传这样的两个参数吗?
27:11
不是对吧,我们是不是本身这个加等于里边传入的就是一个element呀,就是一个对不对,我们本意也是要把它两个作为一个元组一起传入,传入到这里来对不对,所以是不是还得把它再括起来啊,大家注意一下这里的这个写法,因为我们相当于是用到了这个ara buffer数据类型的一个,呃,重载的函数对吧,运算符重载之后的一个函数,所以我们真正传入的参数是这样的一个元组,然后外面的这个括号相当于是我们函数调用时候的括号。呃,但是现在我们还在不停的报错,那大家知道是因为我们前面这个get movie score没实现,对不对啊,我们先把它放一放啊,等一下把它统一搞定好,那么这个scores如果我们已经得到的话,接下来我们还应该有什么样的,呃,这个计算呢?
28:09
是不是还应该去判断一下。是不是当前这个评分到底是不是大于等于三啊,对吧?啊,当然大家直接说它大于三也是可以的啊,Rating_二,这是当前的评分port,对不对?我们要看它是否大于三,比方说我这里就看它是否大于三吧,如果大于三的话应该做什么?对,Inre map里边这是一个map,哈希map。它是不是就应该存入我们当前的can,以当前的mid备选电影的mid作为K去存一个值,对不对?呃,那么它对应的这个值给什么呢?呃,大家会想到,我可以想想到是直接这么去加等于一是不是,但是这里面会有一个问题,什么问题呢?就一开始如果要是说他还没有这个,我们没把这个K里面付给值的话,是不是这里面什么东西都没有啊,你直接加等于一,加等于一,那是不是就报错了,呃,所以我们这里面用一个。
29:16
就让他先去。大家会想到是不是可以先做一个get哦。我们是get on else还是get on default呢?我们是不是想get on default啊,如果要是拿不到的话,是不是应该给他一个初值啊?哎,对,所以这里边get our default给一个什么?我们要get的是candidate movie,如果拿不到诶,是不是他就应该是给零了?对,这是我们的这个操作啊,那后边再把它加一,是不是这样就完事了啊?呃,这是我们做了这个就是增强因子的这个处理,那同样大家会想到后边减弱因子是不是一样啊?ELSE4里边我们要处理的是不是就是re map啊?
30:07
对应的这里也变成这个re map,那是不是后边是不是也是如果没有的话用零,然后再加一对不对啊,就是这样的一种一种实现,好呃,大家看现在实现到这儿的话,相对来讲还是有有点复杂了,有点绕了,对不对?呃,到这一步大家看如果这个for循环结束之后,会出现一个什么样的效果,我们得到的是不是就是一个scores,这个scores里边把所有的备选电影。然后后边跟着的是不是都是他跟每一个已经评分过电影之后的那个加权乘积啊,这是一个。然后大家会想到,假如我们现在ID是一的这个电影,它是不是应应该跟每一个。已经看过的电影都有这样的一个成绩,这个分数啊,所以有可能这里面是不是就是这里的mid是一后面跟着一个0.3,还有一个元素可能是一后面跟着一个0.6,对不对。
31:10
大家想一想,是不是得到是这样的一个一个数组。所以最后我们是不是要根据前面这个mid对后边做一个啊。呃,大家想,我们其实前面把它存成这个瑞buffer,其实就是为了方便后面做这样的一些算子的应用,对不对啊,充分利用这里面的算子。
我来说两句