Hadoop学习系列之PageRank
?
昨晚上不想做其他的事,突然想起來好久都沒更新博客了,shell也差不多學完了,只不過學習的時候都是只帶著書出去了,改天總結總結。Hadoop么,黃宜華老師講完了,自己也馬馬虎虎快學完了,也是沒總結,那今天就寫下前段時間寫的一個關于英文Wiki的PageRank代碼吧。
PageRank的ABC
什么是PageRank
PageRank是一種在搜索引擎中根據網頁之間相互的鏈接關系計算網頁排名的技術。
PageRank是Google用來標識網頁的等級或重要性的一種方法。其級別從1到10級,PR值越高說明該網頁越受歡迎(越重要)。
?
PageRank的基本設計思想和原則
被許多優質網頁所鏈接的網頁,多半也是優質網頁。
一個網頁要想擁有較高的PR值的條件:
PageRank的簡化模型
可以把互聯網上的各個網頁之間的鏈接關系看成一個有向圖。
對于任意網頁Pi,它的PageRank值可表示為:
?
其中Bi為所有鏈接到網頁i的網頁集合,Lj為網頁j的對外鏈接
?
簡化模型面臨的缺陷
? 實際的網絡超鏈接環境沒有這么理想化,PageRank會面臨兩個問題:
解決簡化模型的缺陷的解決辦法——采用隨機瀏覽模型:
? 假定一個上網者從一個隨機的網頁開始瀏覽
? 上網者不斷點擊當前網頁的鏈接開始下一次瀏覽
? 但是,上網者最終厭倦了,開始了一個隨機的網頁
? 隨機上網者用以上方式訪問一個新網頁的概率就等于這個網頁的PageRank值
? 這種隨機模型更加接近于用戶的瀏覽行為
采用隨機瀏覽模型后的PR值計算公式變為:
?
其中d為按照超鏈進行瀏覽的概率,1-d即為用戶隨機跳轉一個新網頁的概率,顯然跳轉到每個網頁的概率為(1-d)/N,N為所有網頁的數目。
?
依據上述公式,一般經過10次左右的計算,每一個網頁可以得到一個穩定的PR值(數學證明使用馬爾可夫鏈收斂定理,不太懂,有興趣的同學可以關注下)
?
使用MapReduce實現PageRank
顯然這樣一個需要進行大量累加計算的工作是適合用MapReduce來做的,那么怎么做呢?分三個階段完成這個事情:
? Phase1: GraphBuilder
? 建立網頁之間的超鏈接圖
? Phase2: PageRankIter
? 迭代計算各個網頁的PageRank值
? Phase3: RankViewer
? 按PageRank值從大到小輸
?
具體設計:
En_wiki中每行對應于一個頁面,頁面的標題包含在“<title>Name of thearticle</title>”中,每個頁面的鏈出標題在一對雙中括號中("[[Name of other article]]"),我們需要做的就是用PageRank算法給出每個頁面的重要性,并按重要程度從高到低輸出。首先要做的就是構建每個頁面的鏈接關系圖,這個工作我們GraphBuilder類來實現,給出的結構類似于圖的鄰接表表示方式;第二步需要做的工作就是用PageRank算法經過一定次數的迭代,得出最終每個頁面的PRValue,具體算法在PageRankler類中實現;第三步需要將結果展現出來,并按“PRvalue?????????? title”的格式降序輸出,類PageRankViewer實現該功能;最后,需要組織整個算法,這是main函數完成的功能。
以下具體闡述每個類的具體實現:
1.?????????? 整體類視圖
?
2.?????????? GraphBuilder類
map中完成鏈接圖的構造。首先需解決的問題就是如何提取出title及linktitle,我們使用正則表達式來完成:"(?<=<title>)(.*?)(?=</title>)"來完成對title的匹配,使用"(?<=\\[\\[)(.+?)(?=\\]\\])"來完成對linktitle的匹配。此處需要主要注意的在第二個匹配模式中,由于'['和']'屬于正則表達式中的元字符,因此需要對其進行轉義,在Java語言的字符串中還要對轉義字符進行一次轉義,因此會出現兩個反斜杠。提取完成之后,key設為title,初始PRValue和鏈出列表以“PRValue%%%%link1?? link2????? link3????? ...”的格式作為value發射出去。key和value的類型都是Text。
reduce階段不需要做額外的工作,將map階段給的鍵值隊原樣發射出去即可,可以使用默認的reduce來做,此處還是自己實現。
main11函數完成整個job的參數設置及運行該job,如果使用默認的reduce,此處需要具體設置map輸出的key、value以及輸出的key、value的類型,否則會出現一個類型不匹配的錯誤。由于輸出文件還要在下一個job中作為輸入,因此輸出類型設為二進制類型(SequenceFileOutputFormat),在下一步中獎輸入格式設為二進制后,map可以自己識別出key和value。另外需要做的工作就是,如果輸出目錄存在需要將其刪除,然后開始執行job。
3.?????????? PageRankler類
map的輸入和輸出的key和value都為Text類型,需要做的工作是繼續維護圖的結構以及“分餅”工作,即將自己的PRValue均分到每個鏈出的title上。從讀入的value中得到自己的PRValue和鏈出的title,由于value的格式為:“PRValue%%%%%%link1 link2????? link3????? ...”因此用兩次split就可以得到PRValue和linktitle數組。對linktitle數組中的每個元素都分配PRValue并發射出去,發射的key為linkTitle,value為PRValue/linktitle.length(),最后將圖的結構“link1?????? link2????? link3????? …”發射出去。
需要自己定制combiner,因為一個頁面中出現相同的linktitle是有可能的。如果發來的圖結構,不處理直接發射出去,如果不是,進行簡單的累加后發射。
redece階段對title從每個鏈接源得到的PR值進行合并得到PRValue,然后按照公式:newPR = (1 - d) + d * PRvalue得到newPR,注意此處隨機瀏覽的概率設置為1-d而不是(1-d)/N,主要是相對非常大的N,(1-d)/N小到可以忽略。剛開始的時候,我試圖在GraphBuilder中的map中得到N,設置了一個全局靜態變量,在map處理一行的時候對該變量加一,在本機上這個機制是有作用的,但是到集群上之后,得到的所有PRValue都是無窮大,后來領悟到:map是在各個節點上做的,所以N值不會變化,而是初始的值0,后來自己想寫一個job得到N,發現沒有任何意義,舍棄之。得到新的PRValue后,將value設為“PRValue%%%%link1?????? link2????? link3????? ...”發射,供下輪job使用。
isDouble函數完成對一個字符串是否為一個浮點數進行判斷,這個函數用在map階段,用于判斷一個value是圖結構還是分到的PRValue。
main11對整個job進行設置,輸入輸出格式都設為二進制,其他的與上個階段的main11做的事基本相同。
4.?????????? PageRankViewer類
map階段所做的事是將value中的PRValue提取出來,然后將key設為PRValue,value設為title,發射。
因為要求按降序輸出,故此處還要寫自己的Comparator,只需要返回父類的相關函數的返回值的相反值即可。
main11函數設置相關的參數和輸入輸出值的類型,基本同上個類。
5.?????????? main函數
main函數完成對所有job流程的控制,包括設置輸入輸出路徑以及參數檢查,還有設置PageRank的迭代次數等等。
?
運行結果:
本次實驗將所有title的初始PRValue設置為0.5,阻尼系數設置為0.85,PageRank迭代次數設為10次,在集群上的運行結果的前30個title列表及其PRValue值如下圖所示:
?代碼就不貼了,按照這個思路實現起來應該很簡單的
轉載于:https://www.cnblogs.com/BigBesom/archive/2012/05/15/2500891.html
總結
以上是生活随笔為你收集整理的Hadoop学习系列之PageRank的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDOJ1860 ( 统计字符 ) 【水
- 下一篇: 【HDU】2795 Billboard