PageRank网页排名算法

互联网上各个网页之间的链接关系我们都可以看成是一个有向图,一个网页的重要性由链接到该网页的其他网页来投票,一个较多链入的页面会有比较高等级,反之如果一个页面没有链入或链入较少等级则低,网页的PR值越高,代表网页越重要

假设一个有A、B、C、D四个网页组成的集合,B、C、D三个页面都链入到A,则A的PR值将是B、C、D三个页面PR值的总和:

PR(A)=PR(B)+PR(C)+PR(D)

继续上面的假设,B除了链接到A,还链接到C和D,C除了链接到A,还链接到B,而D只链接到A,所以在计算A的PR值时,B的PR值只能投出1/3的票,C的PR值只能投出1/2的票,而D只链接到A,所以能投出全票,所以A的PR值总和应为:

PR(A)=PR(B)/3+PR(C)/2+PR(D)

所以可以得出一个网页的PR值计算公式应为:

其中,Bu是所有链接到网页u的网页集合,网页v是属于集合Bu的一个网页,L(v)则是网页v的对外链接数(即出度)

图1-1

表1-2 根据图1-1计算的PR值

 
PA(A)


P(B)

PR(C) PR(D)
初始值 0.25  0.25 0.25
0.25

一次迭代  0.125  0.333  0.083
0.458

二次迭代  0.1665  0.4997 0.0417
0.2912

……  …… …… ……
……

n次迭代  0.1999 0.3999 0.0666
0.3333

表1-2,经过几次迭代后,PR值逐渐收敛稳定

然而在实际的网络环境中,超链接并没有那么理想化,比如PageRank模型会遇到如下两个问题:

  1.排名泄露 

  如图1-3所示,如果存在网页没有出度链接,如A节点所示,则会产生排名泄露问题,经过多次迭代后,所有网页的PR只都趋向于0

图1-3

 
PR(A)

PR(B) PR(C) PR(D)
初始值
0.25

0.25 0.25 0.25
一次迭代
0.125

0.125 0.25 0.25
二次迭代
0.125

0.125 0.125 0.25
三次迭代
0.125

0.125 0.125 0.125
……
……

…… …… ……
n次迭代
0

0 0 0

表1-4为图1-3多次迭代后结果 

   2.排名下沉

   如图1-5所示,若网页没有入度链接,如节点A所示,经过多次迭代后,A的PR值会趋向于0

  

图1-5

 

 
PR(A)

PR(B) PR(C) PR(D)
初始值
0.25

0.25 0.25 0.25
一次迭代
0

0.375 0.25 0.375
二次迭代
0

0.375 0.375 0.25
三次迭代
0

0.25 0.375 0.375
……
……

…… …… ……
n次迭代
0

…… …… ……

表1-5为图1-4多次迭代后结果 

我们假定上王者随机从一个网页开始浏览,并不断点击当前页面的链接进行浏览,直到链接到一个没有任何出度链接的网页,或者上王者感到厌倦,随机转到另外的网页开始新一轮的浏览,这种模型显然更贴近用户的习惯。为了处理那些没有任何出度链接的页面,引入阻尼系数d来表示用户到达缪戈页面后继续向后浏览的概率,一般将其设为0.85,而1-d就是用户停止点击,随机转到另外的网页开始新一轮浏览的概率,所以引入随机浏览模型的PageRank公式如下:

图1-6

代码1-7为根据图1-6建立数据集

[email protected]:/data# cat links
A       B,C,D
B       A,D
C       D
D       B

GraphBuilder步骤的主要目的是建立网页之间的链接关系图,以及为每一个网页分配初始的PR值,由于我们的数据集已经建立好网页之间的链接关系图,所以在代码1-8中只要为每个网页分配相等的PR值即可

代码1-8

