【10】基于大数据hadoop框架实现PageRank算法

一、PageRank算法的简介

  • PageRank算法也叫佩奇排序算法,是Google在搜索引擎称霸互联网宝藏中的的算法之一,用于衡量特定网页相对于搜索引擎索引中的其他网页而言的重要程度。
  • 是Google创始人拉里·佩奇和谢尔盖·布林于1997年创造的
  • PageRank实现了将链接价值概念作为排名因素

本次代码计算环境是 :

  • Hadoop-3.1.2
  • 四台主机
  • 两台NN的HA(高可用的NameNode节点)
  • 两台RM的HA(高可用的ResourceManager节点)
  • 离线计算框架MapReduce

二、算法原理

1、基本原理

这个算法主要解决的问题是,对于Google搜索引擎来说,爬取了非常巨大的网页信息存储到服务器中,用户通过输入关键词之后,对于包含关键词的页面会通过这个PageRank算法得出页面的权重,最后根据页面的权重排序返回给用户,极大的提高了用户体验。那么这个算法的原理如下:

  • 入链 ====投票:PageRank让链接来“投票“,到一个页面的超链接相当于对该页投一票
  • 入链数量 :如果一个页面节点接收到的其他网页指向的入链数量越多,那么这个页面越重要。
  • 入链质量: 指向页面A的入链质量不同,质量高的页面会通过链接向其他页面传递更多的权重。所以越是质量高的页面指向页面A,则页面A越重要。
  • 初始值:Google的每个页面设置相同的PR值;pagerank算法给每个页面的PR初始值为1。
  • 迭代计算(收敛):Google不断的重复计算每个页面的PageRank。那么经过不断的重复计算,这些页面的PR值会趋向于稳定,也就是收敛的状态。在具体企业应用中怎么样确定收敛标准?(1)每个页面的PR值和上一次计算的PR相等
    (2)设定一个差值指标(0.0001)。当所有页面和上一次计算的PR差值平均小于该标准时,则收敛。(3)设定一个百分比(99%),当99%的页面和上一次计算的PR相等。

举例说明每个知识点:
在这里插入图片描述
这里的A/B/C/D模拟为四个页面,每个页面的PR的初始值为1,A的初链为2个,所以PR值会被平分为1/2,分别给了C和B,同时类式的,其他页面指向了A,给了PR值,依次类推所有页面。

2、互联网角度
  • 只出,不入:PR会为0
  • 只入,不出:PR会很高
  • 直接访问网页
3、修正PageRank计算公式:增加阻尼系数
  • 在简单公式的基础上增加了阻尼系数(damping factor)d
  • 一般取值d=0.85。
  • 完整PageRank计算公式

在这里插入图片描述

注意:
1、d:阻尼系数
2、M(i):指向i的页面集合
3、L(j):页面的出链数
4、PR(pj):j页面的PR值
5、 n:所有页面数
这个公式反映的是从概率论中,我们页面点击有85%概率是通过页面跳转到指定页面中,当然15%概率是通过直接访问页面。但是里面的迭代计算原理,更上面的分析是一致的。

4、基于大数据原生hodoop来思考这个算法
  • 1、首先MapReduce的元语是不能被破坏的:即 “相同”的key为一组,调用一次reduce方法,方法内迭代这组数据。
  • 2、通过观察,我们可以看到这样的现象,页面包含超链接,每次迭代将pr值除以链接数后得到的值传递给所链接的页面,每次迭代都要包含页面链接关系和该页面的pr值。
  • 3、MapReduce设计思路: 其中:
    map阶段:主要做两件事情。
    第一,读懂数据,第一次附加初始pr值;
    第二,映射k:v。传递页面链接关系,key为该页面,value为页面链接关系,计算链接的pr值,key为所链接的页面,value为pr值
    reduce阶段:按页分组
    第一: 两类value分别处理
    第二: 最终合并为一条数据输出:key为页面&新的pr值,value为链接关系
