Mapreduce -- PageRank

来源:http://www.cnblogs.com/one--way/archive/2016/07/15/5672207.html
-Advertisement-
Play Games

PageRank 簡單理解為網頁排名,但是網頁是根據什麼排名的,接下來就簡單介紹一下。 舉例: 假設網頁 A 的內容中有網頁 B,C 和 D 的鏈接,並且 A 的 PageRank的值為0.25。 那接下里我們就可以計算在網頁 A 中的其他網頁的PageRank的值了。我們拿網頁 B 來進行說明, ...


PageRank 簡單理解為網頁排名,但是網頁是根據什麼排名的,接下來就簡單介紹一下。

 

舉例:

假設網頁 A 的內容中有網頁 B,C 和 D 的鏈接,並且 A 的 PageRank的值為0.25。

那接下里我們就可以計算在網頁 A 中的其他網頁的PageRank的值了。我們拿網頁 B 來進行說明,

在網頁 A 中的網頁 B 的 PageRank 為 0.25 * (1/n) 其中n為網頁 A 中網頁鏈接數,結果則為 0.25*(1/3)。

可以簡單理解為A的PageRank被B,C 和 D 平分了,B分到了0.25的三分之一。

然後將所有網頁中的關於網頁B的pagerank值求出來,就是網頁B真實的pagerank了。

 

但是上面的例子沒有考慮到如下的特殊情況:

1 網頁A中只有指向自己的網頁鏈接。

2 網頁A中沒有任何鏈接。

如果出現以上情況,會導致pagerank結果不准確。

 

所以出現了下麵的公式:

result = sum * n + (1-n)/N

sum 為上面計算出來的,如網頁B在所有網頁中的pagerank值的總和。

n 可以理解為停留在當前網頁繼續進行網頁跳轉瀏覽的概率

1-n 可以理解為不訪問當前網頁的任何鏈接,從瀏覽器的地址欄輸入,轉去其他網頁的概率。

N 為網頁的數量

 

下麵介紹通過MapReduce實現PageRank

簡單的流程分析:

Map

取一行數據進行說明

A    B    C    D

網頁A中有網頁B,C,D的鏈接;

剛開始給網頁A一個預設的pagerank值,然後根據這個值計算其他網頁鏈接在網頁A中的PageRank。處理後的數據如下:

A    0.25    B    C    D
B    0.25*(1/3)
C    0.25*(1/3)
D    0.25*(1/3)

 

Reduce

然後通過 Reduce 計算出各個網頁在其他網頁中的 PageRank 的總和 sum,然後代入公式計算實際的PageRank,並更新 A 0.25 B C D 中的數據,這裡將0.25更新為計算出來真實的 PageRank。

重覆計算各個網頁的 PageRank 的值,直到 PageRank 的結果收斂,值趨於穩定。

A    0.25    B    C    D  =>A    ?    B    C    D

 

測試數據:

A    B       C       D
B    A       D
C    C
D    B       C

 

測試代碼:

