什么是Pagerank
-PageRank是Google提出的算法,用于衡量特定网页相对于搜索引擎索引中的其他网页而言的重要程度。
-是Google创始人拉里.佩奇和谢尔盖.布林于1997年创造的
-PageRank实现了将链接价值概念作为排名因素
#计算环境
--Hadoop-2.7.1
--四台主机
--两台RM的HA
--离线计算框架MapReduce
算法原理
---思考超链接在互联网中的作用?
---入链====投票
PageRank让链接来“投票”,到一个页面的超链接相当于该页投一票
---入链数量
如果一个页面节点接收到的其他网页指向的入链数量越多,那么这个页面越重要。
---入链质量
指向页面A的入链质量不同,质量高的页面会通过链接向其他页面传递更多的权重。所以越是质量高的页面指向页面A,则页面A越重要。
算法原理(2)
------初始值
Google的每个页面设置相同的PR值
pagerank算法给每个页面的PR初始值为1.
-------迭代计算(收敛)
Googel不断的重复计算每个页面的PageRank,那么经过不断的重复计算,这些页面的RP值会趋向于稳定,也就是收敛的状态。
在具体企业应用中怎么样确定收敛标准?
1.每个页面的PR值和上一次计算的PR相等
2.设定一个差值指标(0.0001),当所有页面和上一次计算的PR差值平均小于该标准时,则收敛
3.设定一个百分比(99%),当99%的页面和上一次计算的PR相等
算法原理(3)
站在互联网的角度:
只出,不入:PR会为0
只入,不出:PR会很高
直接访问网页
--------修改PageRank计算公式:增加阻尼系数
在简单公式的基础上增加了阻尼系数(damping factor) d
一般取值d=0.85(google通过大量数据分析所得经验数据)
---------完整PageRank计算公式
d:阻尼系数
M(i):指向i的页面集合
L(i):页面的出链数
PR(pj):j页面的PR值
n:所有页面数
代码初试
package hadoop.mr.pagerank;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
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.input.KeyValueTextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
public class RunJob {
public static enum Mycounter {
my
}
public static void main(String[] args) {
Configuration conf = new Configuration(true);
conf.set("mapreduce.app-submission.corss-paltform", "true");
// 如果分布式运行,必须打jar包,且client在集群外非hadoop jar这种方式启动,client中必须配置jar的位置
conf.set("mapreduce.framework.name", "local");
// 这个配置只属于切换分布式到本地进程模拟运行的配置
// 不是分布式,不用打jar包
double d = 0.001;
int i = 0;
while (true) {
i++;
try {
conf.setInt("runCount", i);
FileSystem fs = FileSystem.get(conf);
Job job = Job.getInstance(conf);
job.setJarByClass(RunJob.class);
job.setJobName("pr" + i);
job.setMapperClass(PageRankMapper.class);
job.setReducerClass(PageRankReducer.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
// 使用了新的输入格式化类,未设置时默认是Text,当使用该设定,制表符前为key,后面内容为value
job.setInputFormatClass(KeyValueTextInputFormat.class);
Path inputPath = new Path("/data/input/pagerank/");
if (i > 1) {
inputPath = new Path("/data/output/pagerank/pr" + (i - 1));
}
FileInputFormat.addInputPath(job, inputPath);
Path outpath = new Path("/data/output/pagerank/pr" + i);
if (fs.exists(outpath)) {
fs.delete(outpath, true);
}
FileOutputFormat.setOutputPath(job, outpath);
boolean f = job.waitForCompletion(true);
if (f) {
System.out.println("success.");
long sum = job.getCounters().findCounter(Mycounter.my).getValue();
System.out.println(sum);
double avgd = sum / 4000.0;
if (avgd < d) {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
static class PageRankMapper extends Mapper<Text, Text, Text, Text> {
@Override
protected void map(Text key, Text value, Context context) throws IOException, InterruptedException {
int runCount = context.getConfiguration().getInt("runCount", 1);
// A B D
// A B D 0.3
// k:A
// V:B D
// K:A
// V:0.3 B D
String page = key.toString();
Node node = null;
if (runCount == 1) {
node = Node.fromMR(1.0, value.toString());
} else {
node = Node.fromMR(value.toString());
}
// A 1.0 B D 传递老的pr值和对应的页面关系
context.write(new Text(page), new Text(node.toString()));
if (node.containsAdjacentNodes()) {
// 票面值的计算
double outValue = node.getPageRank() / node.getAdjacentNodeNames().length;
for (int i = 0; i < node.getAdjacentNodeNames().length; i++) {
String outPage = node.getAdjacentNodeNames()[i];
// B:0.5
// D:0.5 页面A投给谁,谁作为Key,val是票面值,票面值为:A的pr值除以超链接数量
context.write(new Text(outPage), new Text(outValue + ""));
}
}
}
}
static class PageRankReducer extends Reducer<Text, Text, Text, Text> {
@Override
protected void reduce(Text key, Iterable<Text> iterable, Context context)
throws IOException, InterruptedException {
// 相同的key为一组
// key:页面名称比如B
// 包含两类数据
// B:1.0 C//页面对应关系及老的pr值
// B:0.5 //投票值
// B:0.5
double sum = 0.0;
Node sourceNode = null;
for (Text i : iterable) {
Node node = Node.fromMR(i.toString());
if (node.containsAdjacentNodes()) {
sourceNode = node;
} else {
sum = sum + node.getPageRank();
}
}
// 4为页面总数
double newPR = (0.15 / 4) + (0.85 * sum);
System.out.println("*****new pageRank value is" + newPR);
// 把新的pr值和计算之前的pr值比较
double d = newPR - sourceNode.getPageRank();
int j = (int) (d * 1000.0);
j = Math.abs(j);
System.out.println(j + "________");
context.getCounter(Mycounter.my).increment(j);
sourceNode.setPageRank(newPR);
context.write(key, new Text(sourceNode.toString()));
// A B D 0.8
}
}
}
package hadoop.mr.pagerank;
public class Node {
private static double pageRank = 1.0;
private static String[] adjacentNodeNames;
public static final char fieldSeparator = '\t';
public double getPageRank(){
return pageRank;
}
public Node setPageRank(double pageRank){
this.pageRank = pageRank;
return this;
}
public String[] getAdjacentNodeNames(){
return adjacentNodeNames;
}
public Node setAdjacentNodeName(String[] adacentNodeNames){
this.adjacentNodeNames = adjacentNodeNames;
return this;
}
public boolean containsAdjacentNodes(){
return adjacentNodeNames !=null&adjacentNodeNames.length>0;
}
public static Node fromMR(double st1, String st2) {
adjacentNodeNames[adjacentNodeNames.length]=st2;
return Node(st1,adjacentNodeNames);
}
private static Node Node(double st1, String[] adjacentNodeNames2) {
// TODO Auto-generated method stub
return null;
}
public static Node fromMR(String s2){
adjacentNodeNames[adjacentNodeNames.length]=s2;
return Node(pageRank, adjacentNodeNames);
}
}