package com.hadoop.mapreduce;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class GraphBuilder {

	public static class GraphBuilderMapper extends Mapper<LongWritable, Text, Text, Text> {

		private Text url = new Text();
		private Text linkUrl = new Text();

		protected void map(LongWritable key, Text value, Context context) throws java.io.IOException, InterruptedException {
			String[] tuple = value.toString().split("\t");
			url.set(tuple[0]);
			if (tuple.length == 2) {
				// 网页有出度
				linkUrl.set(tuple[1] + "\t1.0");
			} else {
				// 网页无出度
				linkUrl.set("\t1.0");
			}
			context.write(url, linkUrl);
		};
	}

	protected static void main(String[] args) throws Exception {
		Configuration conf = new Configuration();
		Job job = Job.getInstance(conf);
		job.setJobName("Graph Builder");
		job.setJarByClass(GraphBuilder.class);
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(Text.class);
		job.setMapperClass(GraphBuilderMapper.class);
		FileInputFormat.addInputPath(job, new Path(args[0]));
		FileOutputFormat.setOutputPath(job, new Path(args[1]));
		job.waitForCompletion(true);
	}

}

PageRankIter步骤的主要目的是迭代计算PageRank数值,直到满足运算结束条件,比如收敛或达到预定的迭代次数,这里采用预设迭代次数的方式,多次运行该步骤

代码1-9

package com.hadoop.mapreduce;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class PageRankIter {

	private static final double DAMPING = 0.85;

	public static class PRIterMapper extends Mapper<LongWritable, Text, Text, Text> {

		private Text prKey = new Text();
		private Text prValue = new Text();

		protected void map(LongWritable key, Text value, Context context) throws java.io.IOException, InterruptedException {
			String[] tuple = value.toString().split("\t");
			if (tuple.length <= 2) {
				return;
			}
			String[] linkPages = tuple[1].split(",");
			double pr = Double.parseDouble(tuple[2]);
			for (String page : linkPages) {
				if (page.isEmpty()) {
					continue;
				}
				prKey.set(page);
				prValue.set(tuple[0] + "\t" + pr / linkPages.length);
				context.write(prKey, prValue);
			}
			prKey.set(tuple[0]);
			prValue.set("|" + tuple[1]);
			context.write(prKey, prValue);
		};
	}

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

		private Text prValue = new Text();

		protected void reduce(Text key, Iterable<Text> values, Context context) throws java.io.IOException, InterruptedException {
			String links = "";
			double pageRank = 0;
			for (Text val : values) {
				String tmp = val.toString();
				if (tmp.startsWith("|")) {
					links = tmp.substring(tmp.indexOf("|") + 1);
					continue;
				}
				String[] tuple = tmp.split("\t");
				if (tuple.length > 1) {
					pageRank += Double.parseDouble(tuple[1]);
				}
			}
			pageRank = (1 - DAMPING) + DAMPING * pageRank;
			prValue.set(links + "\t" + pageRank);
			context.write(key, prValue);
		};
	}

	protected static void main(String[] args) throws Exception {
		Configuration conf = new Configuration();
		Job job = Job.getInstance(conf);
		job.setJobName("PageRankIter");
		job.setJarByClass(PageRankIter.class);
		job.setOutputKeyClass(Text.class);
		job.setOutputValueClass(Text.class);
		job.setMapperClass(PRIterMapper.class);
		job.setReducerClass(PRIterReducer.class);
		FileInputFormat.addInputPath(job, new Path(args[0]));
		FileOutputFormat.setOutputPath(job, new Path(args[1]));
		job.waitForCompletion(true);
	}

}

PageRankViewer步骤将迭代计算得到的最终排名结果按照PageRank值从大到小的顺序进行输出,并不需要reduce,输出的键值对为<PageRank,URL>

代码1-10

package com.hadoop.mapreduce;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.FloatWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.io.WritableComparator;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class PageRankViewer {

	public static class PageRankViewerMapper extends Mapper<LongWritable, Text, FloatWritable, Text> {

		private Text outPage = new Text();
		private FloatWritable outPr = new FloatWritable();

		protected void map(LongWritable key, Text value, Context context) throws java.io.IOException, InterruptedException {
			String[] line = value.toString().split("\t");
			outPage.set(line[0]);
			outPr.set(Float.parseFloat(line[2]));
			context.write(outPr, outPage);
		};

	}

	public static class DescFloatComparator extends FloatWritable.Comparator {

		public float compare(WritableComparator a, WritableComparable<FloatWritable> b) {
			return -super.compare(a, b);
		}

		public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) {
			return -super.compare(b1, s1, l1, b2, s2, l2);
		}
	}

	protected static void main(String[] args) throws Exception {
		Configuration conf = new Configuration();
		Job job = Job.getInstance(conf);
		job.setJobName("PageRankViewer");
		job.setJarByClass(PageRankViewer.class);
		job.setOutputKeyClass(FloatWritable.class);
		job.setSortComparatorClass(DescFloatComparator.class);
		job.setOutputValueClass(Text.class);
		job.setMapperClass(PageRankViewerMapper.class);
		FileInputFormat.addInputPath(job, new Path(args[0]));
		FileOutputFormat.setOutputPath(job, new Path(args[1]));
		job.waitForCompletion(true);
	}

}