RunJob.java

  1 import org.apache.hadoop.conf.Configuration;
  2 import org.apache.hadoop.fs.FileSystem;
  3 import org.apache.hadoop.fs.Path;
  4 import org.apache.hadoop.io.Text;
  5 import org.apache.hadoop.mapreduce.Job;
  6 import org.apache.hadoop.mapreduce.Mapper;
  7 import org.apache.hadoop.mapreduce.Reducer;
  8 import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
  9 import org.apache.hadoop.mapreduce.lib.input.KeyValueTextInputFormat;
 10 import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
 11 
 12 import java.io.IOException;
 13 
 14 /**
 15  * Created by Edward on 2016/7/13.
 16  */
 17 public class RunJob {
 18 
 19     public static enum ValueEnum{
 20         CLOSURE_VALUE;
 21     }
 22 
 23     public static void main(String[] args)
 24     {
 25 
 26         //access hdfs's user
 27         System.setProperty("HADOOP_USER_NAME","root");
 28 
 29         Configuration conf = new Configuration();
 30         conf.set("fs.defaultFS", "hdfs://node1:8020");
 31 
 32         try {
 33             int i = 0;
 34             while(true) {
 35                 i++;
 36                 conf.setInt("count", i);
 37 
 38                 FileSystem fs = FileSystem.get(conf);
 39                 Job job = Job.getInstance(conf);
 40                 job.setJarByClass(RunJob.class);
 41                 job.setMapperClass(MyMapper.class);
 42                 job.setReducerClass(MyReducer.class);
 43 
 44                 //需要指定 map out 的 key 和 value
 45                 job.setOutputKeyClass(Text.class);
 46                 job.setOutputValueClass(Text.class);
 47 
 48                 //設置輸入類的
 49                 job.setInputFormatClass(KeyValueTextInputFormat.class);
 50                 if(i==1)
 51                     FileInputFormat.addInputPath(job, new Path("/test/pagerank/input"));
 52                 else
 53                     FileInputFormat.addInputPath(job, new Path("/test/pagerank/output/pr"+(i-1)));
 54 
 55                 Path path = new Path("/test/pagerank/output/pr"+i);
 56                 if (fs.exists(path))//如果目錄存在,則刪除目錄
 57                 {
 58                     fs.delete(path, true);
 59                 }
 60                 FileOutputFormat.setOutputPath(job, path);
 61 
 62                 boolean b = job.waitForCompletion(true);
 63                 if (b) {
 64                     long closure =job.getCounters().findCounter(ValueEnum.CLOSURE_VALUE).getValue();
 65                     double avg= closure/4000.0;//計算收斂的平均值,浮動小於0.001則認為收斂
 66                     System.out.println("執行第"+i+"次, closure="+closure+",avg="+avg);
 67                     if(avg < 0.001){
 68                         System.out.println("總共執行了"+i+"次,之後收斂");
 69                         break;
 70                     }
 71                 }
 72             }
 73 
 74         } catch (Exception e) {
 75             e.printStackTrace();
 76         }
 77     }
 78 
 79 
 80     public static class MyMapper extends Mapper<Text, Text, Text, Text> {
 81         @Override
 82         protected void map(Text key, Text value, Context context) throws IOException, InterruptedException {
 83             AdjacentNodes adjacentNodes  = new AdjacentNodes();
 84             int count = context.getConfiguration().getInt("count", 1);
 85 
 86             if(count == 1)
 87             {
 88                 AdjacentNodes firstAdj = new AdjacentNodes();
 89                 firstAdj.setValue(1.0);
 90                 firstAdj.setNodes(value.toString().split("\t"));
 91                 adjacentNodes = firstAdj;
 92             }
 93             else
 94             {
 95                 //格式化 value: 1.0 B C D
 96                 adjacentNodes.formatInfo(value.toString());
 97             }
 98             //A 1.0 B C D
 99             context.write(key, new Text(adjacentNodes.toString()));
100 
101             double pagerank = adjacentNodes.getValue()/adjacentNodes.getNum();
102             for(int i=0; i<adjacentNodes.getNum(); i++)
103             {
104                 String node = adjacentNodes.getNodes()[i];
105                 //B 0.333
106                 context.write(new Text(node), new Text(pagerank+""));
107             }
108         }
109     }
110 
111     public static class MyReducer extends Reducer<Text, Text, Text, Text> {
112         @Override
113         protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
114 
115             AdjacentNodes adjacentNodes = new AdjacentNodes();
116 
117             Double sum = 0.0;
118             for(Text adj : values)
119             {
120                 String str = adj.toString();
121                 if(str.split("\t").length>1)
122                 {
123                     adjacentNodes.formatInfo(str);
124                 }
125                 else{
126                     sum += Double.parseDouble(str);   //對節點的 pagerank 求和,
127                 }
128             }
129 
130             //計算pagerank
131             double n = 0.80;
132             double pagerank = sum * n + (1-n)/4.0;// 計算pagerank 公式 sum * n + (1-n)/N
133 
134             //計算收斂的差值
135             int closure =(int)(Math.abs(pagerank - adjacentNodes.getValue()) * 1000);
136             //通過context.getCounter(ENUM)方法,每次執行reduce將closure的值進行累加,結果傳遞給主函數,
137 
138             context.getCounter(ValueEnum.CLOSURE_VALUE).increment(closure);
139 
140             adjacentNodes.setValue(pagerank);
141             context.write(key, new Text(adjacentNodes.toString()));
142         }
143     }
144 }

