[hadoop]PeopleRank初步概念与PageRank的hadoop算法

参考内容:https://blog.csdn.net/Gamer_gyt/article/details/51533186
参考内容:https://blog.csdn.net/hguisu/article/details/7996185

一:PageRank与PeopleRank

PageRank,网页排名,又称网页级别、Google左侧排名或佩奇排名,是一种由 根据网页之间相互的超链接计算的技术,而作为网页排名的要素之一,以Google公司创办人拉里·佩奇(Larry Page)之姓来命名。Google用它来体现网页的相关性和重要性,在搜索引擎优化操作中是经常被用来评估网页优化的成效因素之一。Google的创始人拉里·佩奇和谢尔盖·布林于1998年在斯坦福大学发明了这项技术。
PageRank通过网络浩瀚的超链接关系来确定一个页面的等级。Google把从A页面到B页面的链接解释为A页面给B页面投票,Google根据投票来源(甚至来源的来源,即链接到A页面的页面)和投票目标的等级来决定新的等级。简单的说,一个高等级的页面可以使其他低等级页面的等级提升。
PR算法主要用于网页评分计算,它利用互联网的网页之间的连接关系,给网页进行打分,最终PR值越高的网页价值也就越高。

自2012以来,中国开始进入社交网络的时代,开心网,人人网,新浪微博,腾讯微博,微信等社交网络应用,开始进入大家的生活。最早是由“抢车位”,“偷菜”等社交游戏带动的社交网络的兴起,如今人们会更多的利用社交网络,获取信息和分享信息。我们的互联网,正在从以网页信息为核心的网络,向着以人为核心的网络转变着。

于是有人就提出了,把PageRank模型应用于社交网络,定义以人为核心的个体价值。这样PageRank模型就有了新的应用领域,同时也有了一个新的名字PeopleRank。

二:PageRank算法的思路

这个例子中只有四个网页,如果当前在A网页,那么悠闲的上网者将会各以1/3的概率跳转到B、C、D,这里的3表示A有3条出链,如果一个网页有k条出链,那么跳转任意一个出链上的概率是1/k,同理D到B、C的概率各为1/2,而B到C的概率为0。
在这里插入图片描述
一般用转移矩阵表示上网者的跳转概率,如果用n表示网页的数目,则转移矩阵M是一个n*n的方阵;如果网页j有k个出链,那么对每一个出链指向的网页i,有M[i][j]=1/k,而其他网页的M[i][j]=0;上面示例图对应的转移矩阵如下:
在这里插入图片描述

初试时,假设上网者在每一个网页的概率都是相等的,即1/n,于是初试的概率分布就是一个所有值都为1/n的n维列向量V0,用V0去右乘转移矩阵M,就得到了第一步之后上网者的概率分布向量MV0,(nXn)*(nX1)依然得到一个nX1的矩阵。下面是V1的计算过程:
在这里插入图片描述
注意矩阵M中M[i][j]不为0表示用一个链接从j指向i,M的第一行乘以V0,表示累加所有网页到网页A的概率即得到9/24。得到了V1后,再用V1去右乘M得到V2,一直下去,最终V会收敛,即Vn=MV(n-1),上面的图示例,不断的迭代,最终V=[3/9,2/9,2/9,2/9]’:
在这里插入图片描述
以上为Pagerank的算法原理.具体的你也可以参考https://blog.csdn.net/hguisu/article/details/7996185.

三:PsgeRank技术的部分知识

由于存在一些出链为0,也就是那些不链接任何其他网页的网, 也称为孤立网页,使得很多网页能被访问到。因此需要对 PageRank公式进行修正,即在简单公式的基础上增加了***阻尼系数***(damping factor)q, q一般取值q=0.85。

其意义是,在任意时刻,用户到达某页面后并继续向后浏览的概率。 1- q= 0.15就是用户停止点击,随机跳到新URL的概率)的算法被用到了所有页面上,估算页面可能被上网者放入书签的概率。

最后,即所有这些被换算为一个百分比再乘上一个系数q。由于下面的算法,没有页面的PageRank会是0。所以,Google通过数学系统给了每个页面一个最小值。

在这里插入图片描述