代码1-11

package com.hadoop.mapreduce;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;

public class PageRankDriver {

	public static void main(String[] args) throws Exception {
		if (args == null || args.length != 3) {
			throw new RuntimeException("请输入输入路径、输出路径和迭代次数");
		}
		int times = Integer.parseInt(args[2]);
		if (times <= 0) {
			throw new RuntimeException("迭代次数必须大于零");
		}
		String UUID = "/" + java.util.UUID.randomUUID().toString();
		String[] forGB = { args[0], UUID + "/Data0" };
		GraphBuilder.main(forGB);
		String[] forItr = { "", "" };
		for (int i = 0; i < times; i++) {
			forItr[0] = UUID + "/Data" + i;
			forItr[1] = UUID + "/Data" + (i + 1);
			PageRankIter.main(forItr);
		}
		String[] forRV = { UUID + "/Data" + times, args[1] };
		PageRankViewer.main(forRV);
		Configuration conf = new Configuration();
		FileSystem fs = FileSystem.get(conf);
		Path path = new Path(UUID);
		fs.deleteOnExit(path);
	}

}

运行代码1-11,结果如代码1-12所示

代码1-12

[email protected]:/data# hadoop jar pageRank.jar com.hadoop.mapreduce.PageRankDriver /data /output 10……
[email protected]:/data# hadoop fs -ls -R /output-rw-r--r--   1 root supergroup          0 2017-02-10 17:55 /output/_SUCCESS-rw-r--r--   1 root supergroup         50 2017-02-10 17:55 /output/part-r-00000[email protected]:/data# hadoop fs -cat /output/part-r-000001.5149547       B1.3249696       D0.78404236      A0.37603337      C
时间: 2024-10-25 13:08:33

PageRank网页排名算法的相关文章

第十章 PageRank——Google的民主表决式网页排名技术

搜索引擎的结果取决于两组信息:网页的质量信息,这个查询与每个网页的相关性信息.这里,我们介绍前一个. 1.PageRank算法原理 算法的原理很简单,在互联网上,如果一个网页被很多其他网页所链接,说明它收到普遍的承认和信赖,那么它的排名就高.比如我们要找李开复博士,有100个人举手说自己是李开复,那么谁是真的呢?如果大家都说创新工厂的那个是真的,那么他就是真的.这就是所谓的民主表决.但是,那么多网页,我们不可能一样对待.有些可靠的链接,相应的权重就要大一点.但是麻烦来了,一开始的时候,我们怎么给

浅谈PageRank网页排序技术

PageRank的主要原理是用链接数量作为搜索排序的一个因子.在互联网上,如果一个网页被很多其他网页所链接,说明它受到普遍的承认和信赖,那么它的排名就高.这就是PageRank的核心思想.举个例子,我们知道一个网页Y的排名应该来自于所有指向这个网特的其他网页X1,X2,.......Xn,的权重之和,如图1所示,Y的网页pageRank=0.001+0.01+0.02+0.05=0.081. 图1 网页排名计算 接下来的问题就是X1,X2,X3,X4的权重分别是多少,如何度量.首先,假定所有的网

搜索引擎网页排序算法