实例
  • 1、测试数据样本如下:
    A B D
    B C
    C A B
    D B C
    -2、 map阶段计算结果:
    A:BD
    B:1/2
    D:1/2
    A:1/
  • 3、reduce阶段的计算结果:
    //A: 1/2, B D
    //A:3/4
    A: 3/4,B,D
    这里需要注意的是:我们用MapReduce设计来计算时候,不仅要考虑每一行读取的pr值,而且要保存他们之间关系。方便下一次迭代计算。

三、Java代码实现

其中暂时核心代码如下:如需要整个demo代码,可私撩我

  • node类
public class Node {

	private double pageRank = 1.0;
	private 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 setAdjacentNodeNames(String[] adjacentNodeNames) {
		this.adjacentNodeNames = adjacentNodeNames;
		return this;
	}

	public boolean containsAdjacentNodes() {
		return adjacentNodeNames != null && adjacentNodeNames.length > 0;
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append(pageRank);

		if (getAdjacentNodeNames() != null) {
			sb.append(fieldSeparator).append(
					StringUtils.join(getAdjacentNodeNames(), fieldSeparator));
		}
		return sb.toString();
	}

	// value =1.0 B D
	public static Node fromMR(String value) throws IOException {
		String[] parts = StringUtils.splitPreserveAllTokens(value,
				fieldSeparator);
		if (parts.length < 1) {
			throw new IOException("Expected 1 or more parts but received "
					+ parts.length);
		}
		Node node = new Node().setPageRank(Double.valueOf(parts[0]));
		if (parts.length > 1) {
			node.setAdjacentNodeNames(Arrays
					.copyOfRange(parts, 1, parts.length));
		}
		return node;
	}
	public static Node fromMR(String v1,String v2) throws IOException {
		return fromMR(v1+fieldSeparator+v2);
		//1.0	B D
	}
}
  • 2、 RunJob类
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.0000001;
		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);
				
				//使用了新的输入格式化类
				job.setInputFormatClass(KeyValueTextInputFormat.class);
				
				
				Path inputPath = new Path("/data/pagerank/input/");
				
				if (i > 1) {
					inputPath = new Path("/data/pagerank/output/pr" + (i - 1));
				}
				FileInputFormat.addInputPath(job, inputPath);

				Path outpath = new Path("/data/pagerank/output/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> {
		protected void map(Text key, Text value, Context context) throws IOException, InterruptedException {
			
			int runCount = context.getConfiguration().getInt("runCount", 1);
			
			//A	   B D
			//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> {
		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) + (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()));
		}
	}
}
	
j = Math.abs(j);
			System.out.println(j + "___________");
			context.getCounter(Mycounter.my).increment(j);

			sourceNode.setPageRank(newPR);
			context.write(key, new Text(sourceNode.toString()));
		}
	}
}
  • 3、运行结果

在这里插入图片描述

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是大数据Hadoop平台实现新能源智能运营的简单代码实现,供您参考: 1. 数据采集和存储 使用Hadoop平台的MapReduce框架,编写数据采集和存储程序。程序可以从各种传感器和监测设备获取实时数据,并将其存储到Hadoop分布式文件系统(HDFS)中。 2. 数据处理和分析 使用Hadoop平台的MapReduce框架Hadoop生态系统中的数据处理工具,如Hive和Pig,编写数据处理和分析程序。程序可以对从各种传感器和监测设备中收集到的实时数据进行处理和分析,以识别出潜在的问题和改进点。例如,程序可以通过分析能源生产和消费的效率、能源质量、设备状态等方面的数据,来识别出潜在的问题。 3. 数据可视化 使用Hadoop平台的数据可视化工具,如Apache Zeppelin和Tableau,编写数据可视化程序。程序可以将处理和分析后的数据可视化,帮助运营人员更直观地了解能源生产和消费的情况,及时采取措施,提高能源生产和消费的效率。 4. 机器学习预测 使用Hadoop平台的机器学习框架,如Apache Mahout和Apache Spark,编写机器学习预测程序。程序可以分析历史数据,预测未来的能源需求和市场趋势,提高能源供应链的可靠性和稳定性。预测数据可以帮助运营人员做出更好的决策,提高新能源供应链的效率和可靠性。 以上是大数据Hadoop平台实现新能源智能运营的简单代码实现。需要注意的是,具体的实现方式可能因应用场景和数据来源的不同而有所不同。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值