AdjacentNodes.java
/**
 * Created by Edward on 2016/7/14.
 */
public class AdjacentNodes {

    double value = 0.0;
    int num = 0;
    String[] nodes = null;

    public void formatInfo(String str)
    {
        String[] val = str.split("\t");
        this.setValue(Double.parseDouble(val[0]));
        this.setNum(val.length-1);

        if(this.num != 0)
            this.nodes = new String[this.num];

        for(int i=1; i<val.length; i++)
        {
            this.nodes[i-1] = val[i];
        }
    }

    public boolean isEmpty()
    {
        if(this.num == 0)
            return true;
        else
            return false;
    }

    public void setNodes(String[] nodes) {
        this.nodes = nodes;
        this.num = nodes.length;
    }

    public void setNum(int num) {
        this.num = num;
    }

    public void setValue(double value) {
        this.value = value;
    }

    public double getValue() {
        return value;
    }

    public int getNum() {
        return num;
    }

    public String[] getNodes() {
        return nodes;
    }


    @Override
    public String toString() {

        StringBuffer stringBuffer = new StringBuffer(this.value+"");

        for(int i=0; i<this.num; i++)
        {
            stringBuffer.append("\t"+this.nodes[i]);
        }

        return stringBuffer.toString();
    }
}

 

結果數據:

A       0.10135294176208584     B       C       D
B       0.12838069628609527     A       D
C       0.6560527651143326      C
D       0.12838069628609527     B       C

總共執行了24次,之後收斂;

PageRank值越高,越值得推薦。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、概念 生產者與消費者問題是一個金典的多線程協作的問題.生產者負責生產產品,並將產品存放到倉庫;消費者從倉庫中獲取產品並消費。當倉庫滿時,生產者必須停止生產,直到倉庫有位置存放產品;當倉庫空時,消費者必須停止消費,直到倉庫中有產品。 解決生產者/消費者問題主要用到如下幾個技術:1.用線程模擬生產者 ...
  • 1. 從官網下載最新版Python 3.X 後安裝;由於Mac OS X EI Capitan中預設已經集成了 Python 2.7,因此需要在Terminal中輸入 Python3 來檢測是否安裝成功,使用Python命令預設調用的是Python 2.7。 2. 安裝pip;從官網頁面下載get- ...
  • function myBrowser() { var userAgent = navigator.userAgent; //取得瀏覽器的userAgent字元串 var isOpera = userAgent.indexOf("Opera") > -1; //判斷是否Opera瀏覽器 var isI ...
  • 用百度編輯器——Ueditor(版本1.4.3.3,2016-05-18日上線)插入錨點的時候,每次總是失敗,百思不得其解。通過分析Ueditor的代碼ueditor.all.js,可以看出Ueditor插入錨點的過程,實際上是一個img標簽和a標簽相互轉換的過程,其代碼如下: 'anchor':{ ...
  • 主要練習一下GridView MainActivity.java activity_main.xml main_grid_item.xml ...
  • ObjC中怎麼判斷可變和不可變 怎麼判斷NSString和NSMutableString呢? 請聽題 這很簡單當然選B的,字元串常量是NSString。所以正確答案是A,是不是有種高考題的趕腳。建議這題出面試。 首先應該百度objc的類簇概念,然後是工廠模式。這篇筆記只講怎麼判斷,開個傳送門自己去打 ...
  • 在如今的互聯網時代,微信已是一個超級App。這篇通過ViewPager + Fragment實現一個類似於微信的界面,之前有用FragmentTabHost實現過類似界面,ViewPager的實現方式相對於FragmentTabHost的方式更簡單明瞭。 ViewPager: ViewPager繼承 ...
  • 一個簡單的SDK製作是很容易的,複雜的sdk其實就和複雜化的應用一樣,都是從簡單開始的,這裡介紹一下sdk的簡單製作 步驟: 1.創建sdk,公開文件 2.編譯、獲取sdk文件 3.導入工程,配置文件 4.解決錯誤,完成 1.創建sdk,公開文件 然後起個需要的名字 創建出這樣的sdk,自動生成的文 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...