mahout的taste框架是协同过滤算法的实现。它支持DataModel,如文件、数据库、NoSQL存储等,也支持Hadoop的MapReduce。这里主要分析的基于MR的实现。
基于MR的CF实现主要流程就在org.apache.mahout.cf.taste.hadoop.item.RecommenderJob类中(注意mahout有两个RecommendJob,要看清楚是哪一个包)。这 个类的run方法就包含了所有的步骤。从上到下,完整的其实有10步(中间计算item相似度其实拆分成了3个job,我们也当做是一个phase吧), 也就是说,如果指定了所有的必要参数,运行一次item-based CF算法,会执行12个JOB,当然有的步骤是可以忽略的,下面会讲。以下就是详细的每一步骤的分析:
phase1: itemIDIndex
这步主要是将itemId转成一个int。这里设计上其实有点小问题,如果item的数量非常多,比如超过int的最大值,那就有可能会出现重合了。所以用long其实更为合适。
input:用户评分文件(这也是我们最原始的输入了),格式一般为:userId \t itemId \t score。注意输入必须是textfile的。可能是为了方便测试吧,mahout的很多包默认输出都是textfile格式的。
map:(index, itemId)
reduce: (index, itemId)
phase2: toUserVector
input:用户评分文件
param: --userBooleanData如果这个参数为true,则会忽略评分列,对于买或不买这类数据有时需要指这定这个值。
map: (userId, itemId,pref)
reduce: 以用户为key,输出成向量形式è (userId, VectorWritable<itemId, pref>)
phase3: countUser,计算用户数
map: (userId)
reduce: 输出总用户数count
phase4: maybePruneAndTranspose
input: phase2的输出:userVector
param: --maxCooccurrences
map: (userId,Vector<itemId, pref>) è(itemId,DistributedRowMatrix<userId,pref>),注意如果指定了—maxCooccurrences参数,这里会有裁剪, 每个userId最多对maxCooccurrences的itemId打分
这里的DistributedRowMatrix,分布式行矩阵:行:itemId, 列:userId
reduce: (itemId, VectorWritable<userId,pref>)
phase5: RowSimilarityJob
这一步比较关键,计算item相似度,它拆分成了三个JOB。
param: --numberOfColumns, --similarityClassname,--maxSimilaritiesPerRow(默认:100)
job1:weight
input:phase4的输出
map: (itemId, VectorWritable <userId, pref>) ==>(userId, WeightedOccurrence<itemId, pref, weight>)
这里的weight,对于欧氏向量距离,或者Pearson距离等,均为Double.NaN,即无效。在LoglikelihoodVectorSimilarity中有用到weight的值。
reduce:(userId, WeightedOccurrenceArray<itemId, pref, weight>)
job2:pairwise similarity *item相似度计算*
map: 对同一用户的所有item-rating,输出两两item之间的关系 ==>(WeightedRowPair<itemA, itemB, weightA, weightB>, coocurrence<userId,valueA, valueB>) (同上,这里的权重weightA,B对于欧氏距离等可以忽略)
reduce: 在这端,以<itemA,itemB>为key聚合了来自不同map的所有用户的打分,最后输出itemA和B的对称相似度(即以itemA为key或以itemB为key)==>(SimilarityMatrixEntryKey<itemA,similarity>, MatrixEntryWritable<WeightedRowPair<itemA, itemB,weightA, weightB>>) ,(SimilarityMatrixEntryKey<itemB,similarity>, MatrixEntryWritable<WeightedRowPair<itemB, itemA,weightB, weightA>>)