这个公式就是.S Brin 和 L. Page 在《The Anatomy of a Large- scale Hypertextual Web Search Engine Computer Networks and ISDN Systems 》定义的公式。

所以一个页面的PageRank是由其他页面的PageRank计算得到。Google不断的重复计算每个页面的PageRank。如果给每个页面一个随机PageRank值(非0),那么经过不断的重复计算,这些页面的PR值会趋向于正常和稳定。这就是搜索引擎使用它的原因。
四:pagepank的mapreduce化
github地址:https://github.com/chubbyjiang/MapReduce/tree/master/src/main/java/info/xiaohei/www/mr/peoplerank
(提示代码中用的25个节点,原始数据:链接: https://pan.baidu.com/s/1QIPCfahpSTs8vcq8fCer3w 提取码: yaxg )

以4个节点为例
people.csv数据为
1,2
1,3
1,4
2,3
2,4
3,4
4,2
peoplerank.csv(默认各页面起始pr值为1)
1,1
2,1
3,1
4,1
第一步: 构建概率矩阵

map:

   public static class AdjacencyMapper extends Mapper<LongWritable, Text, Text, Text> {
            Text k = new Text();
            Text v = new Text();
    
            @Override
            protected void setup(Context context) throws IOException, InterruptedException {
                super.setup(context);
                System.out.println("AdjacencyMapper input:");
            }
    
            @Override
            protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
                //打印当前读入的数据
                System.out.println(value.toString());
                String[] strArr = HadoopUtil.SPARATOR.split(value.toString());
                //原始用户id为key,目标用户id为value
                k.set(strArr[0]);
                v.set(strArr[1]);
                context.write(k, v);
            }
        }

输入people.csv
输出到reduce内容为
1 2
1 3
1 4
2 3
2 4
3 4
4 2
reduce:

   public static class AdjacencyReducer extends Reducer<Text, Text, Text, Text> {

    Text v = new Text();

    @Override
    protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
        //初始化概率矩阵,概率矩阵只有一列,函数和总用户数相同
        //用户数
        int nums = 4;
        float[] G = new float[nums];
        //概率矩阵的值为pr公式的(1-d)/n的部分
        //阻尼系数
        float d = 0.85f;
        Arrays.fill(G, (1 - d) / nums);
        //构建用户邻接矩阵
        float[] U = new float[nums];
        //该用户的链出数
        int out = 0;
        StringBuilder printSb = new StringBuilder();
        for (Text value : values) {
            //从value中拿到目标用户的id
            int targetUserIndex = Integer.parseInt(value.toString());
            //邻接矩阵中每个目标用户对应的值为1,其余为0
            U[targetUserIndex - 1] = 1;
            out++;
            printSb.append(",").append(value.toString());
        }
        //打印reducer的输入
        

        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < nums; i++) {
            stringBuilder.append(",").append(G[i] + U[i] * d / out);
        }
        v.set(stringBuilder.toString().replaceFirst(",", ""));
        
        context.write(key, v);
    }
}

注意:float d = 0.85f;
Arrays.fill(G, (1 - d) / nums);
这里定义了阻尼系数,阻尼系数的作用在上文提起过.
G[i] + U[i] * d / out这里
U[i]/out得到的为概率矩阵,上文也提起过.
邻接矩阵*阻尼系数/该用户链出数+概率矩阵=邻接概率矩阵
在这里插入图片描述

        正常输出的邻接概率矩阵为

在这里插入图片描述

