1. 什麼是PageRank
PageRank對網頁排名的算法,曾是Google發家致富的法寶。PageRank算法計算每一個網頁的PageRank值,然後根據這個值的大小對網頁的重要性進行排序。
2. 簡單PageRank算法
首先,將Web做如下抽象:
- 將每個網頁抽象成一個節點;
- 如果一個頁面
A 有鏈接直接鏈向B ,則存在一條有向邊從A 到B (多個相同鏈接不重複計算邊)。
因此,整個Web被抽象爲一張有向圖。現在假設世界上只有四張網頁:
顯然這個圖是強連通的(從任一節點出發都可以到達另外任何一個節點)。然後需要用一種合適的數據結構表示頁面間的連接關係。
PageRank算法基本思想描述:被用戶訪問越多的網頁更可能質量越高,而用戶在瀏覽網頁時主要通過超鏈接進行頁面跳轉,因此需要通過分析超鏈接組成的拓撲結構來推算每個網頁被訪問頻率的高低。最簡單的,我們可以假設當一個用戶停留在某頁面時,跳轉到頁面上每個被鏈頁面的概率相同。
例如,上圖中
設初始時每個頁面的
注意:
M 第一行分別是A、B、C 和D 轉移到頁面A 的概率,而v 的第一列分別是A、B、C 和D 當前的rank ,因此用M 的第一行乘以v 的第一列,所得結果就是頁面A最新rank 的合理估計,同理,Mv 的結果就分別代表A、B、C、D 新rank 值。
然後用
3. 終止點問題
上面過程要滿足收斂性,需要具備一個條件:圖是強連通的,即從任意網頁可以到達其他任意網頁。
互聯網中存在網頁不滿足強連通的特性,因爲有一些網頁不指向任何網頁,按照上面公式迭代計算下去,導致前面累計得到的轉移概率被清零,最終得到的概率分佈向量所有元素幾乎都爲0。
假設把上面圖中
轉移矩陣
不斷迭代,最終得到所有元素都爲0。
4. 陷阱問題
陷阱問題:是指有些網頁不存在指向其他網頁的鏈接,但存在指向自己的鏈接。比如下面這個圖:
這種情況下,PageRank算法不斷迭代會導致概率分佈值全部轉移到
不斷迭代,最終得到如下結果:
5. 完整PageRank算法
爲了解決終止點問題和陷阱問題,下面需要對算法進行改進。假設選取下一個跳轉頁面時,既不選當前頁面,也不選當前網頁上的其他鏈接,而是以一定概率跳轉到其他不相關網頁,那麼上面兩個問題就能得到很好的解決,這就是完整PageRank算法思想。
假設跳轉到當前頁面(包括當前頁面上的鏈接)的概率爲
假設
利用上面公式繼續迭代下去,直到收斂,得到最終
6. Spark實現RageRank
這裏簡化初始值爲1.0,
// 生成網頁邊的關係
val links = sc.parallelize(Array(('A',Array('D')),('B',Array('A')),
('C',Array('A','B')),('D',Array('A','C'))),2).map(x => (x._1, x._2)).cache()
// 初始化rank值,2表示分兩個partition
var ranks = sc.parallelize(Array(('A',1.0),('B',1.0),('C',1.0),('D',1.0)), 2)
// 迭代10次
for ( i <- 1 to 10){
val contribs = links.join(ranks, 2)
val flatMapRDD = contribs.flatMap {
case (url,(links,rank)) => links.map(dest => (dest, rank/links.size))
}
val reduceByKeyRDD = flatMapRDD.reduceByKey(_ + _, 2)
ranks = reduceByKeyRDD.mapValues(0.15 + 0.85 * _)
}
7. 參考
- 維基百科
- 在線PageRank算法演示,作者博客,可能需要梯子,我用的梯子。
【完】