2.1基于词频统计——词位置加权的搜索引擎 利用关键词在文档中出现的频率和位置排序是搜索引擎最早期排序的主要思想,其技术发展也最为成熟,是第一阶段搜索引擎的主要排序技术,应用非常广泛,至今仍是许多搜索引擎的核心排序技术.其基本原理是:关键词在文档中词频越高,出现的位置越重要,则被认为和检索词的相关性越好. 1)词频统计 文档的词频是指查询关键词在文档中出现的频率.查询关键词词频在文档中出现的频率越高,其相关度越大.但当关键词为常用词时,使其对相关性判断的意义非常小.TF/IDF很好的解决了这个问

黄聪:博客园的积分和排名算法探讨,积分是怎么计算的?(转)

我们先来看看现行规则,用公式表示为:-------------------------------------------------------------------BlogScore = BeRead + 10 * BeComment + 50 * CommentBlogScore:博客积分BeRead:个人博客所有随笔和文章的阅读数之和BeComment:个人博客被评论总数Comment: 个人所发表的评论总数---------------------------------------

3.4 网页分析算法

在搜索引擎中,爬虫爬取了对应的网页之后,会将网页存储到服务器的原始数据库中,之后搜索引擎会对这些网页进行分析并确定各网页的重要性,即会影响用户的检索的排名结果.对于这些重要性的确定及排名结果的确定需要算法来解决,所以先来了解一下算法. 搜索引擎的网页分析算法主要分为3类:基于用户行为的网页分析算法.基于网络拓扑的网页分析算法.基于网页内容的网页分析算法.接下来我们分别对这些算法进行讲解. 搜索引擎的网页分析算法主要分为3类:基于用户行为的网页分析算法.基于网络拓扑的网页网页分析算法.基于网页内容

搜索和网页排名的数学原理

一.布尔代数和搜索引擎 搜索引擎是每天都在使用的一种工具,它是一门非常复杂的技术,实现一个搜索引擎并非易事.但是,技术是分为术和道两种的,具体的做事方法是术,做事的原理和原则是道. 不谈搜索引擎的术,但可以说说它的道. 搜索引擎的原理相对于它在技术上的实现,就非常简单了.建立一个搜索引擎大致需要做这几件事:自动下载尽可能多的网页:建立快速有效的索引:根据相关性对网页进行公平准确的排序. 1.布尔代数 布尔代数起源于二进制.中国的阴阳学说是二进制的雏形,而二进制作为一个计数系统,是在公元前2-5世

编程之美之实时排名算法

首先来看一个实时排名算法 参考文献 某海量用户网站,用户拥有积分,积分可能会在使用过程中随时更新.现在要为该网站设计一种算法,在每次用户登录时显示其当前积分排名.用户最大规模为2亿:积分为非负整数,且小于100万. 存储结构 首先,我们用一张用户积分表user_score来保存用户的积分信息. 表结构: 示例数据: 下面的算法会基于这个基本的表结构来进行. 算法1:简单SQL查询 首先,我们很容易想到用一条简单的SQL语句查询出积分大于该用户积分的用户数量: select 1 + count(t

啥是佩奇排名算法

佩奇排名介绍 佩奇排名是根据页面之间的链接结构计算页面的值的一种算法.下面我们通过动画来理解进行计算的具体流程. 假设一个正方形表示一个 WEB 页面,一个箭头表示一个页面之间的链接. 此图表明下面 3 页包含指向上面 1 页的链接 在佩奇排名算法中,网页指向的链接越多,页面被确定为越重要. 因此,在这里,确定首页最重要. 确定首页最重要 实际上,每个页面的重要性都是通过计算来量化的. 基本的计算方法思想 1.未链接的页面分数为 1 未链接的页面分数为 1 2.有链接的页面得分为正在链接的页面的

高效网页去重算法-SimHash

记得以前有人问过我,网页去重算法有哪些,我不假思索的说出了余弦向量相似度匹配,但如果是数十亿级别的网页去重呢?这下糟糕了,因为每两个网页都需要计算一次向量内积,查重效率太低了!我当时就想:论查找效率肯定是要考虑hash算法,相同字符串的hashcode肯定相同,不同字符串的hashcode却是大不相同,这也不符合要求啊,会不会存在一种算法能够使相似字符串的code值也相同或相似呢,于是就找到了Google的网页去重算法-SimHash.我们在使用SimHash算法前需要根据文档量级选择SimHa