第二步:

  public class CalcPeopleRank {

/**
 * 输入邻接概率矩阵和pr矩阵
 * 按照矩阵相乘的公式,将对应的数据输出到reduce进行计算
 */
public static class CalcPeopleRankMapper extends Mapper<LongWritable, Text, Text, Text> {

    Text k = new Text();
    Text v = new Text();
    String flag = "";

    @Override
    protected void setup(Context context) throws IOException, InterruptedException {
        super.setup(context);
        FileSplit fileSplit = (FileSplit) context.getInputSplit();
        flag = fileSplit.getPath().getName();
        System.out.println("CalcPeopleRankMapper input type:");
        System.out.println(flag);
    }

    /**
     * k的作用是将pr矩阵的列和邻接矩阵的行对应起来
     * 如:pr矩阵的第一列要和邻接矩阵的第一行相乘,所以需要同时输入到reduce中
     */
    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        System.out.println(value.toString());
        int nums = 4;
        //处理pr矩阵
        if (flag.startsWith("peoplerank")) {
            String[] strArr = HadoopUtil.SPARATOR.split(value.toString());
            //第一位为用户id,输入的每行内容都为pr矩阵中的一列,所以也可以看成是列数
            k.set(strArr[0]);
            for (int i = 1; i <= nums; i++) {
                //pr为标识符,i为该列中第i行,strArr[1]为值
                v.set("pr:" + i + "," + strArr[1]);
                context.write(k, v);
            }
        }
        //处理邻接概率矩阵
        else {
            String[] strArr = HadoopUtil.SPARATOR.split(value.toString());
            //k为用户id,输入的每行就是邻接概率矩阵中的一行,所以也可以看成行号
            k.set(strArr[0]);
            for (int i = 1; i < strArr.length; i++) {
                //matrix为标识符,i为该行中第i列,strArr[i]为值
                v.set("matrix:" + i + "," + strArr[i]);
                context.write(k, v);
            }
        }
    }
}

/**
 * 每行输入都是两个矩阵相乘中对应的值
 * 如:邻接矩阵的第一行的值和pr矩阵第一列的值
 */
public static class CalcPeopleRankReducer extends Reducer<Text, Text, Text, Text> {

    Text v = new Text();

    @Override
    protected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
        System.out.println("CalcPeopleRankReducer input:");
        StringBuilder printStr = new StringBuilder();
        //pr统计
        float pr = 0f;
        StringBuffer sb = new StringBuffer();
        //存储pr矩阵列的值
        Map<Integer, Float> prMap = new HashMap<Integer, Float>();
        //存储邻接矩阵行的值
        Map<Integer, Float> matrixMap = new HashMap<Integer, Float>();
        //将两个矩阵对应的值存入对应的map中
        for (Text value : values) {
            String valueStr = value.toString();
            String[] kv = HadoopUtil.SPARATOR.split(valueStr.split(":")[1]);
            if (valueStr.startsWith("pr")) {
                prMap.put(Integer.parseInt(kv[0]), Float.valueOf(kv[1]));
            } else {
                matrixMap.put(Integer.parseInt(kv[0]), Float.valueOf(kv[1]));
            }
            printStr.append(",").append(valueStr);
        }
        System.out.println(printStr.toString().replaceFirst(",", ""));
        //根据map中的数据进行计算
        for (Map.Entry<Integer, Float> entry : matrixMap.entrySet()) {
            pr += entry.getValue() * prMap.get(entry.getKey());
            sb.append(entry.getKey()+"mm"+entry.getValue()+"pp"+ prMap.get(entry.getKey())+"ee"+pr+"pr");
            
        }
        //v.set(String.valueOf(pr));
        v.set(sb.toString()+"sl"+pr);
        System.out.println("CalcPeopleRankReducer output:");
        System.out.println(key.toString() + ":" + v.toString());
        System.out.println();
        context.write(key, v);
    	
    }
}
        public static void run() throws InterruptedException, IOException, ClassNotFoundException {
            Configuration conf = new Configuration();
            String inPath1 = HadoopUtil.HDFS + "/out/5-peoplerank/probility-matrix";
            String inPath2 = HadoopUtil.HDFS + "/data/5-peoplerank/peoplerank.csv";
            String outPath = HadoopUtil.HDFS + "/out/5-peoplerank/pr";
            JobInitModel job = new JobInitModel(new String[]{inPath1, inPath2}, outPath, conf, null, "CalcPeopleRank", CalcPeopleRank.class
                    , null, CalcPeopleRankMapper.class, Text.class, Text.class, null, null
                    , CalcPeopleRankReducer.class, Text.class, Text.class);
            BaseDriver.initJob(new JobInitModel[]{job});
    
    
    //        HdfsUtil.rmr(inPath2);
    //        HdfsUtil.rename(outPath + "/part-r-00000", inPath2);
        }
    }

在这里插入图片描述
以上为全部内容,如有错误,恳请斧正.

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值