00:00
好,那接下来我们继续新建一个模块来码这一部分代码,呃,我们这一部分既然是基于内容的信息,我们这个模块就叫content recommend吧,好,我们还是把它创建在,诶这个这个我是不是创建错了,不应该是data load的子项目,对不对?我们应该是recommend下面的子项目啊。好,在这里content recommend创建出来,然后第一步还是去里面到底需要哪些依赖,对不对啊,大家想一想,我们需要哪些依赖呢?在这个问题里边。呃,大家觉得我们这一部分应该是跟哪一个模块去做对比啊,它跟哪一个模块比较像?呃,大家会想到我们这是基于内容的推荐,然后是不是也要提取它的电影的特征信息,对不对?提取电影的信息,最后是不是根据电影的特征信息,然后找到一个它的相似度矩阵啊?哎,我们就准备是做到相似度矩阵之后就结束了,对吧?后面是不是接这个实时推荐那一块输入就可以了,对吧?那大家想到我们实时推荐这一部分给他做输入的相似度矩阵之前是在哪里得到的呢?哎,是不是其实就是在离线推荐,就是基于语义模型这一部分啊,我们当时是怎么做的?当时我们是把这个评分数据拿出来之后。
01:53
宝盈与翼模型里边训练了一个盈与翼模型,对不对?as.train对吧?然后得到的这个模型是不是就可以算预测评分了,得到预测评分还可以得到预测评分,这一部分我们是做这个离线推荐直接推用的,对吧?那另外一部分是我们跟这这里相关的,是不是可以得到模型里边的product features啊。
02:17
我们现在是不是也相当当于要得到一个movie features?得到movie features之后是不是就可以,哎,两两算这个地,这个大家看啊,算这个相似度对不对?后边把它写到我们对应的这个mango表里面去,后边是不是应该都一样啊,甚至这个求余弦相似度的这个过程是不是都可以抄过去啊啊所以大家看到如果我们基于之前隐余模型里边就是算相似度提取特征算相似度的这一部分的话,很多代码其实都类似,我们甚至直接抄就可以对吧?啊,当然代码部分等一下再给大家,具体来说,我们现在是要看依赖,那这一部分我们当时需要的依赖是什么呢?哎,大家想到g plus这个是在什么地方用的?
03:04
这个是跟线性代数相关的一些,呃,矩阵运算相相关的库,对吧?对,算那个相似度的时候是不是用到了它,我们是不是转换成一个double mettrix类型,然后直接就可以调用,大家还记得吗?直接是不是可以调用,直接点dot点击就算出来了对吧?不用我们按照公式去计算了,这里直接NOR2是不是直接把那个模长就算出来了呀啊这个就非常方便,那所以我们既然要抄这部分代码的话,那是不是这个也得也得引入啊,没问题对不对?然后下面是Spark,大家想Spark要吗?要sparkq对你你该去查,该去读写,是不是还都要有啊,然后接下来ML liveb要吗?哦,当时我们用Mr lab主要是要调as算法,对不对,那现在我们没有as算法了,但是我们也有算法,我们是不是要用t fidf去做特征处理啊,特征提取,所以这里边是不是还需要用到M啊,那接下来继续看library,要么mongo相关的KASPA和mongo Spark需要吗?是不是都要啊,啊,所以大家看到。
04:16
这么说了半天,其实是不是所有东西都拿过来就应该对了呀?另外大家想想还有别的需要做的事情吗?我们想一下,结合之前我们这个盈余模型推荐的过程,我们想一下啊,现在要做的推荐是不是一上来之后啊,该定义这些我们就不说了啊,这个呃,就是k plus,还有我们基本的这些常量,这些就不说了,上来是不是也要创建class session啊,然后我们定义这个芒果相关的配置对不对,加载数据,这个加载的可能不一样,我们要用的是电影信息,对吧?主要的内容是要提他的那个类类型信息,把它提取出来,然后这一部分是准备这个训练营语音模型的东西了,我们这一部分不要对不对,我们要做的是不是,诶,根据类型,然后调用t fidf,我们就不是这个,呃,这里as.train了,我们肯定是跟t fidf相关,从类型信息里边提取它的特征,最后是不是应该得到,嗯,Movie features啊。
05:21
如果把这个movie features求出来之后,是不是后面就又都一样了,所以大家看整个过程好像没有用到什么特别的东西了,对不对?哎,所以就是中间这一部分您于模型,然后计算预测评分这一部分我们都替换成t fidf,最后得到movie features就完事,所以是不是直接照抄啊,所以大家看就是代码都是。都是一大抄,但是我们想清楚的话,就会发现这个东西还是很简单的,那前提是我们应该把这部分都了解好,直接来这个就可以了啊,然后接下来我们就要真正去码了。
06:05
Content下面我们还是同样的啊,把它重命名一下,命名成一个哦,这里边还有一个这个log forg,我们先把它copy过来。好。然后这里是不是新建一个sky class啊,大家想到这完全类似,是不是还是一个单例对象,这里边根据我们之前的命名规则,At硅谷点content这个包,然后叫content recommender,好,我们创建这样的一个单一对象。接下来先看样例类对不对啊,那大家想我们这里边的样例类直接就比对这个了啊,这里的样例类我们定义了哪些呢?大家会想到我,我在这个做盈余模型推荐的时候,基于行为数据,基于评分数据,是不是最关键的信息是从这个呃,Rating数据里面去拿的呀,所以我要定义movie rating对不对?那在这里我们需要movie rating吗?啊,我先把这里有的先拿过来啊,大家想一下这个是不是就不需要了,那我们需要什么啊,我们基于的数据是不是就是movie信息啊啊,基于内容嘛,所以说movie rating可能不需要,但是我们需要movie movie这个我们也不直接写了啊,我们在什么地方有。
07:36
大家想一下,我们应该是在统计这一部分是不是有过movie信息的啊,这个引入啊,所以我们这里边的这个样例类是不是可以直接引入啊,所以把这一部分直接copy虑过来啊,就是到处找东西抄,大家看这个倒简单,但是你得想清楚对不对,需要的数据,数据源是电影信息,好电影内容信息,对吧?嗯,大家已经想到所有的这些内容里边,其实我们在这个例子里边是不是主要就是要这个runrus这个信息啊,根据这个来做一个提取,然后下面大家想这个monggo config配置相关的需要吗?啊,这个肯定需要,对不对,然后recommendation这个需要吗?这是我们的基基准的推荐对象,那大家想它关键是看下边这些列表还要不要对不对啊,大家想。
08:36
这个基于预测评分的用户推荐列表,这个要吗?啊,这个好像就不要了,我们这里就不直接做一个推荐了,对不对,我们是不是要算一个相似度啊,哎,所以大家想到下边这个是不是可以认为movie ras这是一个相似度这样的一个定义,所以我们是不是还是要把这个相似度列表这个保存下来,所以前面的recommendation也需要,对不对啊,那当然这里就不是基于LFM英语义模型了,而是基于电影内容信息提取出的特征向量,然后它的电影相似度列表对不对啊,所以我们把这一部分提取出来。
09:20
好,那呃,基本的这一个样例类定义好了,接下来里边的内容啊,一开始我们还是先去定义一些常量对吧?呃,对于这个现在的这个常量,如果我们对应的话,需要的表名,诶,我们现在需要什么表名啊,当时最重要的是这个RA对不对,现在我们要吗?哎,其实我们现在只要movie就不要RA了,对不对,所以把这个RA改成movie。Movie,然后下面大家想到这个user res和movie ras这两个还要吗?这个user res我们是做最后写入那个推荐列表里边用的,对不对?这个我们既然没有直接的推荐列表,这个也就没有了,那movie ras是不是还是一样,这是我们的那个电影相似度列表啊,这个要保留对吧?但大家要注意movie ras这个表名是不是我们已经用过了呀,这是我们最后要往里写相似度的,对吧?那之前我们基于英语模型已经有一个movie ras存它的相似度了,现在我们是不是把这个表名改一下呀,对吧?然后改一下我们在实时系统里边,你从哪一个表里边读数据,是不是就相当于基于哪一部分去做实时推荐啊?
10:42
基于哪一部分的相似度做实时推荐,所以这里我们改一下前面加一个content吧,Content内内容啊,Content movie ras,所以这里也加一个content movie ras啊,当然这个是我们推荐列表的长度,这里既然没有推荐列表,是不是这个也没有了?
11:01
啊,所以这个定义的常量和表明就是这些,接下来我们就可以去看关键的这个入口方法,Main函数里边到底怎么写了,对吧?首先还是去挖一个config,那它还是应该是一个map,对不对?那这个map的内容我们其实还是可以看这里的内容来看,呃,Spark要吗?啊,这个要对不对?Mongo UI DB要吗?哎,这都是用到的,还是一样,对不对?还另外大家想想还有别的吗?像stream里边我们还用到了卡夫卡,对不对,卡夫卡topic data loader里边还用到了ES相关的一些配置,这里好像都不用,对不对,就跟mongo打交道够了,对吧,所以照抄。好,那接下来大家想到的这个过程是不是又是跟这里一样,先创建啊Spark config,然后创建Spark session对不对,然后引入啊,引入这个影视的类,然后把这个mongo con定义出来,这四部是不是一模一样啊,这个我就不详细敲了啊,大家如果想要去呃,每次做个复习的话,还是最好把它一次一次都都敲一遍,大家看这里的这个mongo坑,这个它是offline里边来的对不对?所以我们这里引入的话,是不是应该把这个删掉啊,不要用offline里面的mongo con菲用自己定义的对吧?啊,当然其实大家想到我们如果提取一个公共类去做这些配置的话,都可以把它放到一个公共类里面。
12:43
好,那呃,接下来就是要数据了,对吧?加载数据了,这就不一样了,加载数据呃,并做预处理,大家想一下我们现在要的数据主要是什么呢?是不是主要要的就是movie的信息啊,所以我们读取,其实这个大家可以想到我们这里是read,然后从这个monggo rating里边读对不对?我们这里是不是也类似啊,只不过是说从monggo movie里边collection里面去读数就完事,对不对?其实前面这几步也是一样的,那大家想到这里边我们把它转成了RDD,主要是因为后边应用算法的时候,呃,我们as输入的那个基本的数据是不是应该是一个RDD啊,那这里我们,那我们这里要转成什么样的数据类型,是不是要考虑之后的t fidf要用什么样。
13:44
数据对不对?哎,我们后面TFIDF调用它的那个呃库的时候啊,主要用到的是data frame的数据类型,所以我们这里是不是想要把它转成一个data frame啊?另外我们做这个预处理的话,会想到我们想提取的信息是不是主要应该就是它的类别信息啊,所以我们把这个呃,主要的标签其实就是应该,而且是应该是分散开的类别对不对啊,我们先把这个先提取出来啊,比方说这里定义一个叫movie text,要提它的特征标签DF,最后转成DF,这里用到的就是spec session的read的方法对不对?然后这个read方法里边option可以先定义uri,那么uri我们用monggo conig里边的uri对不对?接下来option定义这里。
14:44
我们用到的是monggo movie collection对吧?呃,把这个改过来,呃,然后后边这个是读取,所以我们直接format com.mango db.spark.cq那后边点load是不是就把数据加载进来了啊,当然了,大家会想到这个load进来,我们是不是按照自己把它定义好的这个样例类把它放在是不是放在movie里啊啊先load进来,然后大家会想到我们处理的时候别的那个信息是不是全部要啊,其实那我们是不是最后要的应该就是哪几个信息呢?呃,那我们想到可能mid要一个,然后是不是就是这个类型要一个就够了啊。当然大家如果还想知道这个电影到底是哪部电影的话,我们把这个name也提取出来,就是方便我们看这个数据到底推荐出来。
15:44
这个我一个电影转换成什么呢?是不是就是mid,这是第一项对吧,然后我们把内幕也提取出来,第二项然是不是还应该有一个runrous这个类型信息提取出来啊,这里大家要注意一下,在runrous信息里边,大家回忆一下我们那个数据里边,它是长什么样子来着,类别信息是什样子的。
16:22
诶,这条load呢,竖线对,大家回忆起来是竖线分割的一组这个类型对不对,整个是一个字符串对吧?那这样的一个类型,我们这里大家会想到之后是不是相当于还应该对它做分词提取啊,把挨个每一个这个类型是不是都提取出来,相当于要按照这个竖线去做分词,这里边给大家说一句,就是后边我们可能要定义一个分词器,那么分词器当然我们可以指定它的那个分隔符,它默认的分隔符是什么呢?是空格。
17:01
因为大家会想到就是默认做分词的时候,是不是从一段这个文本里面去分词啊,英文里边的分词是不是就是一个空格隔开的,这就是一个词对不对啊,所以默认一般都是要把它换成这个空格分割的,那这里边我们怎么样把书线换成分空格呢?其实也很简单,我们是不是直接把里边的那个做个替换就好了呀,那最最简单粗暴的一个替换就是我遍历里边的每一个字符是不是,然后我们看到是不是,如果说它等于竖线的话啊,这个就不需要转移了,对吧?这是按照字符严格意义上的字符来考察的,如果它等于这个竖线,是不是把它替换成空格啊?然后大家会想到else是不是还是原来原原来的这个字符,这样是不是相当于把所有的竖线就换成了空格,大家看是不是这样,这有点像有点像我。
18:01
呃,本身在这个CC或者是Java里边的那个三元表达式对不对,就是一个问号,然后后面冒号那种表达式对不对,但是scla里边没有这种三元表达式,所以我们用这个if else是不是就表表示出来了啊,其实就一个表达式啊,好,那么我们把它转换之后,相当于这里边的类别信息都就是都用空格分隔了之后,直接一分子就把它全提出来了啊,这个就比较简单一些,好,那这是相当于一个预处理啊,然后接下来啊,最后大家会想到我们要的是不是一个data frame啊,所以把它在to frame to data frame,另外呃,大家会想到我们这里可能需要给大家就是做一个直观的展示输出,看看它到底是什么样子,另外就是说我们后面在做这个t fidf,它是针对data frame做处理,那我们里边的这个列名也得非常的明确,对不对,哎,我们这里边给定的列名叫做mid。
19:01
第一个列对不对,第二个是不是name马,第三个叫做啊,就叫ROS吧,好,这是我们基本的三个列,当然了,最后大家如果是为了性能考量的话,可以把它持久化在内存里边,对吧,做一个缓存catch,这是我们基本的数据结构,呃,这里边给大家写一句注释啊,呃,就是。默认按照分词器默认空格做分词,所以我们这里边做一个预处理对吧?另外这里是提取mid name runrous3下作为特征,内容特征,我们说原始的内容特征吧,好啊,其实大家可以知道这个我们我们这里面最后用到的就是它对吧,就是S这个特征。
20:06
好,那么这一部分写完之后,大家就会想到我接下来是不是应该应用啊,这个分子器啊,然后t fidf相对应的这些算法,是不是从movie types df里边,特别是它它的这个runs这一列里边提取我们的movie features啊,是不是应该,所以是这里我写一个todo啊,先空下todo,从呃,这个。内容信息中提取。电影特征。向量啊,当然最后我们得到的就应该是一个是什么,结合这个,呃,Offline这里来看的话,我们最后是不是想拿到一个movie features这样的一个东西啊,对吧?所以得到这个特征的话,我们后面就一样去做计算了,所以这里我先定义一个叫features,我们先定义一个nu吧。
21:15
如果拿到这个movies之后,接下来我们怎么做?大家会想到是不是就跟offline这里边做的事情一模一样,只要得到这个movie fisher,当然我们要把它转成跟这里边处理出来的这个格式一样的东西,对不对?也转成哎,一个mid,后边用一个这个double matrix,是不是后边的做法就完全一样了?我们根据movie featureer做一个笛卡尔基,然后自己跟自己过滤掉,然后之后是不是两两配对就可以算这个余弦相似度啊,得到的内容,哎,我们做一个过滤,最后再group by,把它转换成movie ras这个数据类型,最后转换成data frame,是不是就可以save到mongo里面去了,那这里边这个计算相似度怎么样算呢?是不是还是和这里边一样啊啊,那大家会想到接下来的做法是不是完全一样,那我们就不再去抄一遍了,对吧,就就直接copy过来好了,呃,大家看一眼,这里边我们用到了allline里边的这几个movie ras,还有呃,它的这几个东西,那我们是不是都不应该引入,我们直接用自己的就可以了,直接canl,那大家看一眼啊,诶,这里边我们都定义出来了,对不对,所以这里边看起来也没有报错,诶这里边是有问题的,看一眼。
22:38
这里面好像报了一个错,呃,但是大家其实可以注意到,就是这里我们还没有定义这个余弦,计算余弦相似度的这个函数对不对,所以我们是不是应该把这个算出来啊,好,我们看一眼。把这个外面再DeFine一个求余弦相似度的函数,把它同样也抄过来,那这个double magic double magicx是不是应该引入啊,所以这个我们OK一下,好,所以这个整体的项目,这个程序的框架就是这样,大家看这个是不是非常简单啊,嗯,然还在报错,那大家会想到为什么呢?我们这里是不是它本身是个nu啊,本身是个nu的话,后边做这些处理可能会有问题,对不对?所以我们先把这一部分先住吧,先住,但是大家知道到时候我们提取出来之后,是不是后边就直接把它放开就可以了,直接抄过来就可以了,对吧?啊,所以接下来我们要做的事情其实就是呃,怎么样把这个movie features。
23:43
拿出来对吧。
我来说两句