mahout推荐部分单机运行时的代码没有具体看,但是理解看来应该不难,给定【userid,item,rate】的话其他语言写个算法也能实现。在hadoop上运行的时候,才具有挑战意义,没有那些datamodel的概念,mahout in action书上的内容看了半天觉得还是不大了解,上面算的“共现矩阵”,神马神马的,资料也比较少,看得更晕,于是自己看了下实现的步骤,发现还是挺“牛逼”的,出于对java的掌握程度略低,此处就把大概步骤列一下,看官请轻喷- -!
如网上说得,这个部分最恶心的一点是RecommenderJob 是 final类...图如下:
表格右半部分由于博客园搞的东西被遮住了看不到,程序员么,总有办法解决的~ 【审查元素》复制table节点》插入到新的html里】或者【选中表格部分再复制到excel里面看】
整个里面以皮尔逊系数的计算为例,建议先看下皮尔逊算法的计算公式,以及如何将他分解(分解是关键)。
job_name | 功能 | mapper | reducer | combiner | ||||||
inputformat | path | input | output | input | output | outputformat | path | |||
itemIDIndex | 产生itemId->index的映射 | text | rating.CSV | text | [index,itemId] | [index,[itemId,*]] | [index,min(itemId)] | sequence | preparePreferenceMatrix/itemIDIndex/ | ItemIDIndexReducer |
toUserVectors | 产生userID映射 每个itemID的value | text | rating.CSV | text | [userId,[itemId,prefValue]] | [userId,[[itemId,prefValue],*]] | [userId,[[index,value],*]] | sequence | preparePreferenceMatrix/userVectors/ | |
Count产生用户数 | sequence | preparePreferenceMatrix/numUsers.bin | ||||||||
toItemVectors | 产生index映射 userID的value | sequence | preparePreferenceMatrix/userVectors/ | [userId,[[index,value],*]] | [index,[[userId,value],*]] | [index,[[[userId,value],*],*]] | [index,[[userId,value],*]] | sequence | preparePreferenceMatrix/ratingMatrix/ | ToItemVectorsReducer |
normsAndTranspose | 共同购买某个item的用户的商品直接的第一次相似度计算,用户后面产生item到user的最终相似度,分解pearson计算的分子和父母可以发现如此计算的原因 | sequence | preparePreferenceMatrix/ratingMatrix/ | [index,[[userId,value],*]] | [userId,[index,pref]] | [userId,[[index,pref],*](Iterable)] | [userId,[[index,pref],*](vector)] | sequence | weights | MergeVectorsReducer |
产生rowVector为 (xi-x拔)/sqrt(sum(x-x拔后的平方)),pref为上述值 numNonZeroEntries为每次叠加+1 maValue为上述value的最大值 cos和pearson时norm都为0 | 判断后将三个值写入对应文件, 同时输出merge后的向量 | 2的24次方减一:16777215 | sequence | maxValues.bin | ||||||
16777215 | sequence | norms.bin | ||||||||
150994943 | sequence | numNonZeroEntries.bin | ||||||||
pairwiseSimilarity | mapper端:由一个用户的第一次相似度计算结果作为输入,产生 item到item的相似度计算,pearson为两个因子相乘,作为第二次相似度的结果,reducer端,汇总itemA对itemB的第二次相似度计算,原因为A对B时,是N对N的行为,最后相似度相加作为结果 | sequence | weights | [userId,[[index,pref],*]] | [indexA,[[indexB,aggr(prefA,prefB)],*]] | [indexA,[[[indexB,aggr(prefA,prefB)],*]],*] | [indexA,[[indexB,simB],*]] | sequence | pairwiseSimilarity/ | VectorSumReducer |
indexB>indexA,返回 vector.aggregate(prefA,prefB),pearson里面 调用cosin,默认为两式相乘 | preparePreferenceMatrix/ratingMatrix/ 这里面获取列的总数numberOfColumns 像combiner那样先做一次变换,然后调用vector.similarity(),public similarity(double dots, double normA, double normB, int numberOfColumns) { return dots; } cosin 和 person返回dots ,就是value | 到这边indexA 与 indexB的相似度已经计算完 | 对于indexA可能有多个indexB,simB, 合并相同的indexB,默认采用function.plus,为simB+simB1 | |||||||
asMatrix | 减少输入结果集,N*N/2减少为N*TOPK,并且去0 | sequence | pairwiseSimilarity/ | [indexA,[[indexB,simB],*]] | 循环,输出 [indexB,[indexA,simB]],[indexC,[indexA,simC]]simB,simC为非0, 一次性输出[indexA,topKSimilarities]的TOPK向量,K为maxSimilaritiesPerRow,所有输出都是非0 | [indexA,[topKSimilarities,transposedPartial]] | [itemA,[topKSimilarities]] | sequence | similarityMatrix | MergeToTopKSimilaritiesReducer |
maxSimilaritiesPerRow如果没设置返回全部, 如果没任何限制 这里应该也包括了自己和自己的相似度 | ||||||||||
prePartialMultiply1 | mapper端重设和自己的相似度为double.NaN | sequence | similarityMatrix | [itemA,[topKSimilarities]] | [itemA,[topKSimilarities]] | default reducer | sequence | prePartialMultiply1 | ||
重设和自己的相似度为double.NaN | ||||||||||
prePartialMultiply2 | 过滤userVector中的数据,有些用户不需要 | sequence | preparePreferenceMatrix/userVectors/ | [userId,[[index,value],*]] | [index,[user_id,value]] | default reducer | sequence | prePartialMultiply2 | ||
取存在于userFile中的user数据,如果存在user表 则只输出user表中的数据 | ||||||||||
partialMultiply | 通过判断是是vector还是[userid,value],产生一个物品的topk相似度和用户对该物品的评分 | sequence | prePartialMultiply1 | default mapper | index,value为prefOrvector | index,value为prefAndVector | sequence | partialMultiply | ||
prePartialMultiply2 | 对于任一item,只有一个topKSimilarities,但是有多个用户对这个item的value | (similarityMatrixColumn, userIDs, prefValues) | ||||||||
itemFiltering | 根据设置和partialMultiply一样输出的向量,最终达到过滤 | text | filterFile | text | [itemId,userId] | [itemid,[userId,*]] | [index,[[index,NaN],[userId,*],[1.0,*]]] | sequence | explicitFilterPath存在时才能找到 | |
aggregateAndRecommend | 最终推荐… | partialMultiply | [index,VectorAndPrefsWritable (vector, userIDs, prefValues)] | [userId,[prefValue,similarityMatrixColumn]] | [userId,[[prefValue,similarityMatrixColumn],*]] | |||||
explicitFilterPath | 每个用户对某个item的偏好值和该item的topK相似度矩阵 | 遍历 得出最终结果 |