mahout基于Hadoop的CF代码分析(转)
來自:http://www.codesky.net/article/201206/171862.html
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參數,這里會有裁剪,www.codesky.net?每個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>>)
???job3:entries2vectors?*匯總item的相似items*
????? param: --maxSimilaritiesPerRow
?? ?? map:?(itemA, itemB,?similarity) & (itemB,itemA,?similarity) 這里在group的時候按相似度降序做了排序,如果有--maxSimilaritiesPerRow參數,則會做裁剪。
?? ?? reduce: (itemA, VectorWritable <item,similarity>)
至此,item相似度計算完畢。
phase6:?prePartialMultiply1?
?? input: phase5的最后輸出(即item相似度)
?? map: 直接輸出item對應的相似items,這里用VectorOrPrefWritable做了封裝,表明有可能是相似度向量,也有可能是對item的打分,并且對item為自己的,將相似度設為Double.NaN,以過濾自身。è(itemId,VectorOrPrefWritable<item, similarity>)
? ? reduce: IdentityReducer
phase7:?prePartialMultiply2
? ?input: phase2的輸出userVectors
? ?map: 輸出:(itemId, VectorOrPrefWritable<userId, pref>)
???這里默認考慮用戶對10個item的評分,可以通過maxPrefsPerUserConsidered參數調整。
? ?如果指定了usersFile,則在setup時會把所有的userId讀入內存,用于過濾。如果map輸入數據的userID不在usersFile中,則會被忽略。注意,這是mahout的設計bug,對于比較大的數據集,很有可能造成OOM(事實上在我的測試程序中已經出現OOM了…),這種bug下面還會出現。輸出的是用戶的評分,同phase6的VectorOrPrefWritable的封裝。
? ?reduce:?IdentityReducer
phase8:?partialMultiply
? ? ?input: 6和7的輸出:prePartialMultiply1,?prePartialMultiply2
? ? ?map:?Identity。由于6和7的輸出的key均為itemId,因而在reduce端同一item的相似item以及對應的用戶評分會聚合到一起。
? ? ?reduce:(itemId,?VectorAndPrefsWritable<similarityMatrix, List<userId>,List<pref>>) 沒做特殊處理,直接合在一起,輸出相似度矩陣,所有的userId及對item的打分。
phase9:?itemFiltering?
? ? 將過濾文件輸出成<userId, itemId>。如果指定了--filterFile參數,則在最后的聚合推薦中會過濾userId對應的items。這一步在實際中多數是可以忽略的,只要不指定這個參數即可。
phase10:?aggregateAndRecommend
? ? map: 對每個用戶,輸出對當前item的評分,以及與當前item的所有相似 itemsè(userId,?PrefAndSimilarityColumnWritable<pref,vector<item, similarity>>)
? ?reduce: 聚合了這個用戶所有的評分歷史,以及相似items,計算對該用戶的推薦結果 è (userId, List<itemId>)。
注意在reduce的setup中,會將phase1產生的所有itemId到index的映射讀入內存,這里只要Item數據集稍大,就會OOM。這是比較嚴重的設計bug。
事實上,如果item是正規的整數,而不是guid之類的,phase1和這一步的讀入內存是完全可以略掉的。這樣的話 就完全可以在企業級的數據集上使用(我的測試數據集是15億+的user-item-rating,1.5億+的用戶,在最后這一步掛掉了,前面所有 phase都能跑成功)。
至此,已經形成了推薦結果,CF完成。
以上的所有步驟中,phase5的計算item相似度是最慢的(這個其實也很直覺)。
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的mahout基于Hadoop的CF代码分析(转)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 11月上旬息壤网络域名总量呈负增长 份额
- 下一篇: 正则表达式的简单认识