00:00
呃,今天主要讲实时推荐这个模块,大家看到实时推荐的这一个内容里边呢,主要其实就是涉及到一个自定义的模型啊,那么我们整体的思路是怎么样想的呢?其实想的就是说,呃,在实时嘛,他要求的是用户有一个行为之后,我马上就得有一个反馈啊,那么这样一个反馈,一方面我们要求你得快,另外一方面可能精度就不需要那么高,对吧,这是一个基本的需求,或者说基本的一个想法,所以基于这样的想法,我们就提前。把握物品的商品的相似度,先算好,这一部分是在之前这个离线的推荐模块,我们已经把相似度算出来了,作为一个基数,另外一部分呢,我们就需要结合。用户最近的一些评分的数据,然后考察一下他最近的这个偏好,我们的一个基本想法就是说,哎,你最近一段时间偏好可能是一致的,你之前看过什么商品,买过什么商品,那么我接下来给你推荐跟他相近的相似的商品,这个往往就是比较有道理的一种推荐方式啊,所以这基于这样的思想呢,我们再去构建一个模型,这个模型要求就是计算要简单,不一定那么精确,但是我们要很快速的。
01:25
能够给用户做出一个相似的推荐啊。那么具体的这个架构大家再重新来回顾一下啊,当时我们在这个PPT里面给大家做了比较详细的讲解,那么整体来讲。基于模型的实时推荐模块,它的架构其实就是这样啊,我们的数据流是首先在这个日志里面,我们要去产生这样的一个评分数据,那么它的结构应该就是有一个user ID,有一个物品的ID,然后还有一个评分score,最后还有一个时间戳,我们通过flu把它采集进来,连接到后边的这个卡夫卡,做这个消息对消息缓冲,那么在卡夫卡这里可能还会去做一个呃,用卡stream做一个消息的过滤。一开始。
02:15
传进来的时候,这个topic可能叫log,然后我们再把它过滤之后再发,发放到后边这个叫做recommend的这个topic里边来,那么在实时推荐模块这边,我们订阅这一个topic,那么就可以消费它里边的数据了。所以我们这里是要在这里定义实时推荐的算法,然后构建自己自定义的模型。那么这里需要哪些数据呢?一方面的数据是已经保存在mango里边的,呃,就是在之前离线那一部分已经算好的物品相似度,这个东西我们是直接放在mango里面的,大家记得就是那个,呃,就是前面我们所说的。Product re,那个表里边存储的就是相似度列表,对不对?呃,那么另除了相似度之外,另外我们还需要一个数据,就是用户最近的评分,我们把最近的评分会放在red里边缓存起来啊,有了这两部分数据,放到输入入给我们的实时推荐算法,哎,我们经过自定义的这个模型就可以得到最后给用户的一个实时推荐列表,我们把它再写回到网购里面去,就可以给用户做实时的展示了,这就是整体的架构。
03:34
呃,然后我们再重点看一下这个推荐优先级的计算,这里边整个这个架构其实大家都已经很清晰了,那最重要的是我们要考察清楚里边怎么样定义出自定义的模型,然后算出给用户的这个推荐优先级呢?这里就涉及到一个推荐优先级的计算。这一部分我们基本的一个思路或者说原理,就是说用户最近一段时间口味相似。
04:04
呃,所以基于这一个想法,我们就要把用户最近的K4评分都拿出来啊,去综合考虑他跟最近K4评分的相似程度,对不对啊,如果要是跟跟最近K4评分越相近,就代表着。越符合我最近的口味,那就应该去做强烈的推荐,诶,所以这里大家就会看到啊,我们首先是先去找到一个备选的商品列表,就先是找到一组候选人,那么这个候选人从哪里找呢?很简单的思路就是之前我们不是已经算好了相似度嘛,对,一个商品它本身就有一个相似度列表,这个在芒果里面已经写好了,所以我们可以很简单的,你看了某一个商品,或者说买了某一个商品D,我就从相似度矩阵里边把他的那个相似度列表都拿出来,作为备选商品列表。
05:04
然后接下来大家会想到这个列表,如果要直接推的话,是不是也可以?哎,直接推出来的话,这就相当于是一个相似度推荐对吧?呃,这就是非常简单的一种,呃,实时计算了,就是我们前面已经有了结果,这里面直接给你推出来,但是我们觉得他还有一点不好,不好在哪里呢?对大家会想到就是我们在做这个评分的时候,有可能是好评,有可能是差评,如果这里边我给的这个评分是一个差评呢,尽管我看了买了,但是之后给了一个差评。哎,大家就会想到这其实我这一次的推荐力度应该是不那么大才对,哎,是这样的一个考虑是吧,呃,就是我一方面看了这个商品,买了这个商品,这代表我对它比较感兴趣,所以我推跟它相似的,这是没问题的,但是另外一方面呢,我又得考虑到你如果给他差评的话,那如果跟这个差评的相。
06:05
呃,商品非常相似,那其实这个推荐力度你应该削弱的,所以我们应该综合的考虑相似度和评分他们之间的这种影响因素。呃,那么我们综合起来考虑,呃,这个最近K4评分的时候,那我们就不仅仅是看每一个候选商品跟这K4评分的相似度了,我们还要用它的评分去做一个加权,所以大家看啊,我们这个推荐优先级的计算公式,第一项就是基础评分项,它的计算公式其实就是这里边有一个CQR,这表示什么呢?表示的就是我们的每一个备选商品,这是对某某一个备选商品要算他的推荐优先级,所以对于某一个备选商品Q而言,我们挨个去考察它跟最近K4评分的相似度。
07:01
我们整体的一个思路还是跟最近的K4评分越相近,那就越符合最近的这个口味,越符合最近的偏好,我们就越应该推荐,对吧?这是一个基本的思路,所以我们先考察他的这个相似度。那么跟最近的每一个评分过的商品R都算一个相似度,同时我们又会考虑到,如果要是好评的话,诶,对,那你权重就大,我应该强烈推荐,如果要是差评的话,那其实这个推荐力度应该减小一点,对不对啊,就不要去把这个跟差评相似的商品还那么强烈的推荐了,所以这里我们就再乘以它的评分作为一个权重系数,对对他推荐的力度做一个调整。所以这里的R大R下边的这个小标小R指的是什么呢?就是对最近的R这个商品具体的那个评分数值。
08:01
所以把这一部分挨个都做一个计算,最后再求和,除以下面这个SIM sum就是所有评分的个数,对吧?啊,就是每一个。做一个加权平均得到的这个结果就是最后推荐优先级的基础分数,大家看最后在做一个具体事例的时候,大家看这个是怎么算的呢?呃,对于这个X,这是我们的备选商品,它的推荐优先级第一项基础评分怎么算出来的?对,就是跟最近的K4评分的每一个商品算它的这个相似度,这个相似度我们在相似度矩阵里边已经存好了,拿出来就可以了。跟A算一下,这是CAX它的相似度,做一个权重调整,乘以它的分数五分,既然是好评,那跟它相似是不是应该强烈推荐,呃,所以这个算出来应该比较大,对吧?这个值比较大,然后后边再跟比同样的去算一下,乘以它的分数是四,最后再跟C乘一下,乘以它的分数一,那大家会想到你跟C即使是很接近,乘以一之后,这一项是不是就权重比较小了?
09:13
所以最后呃,整个的这个推荐,推荐的优先级,或者说推荐的这个分数就会降低,最后除以评分的这个个数,总共算出来就是一个加权评分。另外后面我们还加了一个啊,就相当于是一个偏移量了,一个是鼓励项,一个是惩罚项,鼓励项指的就是说,诶,如果最近K4评分里边。都是高分,那相当于最近K4评分,是不是非常能代表你最近的口味,你都是高分,你你既看了又买了,而且最后还给了高分,那说明你最近就是喜欢这些东西,所以如果跟这些东西相似的话,那么这个商品我就应该大力推荐,强烈推荐,所以这里还有一个鼓励项,呃,那么他就是比方说这里我们可以自定义就是大于三分,如果算这个好评的话,我们就把大于三分的商品个数。
10:11
这里求一个log对吧?呃,作为一个鼓励项,那么同样后边如果要是最近K4评分都是差评的话,我们同样对它做一个惩罚,呃,这里就是把小于三分的商品评分个数,然后做一个统计,我们求一个log,在这里减去作为一个惩罚就可以,这就是。做这个推荐优先级计算的核心算法,大家可以再好好的把这一部分梳理一下,我们接下来在代码实现当中主要就是用到了这一部分内容。呃,然后另外在这个代码实现的过程当中,我们具体是怎么操作的呢?其实就是这样一个流程,我们会。首先基于两份数据,一个是里边的最近的case评分,我们要把这个数据拿出来,呃,代表最近的这个偏好口味,另外一部分就是对候选商品,候选商品怎么拿呢?从商品的相似度矩阵里面直接拿出来,这就作为我们的候选商品。然后接下来我们会对每一个候选商品,结合他最近的K次评分,是不是要做挨个去计算那个相似推荐的这个优先级啊,也就是说推荐评分,呃,那么具体来讲怎么算呢?首先我们去获取它跟最近K4评分的商品的相似度。
11:32
然后再乘以它对应的那个评分求和,除以个数,是不是就得到的是基础评分啊,哎,这就是我们前面的那个公式里边的第一项,然后后边呢,再加上这个偏移量,统计一下好评是多少,差评是多少,按照公式把它算出来,最后得到一个结果,我们可以按照这个评分高低排序,就得到了一个推荐列表,然后最后可以把它写回到网购里面去。
12:01
这就是整个的计算流程,好,那接下来我们就还是在代码里边去完整的做一个实现啊。呃,那大大家会想到这个实时推荐,这又是一个新的模块了,我们是不是直接在recommend下边再去new一个。我这里面。重新创建一个叫做online的。一个模块,子模块。然后把它放在对应的这个目录下边。好,呃,首先我们要考察这个对应的依赖了,大家先想一想,这里边我们需要什么依赖呢?对,大家会想到我们要做这个实时推荐,那是要做一个流式处理的,要做流式计算,那是不是需要用到SPA streaming啊,这里就是除了之前我们用到的SPASPA是不是还应该有啊?Spark streaming也是需要的。另外大家结合前面的这个offline这一部分来看的话,之前还有什么呢?M Mr lab这里需要吗?
13:14
Mr lab是机器学习库,大家想一下,哎,我们这里是自定义了一个模型,那其实不需要用到库里面的一些方法对吧?哎,所以这里边MRLA可以去掉,然后skyla library是不是也需要啊?呃呃,这基本的一些操作肯定都需要啊,Mongo相关的东西是不是也需要啊?那这个KASPA和这个mongo Spark collector这两个都需要,另外大家想一想还需要什么?对,大家会想到我们这个做实时的流处理的时候,它的数据从哪来呢?对,是从卡夫卡来的,所以是不是还应该把卡夫卡相关的这些组件也加进来啊?呃,这些依赖也得加进来,另外大家再想一下还需要什么?呃,对,我们前面讲到在做这个计算的时候,有一部分数据,最近的case评分,这是从red里边拿出来的,对吧?所以说我们还得把red就je得加入进来,好,大家看一眼这个文档里面的依赖啊,看一眼Spark没问题,对吧?Spark Spark streaming,这是我们要新加的一部分内容,呃,然后接下来sky library,这都没问题,Mongo相关的内容,呃,然后接下来是不是还有red,呃,Je要放进来啊。呃,最后还有卡夫卡相关的卡夫卡客户端,Clients,还有Spark stream卡夫卡,对吧?这这一些东西都是我们可以想到的。
14:42
哪些需要新增,哪些可以删掉,我直接把这个做一个复制。呃,我们放在。Online的po文件里面,好,这个依赖就已经完成了,呃,同样接下来我们还是啊,对应的这个resources下边应该得有一个log。
15:06
Forg的配置文件,我把它复制过来。呃,然后我们同样原文件应该放在呃这个SW下面对吧,我们这里可以改一个名,改成SKY。接下来我们是不是在skyla里边去创建一个,呃,Skyla class对不对?哎,同样大家会想到这里边我们要创建的是什么呢?是class还是object还是对,其实这里边是不是还是一个单立对象啊,因为大家能想到就是在别别处其实是不需要去,呃,就是创建这个类的对象的,所以它其实还是一个单例,好那么我们这里边的包名就叫做艾硅谷点。呃,这里叫online对吧。Online recommend。好啊,这就是。
16:01
我们已经创建好了这这个单例对象,然后接下来第一步按照我们之前的这个标准流程啊,首先还是看一看要定义哪些样例类,呃,那么这里边需要哪些样例类呢?我们还是看一眼这个。离线推荐这里用到了哪些吧,这里边我们用到了。呃,这个product RA相当于就是RA对不对啊,就是平分的那个样例类让啊又断网了。好,我们先看一眼在离线推荐这一部分用到了哪些样例类,首先是呃,一个product RA,这就是评分那个样例类,然后还有这个mongo con fig啊,这是大家会想到,如果用这个mongo相关的这些配置信息的话,肯定这个mongo f是需要的,对吧,这个肯定保留,然后还有这个标准的推荐对象recommendation。
17:00
诶,大家想到我最后如果要做实时推荐,给到那个推荐列表里边去,是不是也应该是类似的一个形式啊,也是一个user ID,然后后边跟着一个呃,这样的一个Rex里边是不是也应该是一个recommendation啊,所以下面的这一部分我们应该是都可以保留出来的啊,这里边大家需要注意的是,那上边这一部分我们是需要用RA数据吗?对,其实我们只要用到相似度矩阵里面的数据是不是就可以了,那么呃,本身相似度里边的那个东西是不是就是保存在product RA里面的呀?呃,所以这一部分我们其实根本不用到评分的数据,所以这一部分我们可以不要啊,这里我们就只把下边的几个复制一下。然后粘过来就可以了,我们可以再想一想,就是还需要什么样的东西呢?
18:06
呃,这里面大家注意,就是我们在这里对大家会想到就是跟red还会有关系,我们应该还要用到red的一些,呃,连接的配置,Red的客户端对吧?我们要定义一个jaice,所以大家可以参考一下文档里边的写法,我们这里边前面定义了一个连接助手对象啊,这里定义的也是一个object,一个单例,对吧?啊,那么这个对象本身里边包含了什么东西呢?就是包含了一个gene,然后还包含了一个mongo的客户端mongo client,所以我们这里边其实主要就是方便做这个数据库连接操作,我们提前把这个呃,就是它的客户端先定义出来,这里大家注意一个小技巧,就是这里面我们还用了一个lazy,这是表示什么啊?
19:06
Lazy表示懒,对,这是一个对懒加载的一个变量,对不对?所以就是说在这里我们只是先定义出来,是使用的时候才会给他做初始化,它会延迟初始化对不对?呃,所以其实就是说,呃,我们在做这个表达式的时候,他就不会去重复计算了,那我们只是用到的时候才会去把它做一个加载。那这里面我们还是在代码里面做一个具体实现啊。呃,前面我们还是。定义一个。呃,定义一个连接助手对象。呃,建立到redis和mongo DB的连接。
20:07
所以这里面我们定义一个object名字,我们就叫做呃,Connection helper连接助手。大家会看到他需要去,呃继承一个什么呢?呃,这里边我继承了一个scalela里边的s sre liable这样一个,呃,对象那大家注意这个sre lizable其实是一个,它其实是一个treat对吧?所以如果我这里边继承一个treat的话,相当于是。继承一个treat相当于是什么?这相当于也给大家复习一下SC里面的这个面对对象的一些知识啊,相当于是不是实现了一个接口啊,大家可以把这个treat认为是Java里边的接口,对不对?所以在skyla里边的话,没有就是实现接口这一说,所有的都是按照这个继承关系extend来做的,那么这里边如果我们去extendable的话,就相当于实现要对这个接口做一个实现啊,那大家会想到为什么要实现这样的一个接口呢?
21:20
是不是要为了这个我们网络传输的过程当中序列化,所以我们要继承这样的一个接口啊,对吧,实现这样的一个接口,呃,那么这里边我们定义这个连接对象的时候,是用了懒加载懒变量啊。呃,这个是要使用的时候。才去初始化。所以这里我们可以定义lazy一个jeice对吧?呃,这里我们就需要去new一个je了。
22:03
呃,大家会看到这里边我们就用jeice里边的client对吧?Jeice这里边需要传入我们默认的这个连接URL,那我这里边就直接local host就可以用默认的这个,呃呃,大家这里还是按照自己起的环境,你的red是在哪里,在哪里配置的,这里需要去做更改对不对?那么后边还会有这个monggo相关的客户端定义,这里定义一个monggo client。我们呃,这个在之前data loader的时候,是不是用过这种方式去去做处理啊,定义这样的一个客户端,那么大家会想到为什么这里边还要去专门定义一个mango客户端呢?我们不是mango的读写操作,直接用呃,Spark session的那个read就可以读,然后用这个data frame writer就可以写吗?这里大家注意到我们可能就不仅仅是读和写的操作了。
23:04
有可能还会用到复杂操作,比方说在data load里面的时候,大家回忆一下是不是用到了,比方说删除操作,比方说用到了创建索引,如果要用这些东西的时候,你直接哎想要去这个data frame writer,那肯定就做不了了,对不对?所以我们还是得去创建一个网购的客户端来做这些事情啊,那我们在这个程序里边哪哪些地方要用到呢?后面大家能够想到我是不是要去。大家大家想到我最后去保存的这个数据,是像之前一样,是整张表所有的数据全存进去,还是说相当于只是每次操作只是针对一个用户。改他的一条数据啊,哎,我们最后做的其实相当于只是把这个一个用户他的实时推荐列表要做一个更改,对不对,那所以这个过程我们是不是就不应该直接用data frame writer直接把那个全复写进去了,那这个过程显然就不应该做这样的操作,所以我们还是要去定义一个mongo client客户端完成这些事情的,呃,就是更复杂的一些任务还是用它来做啊,这里大家还记得里边怎么写吗?Mongo client。
24:25
要有一个uri对不对,要传一个U,然后里边是需要呃,给定他的这个uri啊local host这里面我们用默认,呃,这个uri前面必须得是mango DB对吧。然后local host27017就是默认的端口,后边我们默认的连接的这个数据库是recommend对吧,大家看这里面报错了是因为。呃,我前面不应该用这个mango DB的。
25:00
Monggo client UI,而是要用到这个开SPA里面的mongo client u,这样就不报错了,对吧?好,我们先把这个定义出来。
我来说两句