【大数据】MapReduce 编程-- PageRank--网页排名算法,用于衡量网页“重要性”-排序网页

PageRank 是 Google 创始人拉里·佩奇(Larry Page)和谢尔盖·布林(Sergey Brin)在 1998 年提出的一种网页排名算法,用于衡量网页“重要性”的一种方式。它是搜索引擎中用于排序网页的一种基础算法

一个网页越是被其他重要网页链接,它就越重要

PageRank 的计算流程

  1. 初始化:假设总共 N 个网页,每个网页初始 PR 值为 1/N。

  2. 迭代计算:通过 MapReduce 不断迭代更新 PR 值,直到值趋于稳定。

  3. 结果输出:PR 值越大,说明该网页越重要,排名越靠前



A 0.25 B C D
B 0.25 A D
C 0.25 C
D 0.25 B C
  • 第一列:网页编号(如 A)

  • 第二列:初始 PageRank 值(例如 0.25)

  • 后续列:该网页链接到的其他网页

迭代的计算PageRank值,每次MapReduce 的输出要和输入的格式是一样的,这样才能使得Mapreduce 的输出用来作为下一轮MapReduce 的输入


Map过程

解析输入行,提取:

  • 当前网页 ID

  • 当前网页的 PR 值

  • 当前网页链接的其他网页列表

计算出要链接到的其他网友的个数,然后求出当前网页对其他网页的贡献值。

第一种输出的< key ,value>中的key 表示其他网页,value 表示当前网页对其他网页的贡献值

为了区别这两种输出

出链网页贡献值(标记为 @):<出链网页, @贡献值>

第二种输出的< key ,value>中的key 表示当前网页,value 表示所有其他网页。

网页链接列表(标记为 &):<当前网页, &链接网页列表>
 

B @0.0833
C @0.0833
D @0.0833
A &B C D

import java.io.IOException;
import java.util.StringTokenizer;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;/*map过程*/
public class MyMapper extends Mapper<Object,Text,Text,Text>{        private String id;private float pr;       private int count;private float average_pr;       public void map(Object key,Text value,Context context)throws IOException,InterruptedException{            StringTokenizer str = new StringTokenizer(value.toString());//对value进行解析id =str.nextToken();//id为解析的第一个词,代表当前网页pr = Float.parseFloat(str.nextToken());//pr为解析的第二个词,转换为float类型,代表PageRank值count = str.countTokens();//count为剩余词的个数,代表当前网页的出链网页个数average_pr = pr/count;//求出当前网页对出链网页的贡献值String linkids ="&";//下面是输出的两类,分别有'@'和'&'区分while(str.hasMoreTokens()){String linkid = str.nextToken();context.write(new Text(linkid),new Text("@"+average_pr));//输出的是<出链网页,获得的贡献值>linkids +=" "+ linkid;}       context.write(new Text(id), new Text(linkids));//输出的是<当前网页,所有出链网页>}       
}

输入数据格式(value):网页ID  PageRank值  出链网页1  出链网页2 ...

输出键值对:

  1. <出链网页ID, "@贡献值">(表示这个网页从别的网页获得了多少贡献)

  2. <当前网页ID, "& 出链网页列表">(保留网页结构)

String id;         // 当前网页ID
float pr;          // 当前网页的PageRank值
int count;         // 出链网页的数量
float average_pr;  // 当前网页对每个出链网页的平均贡献值
StringTokenizer str = new StringTokenizer(value.toString());是把整行字符串(比如 "A 1.0 B C D")按照空格分割成一个个小单元(token)

id = str.nextToken();  // 第一个token是当前网页ID------取出第一个单词(比如 A),表示当前正在处理的网页 ID,赋值给 id

pr = Float.parseFloat(str.nextToken());   // 第二个token是当前网页的PageRank值
取出第二个单词(比如 "1.0"),将其转为 float 类型,就是当前网页的 PageRank 值,赋值给 pr

count = str.countTokens();// 剩下的token是出链网页数量----统计剩余 token 的数量
average_pr = pr / count; //把当前网页的 PageRank 值平均分配给所有它链接的网页

贡献值输出:

while(str.hasMoreTokens()) {String linkid = str.nextToken(); // B, 然后 C, 然后 Dcontext.write(new Text(linkid), new Text("@" + average_pr));linkids += linkid + " "; // 把 B、C、D 加入 linkids 中
}

str.hasMoreTokens() 只要还有未读取的 token(即还有出链网页没处理完),就继续执行循环体

网页结构输出(带 & 开头):

String linkids记录当前网页的所有出链网页 ID 

context.write(new Text(id), new Text(linkids));


Shuffle 是指 Map 阶段输出的数据按照 key 进行分组,并将具有相同 key 的数据发送到同一个 Reduce 任务中处理的过程 

每个网页 Map 阶段都会:

  • 向它出链的网页发 PageRank 贡献(加@前缀)

  • 自己保留一份出链结构

Shuffle 阶段:按网页ID归并聚合

  • 对 Map 输出的 key(网页 ID)进行排序

  • 将相同 key 的所有 value 合并成一个列表

Reducer 接收到的格式为:<网页ID, [贡献值, 出链结构]>

<网页ID, 列表[@贡献1, @贡献2, ..., &出链结构]>


Reduce过程

  • 求每个网页的新 PageRank 值

  • 保留该网页的出链结构

  • 输出格式为网页ID 新的PR值 出链网页列表

shuffule的输出也即是reduce的输入。

reduce输入的key 直接作为输出的key

reduce输入的value 进行解析,它是一个列表

a.若列表里的值里包含`@`,就把该值`@`后面的字符串转化成`float`型加起来

b.若列表里的值里包含`&`,就把该值`&`后面的字符串提取出来

c.把所有贡献值的加总,和提取的字符串进行连接,作为`reduce`的输出`value`

public class MyReducer extends Reducer<Text,Text,Text,Text>{

继承 Hadoop 提供的 Reducer 类,泛型参数说明:

  • Text, Text:输入的 key 和 value 类型

  • Text, Text:输出的 key 和 value 类型

public void reduce(Text key, Iterable<Text> values, Context context)
        throws IOException, InterruptedException {
为每一个网页 key 传入一个 values 列表,里面是 Shuffle 过程收集到的所有值

import java.io.IOException;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;/*** Reduce过程:计算每个网页的新PageRank值,并保留出链网页结构。* 输入:<网页ID, [@贡献值, @贡献值, ..., &出链网页列表]>* 输出:<网页ID, 新PageRank值 + 出链网页列表>*/
public class MyReducer extends Reducer<Text, Text, Text, Text> {public void reduce(Text key, Iterable<Text> values, Context context)throws IOException, InterruptedException {String lianjie = ""; // 用于保存当前网页的出链网页列表(结构信息)float pr = 0;        // 用于累加当前网页从其他网页获得的PageRank贡献值// 遍历所有传入的值:包含两类信息,分别通过首字符判断for (Text val : values) {String strVal = val.toString(); // 当前值转换为字符串if (strVal.substring(0, 1).equals("@")) {// 以@开头,表示这是从其他网页传来的PageRank贡献值// 取出@后面的数值并累加pr += Float.parseFloat(strVal.substring(1));} else if (strVal.substring(0, 1).equals("&")) {// 以&开头,表示这是本网页的出链结构信息// 将&后面的网页列表保留下来lianjie += strVal.substring(1); // 注意可能是多个网页用空格分隔}}// 平滑处理(加入跳转因子d = 0.8)// 假设网页总数为4,(1 - d) / N = 0.2 * 0.25 = 0.05// 新PageRank = d * 贡献值总和 + (1 - d)/Npr = 0.8f * pr + 0.2f * 0.25f;// 构造输出字符串:新PR值 + 出链网页列表String result = pr + lianjie;// 输出结果:<当前网页ID, 新的PageRank值 + 出链网页列表>context.write(key, new Text(result));}
}

遍历所有值,分类处理

pr += Float.parseFloat(val.toString().substring(1));

如果是 @ 开头,就从第 1 个字符开始截取字符串(去掉 @),再把它转换成浮点数,并累加到 pr

lianjie += val.toString().substring(1);

如果是 & 开头,就把 & 后面的出链网页字符串加到变量 lianjie

  • @ 开头:表示来自其他网页的 PageRank 贡献值,提取并累加。

  • & 开头:表示这是该网页自身的 出链网页结构,保留下来。

pr = 0.8f * pr + 0.2f * 0.25f;

 PageRank 中的阻尼系数模型

  • 0.8f:阻尼系数 d(表示 80% 用户点击链接)

  • 0.2f:1 - d,有 20% 用户会随机跳转

  • 0.25f:假设网页总数是 4 个,随机跳转概率均分为 0.25

PR(A) = d × 所有贡献值之和 + (1 - d) / N
 



import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.util.Scanner;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import java.net.URI;public class MyRunner {public static void main(String[] args)throws IOException, ClassNotFoundException, InterruptedException {// 创建 Hadoop 配置对象Configuration conf = new Configuration();// 使用控制台输入获取初始输入路径和输出路径Scanner sc = new Scanner(System.in);System.out.print("inputPath:");String inputPath = sc.next();      // 第一次输入的 HDFS 输入路径,如:/pagerank/inputSystem.out.print("outputPath:");String outputPath = sc.next();     // 第一次输出的 HDFS 路径,如:/pagerank/output// 进行 PageRank 的迭代计算,这里迭代 5 次for (int i = 1; i <= 5; i++) {// 创建新的 MapReduce 作业Job job = Job.getInstance(conf);// 设置 Job 的主类,用于打包 Jarjob.setJarByClass(MyRunner.class);// 设置 Map 和 Reduce 的处理类job.setMapperClass(MyMapper.class);job.setReducerClass(MyReducer.class);// 设置 Map 阶段输出键值对类型job.setMapOutputKeyClass(Text.class);job.setMapOutputValueClass(Text.class);// 设置 Reduce 阶段输出键值对类型(最终输出)job.setOutputKeyClass(Text.class);job.setOutputValueClass(Text.class);// 设置输入数据路径(每轮迭代输入路径是上一轮的输出)FileInputFormat.setInputPaths(job, new Path("hdfs://master:9000" + inputPath));// 设置输出数据路径(每轮迭代输出不同路径)FileOutputFormat.setOutputPath(job, new Path("hdfs://master:9000" + outputPath));// 更新下一轮迭代的输入输出路径inputPath = outputPath;        // 当前输出变为下一轮的输入outputPath = outputPath + i;   // 每次输出加上数字以区分路径(如 output1, output2,...)// 提交作业并等待执行完成job.waitForCompletion(true);}// 读取最终输出文件内容并打印到控制台try {// 获取 Hadoop 文件系统FileSystem fs = FileSystem.get(new URI("hdfs://master:9000"), new Configuration());// 拼接最终输出文件的路径(最后一轮输出的 part-r-00000)Path srcPath = new Path(outputPath.substring(0, outputPath.length() - 1) + "/part-r-00000");// 打开输出文件FSDataInputStream is = fs.open(srcPath);// 打印最终结果到控制台System.out.println("Results:");while (true) {String line = is.readLine(); // 读取一行结果if (line == null) break;     // 如果到文件末尾,结束循环System.out.println(line);    // 打印当前行}is.close(); // 关闭输入流} catch (Exception e) {e.printStackTrace(); // 如果读取输出失败,打印错误}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/81785.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

React Flow 数据持久化:Django 后端存储与加载的最佳实践(含详细代码解析)

在构建 React Flow 应用时&#xff0c;前端呈现的节点与连线构成的可视化流程只是冰山一角&#xff0c;其背后的数据持久化与灵活调取才是确保应用稳定运行、支持用户数据回溯与协作的关键。因此&#xff0c;后端存储与加载 React Flow 信息的环节&#xff0c;就如同整个应用的…

深度学习中的归一化:提升模型性能的关键因素

&#x1f4cc; 友情提示&#xff1a; 本文内容由银河易创AI&#xff08;https://ai.eaigx.com&#xff09;创作平台的gpt-4-turbo模型辅助完成&#xff0c;旨在提供技术参考与灵感启发。文中观点或代码示例需结合实际情况验证&#xff0c;建议读者通过官方文档或实践进一步确认…

Pandas:Series和DataFrame的概念、常用属性和方法

本文目录&#xff1a; 一、Series和Dataframe的概念二、创建Series对象三、创建Dataframe对象&#xff08;一&#xff09;Series1.Series的常用属性总结如下&#xff1a;2.Series的常用方法总结如下&#xff1a; &#xff08;二&#xff09;Dataframe1.Dataframe的常用属性2.Da…

数据中心Overlay解决方案

文档围绕数据中心 Overlay 解决方案展开,指出数据中心向大集中、虚拟化、云业务演进,传统架构存在网络规划复杂、弹性不足、业务扩展受限等问题。Overlay 网络在物理网络上构建虚拟网络,实现名址分离、网络与物理解耦,支持业务灵活部署。方案采用VXLAN 技术(如 SDN 控制模…

SpringBoot 项目实现操作日志的记录(使用 AOP 注解模式)

本文是博主在做关于如何记录用户操作日志时做的记录&#xff0c;常见的项目中难免存在一些需要记录重要日志的部分&#xff0c;例如权限和角色设定&#xff0c;重要数据的操作等部分。 博主使用 Spring 中的 AOP 功能&#xff0c;结合注解的方式&#xff0c;对用户操作过的一些…

以太联 - Intellinet 闪耀台北 SecuTech 国际安全科技应用博览会

2025 年 5 月 7 日至 9 日&#xff0c;台北 SecuTech 国际安全科技应用博览会现场热闹非凡&#xff0c;以太联 - Intellinet 携旗下前沿产品与解决方案精彩亮相&#xff0c;成为展会上一道亮丽的风景线&#xff0c;吸引了众多业内人士的目光&#xff0c;收获了广泛关注与高度认…

【华为鸿蒙电脑】首款鸿蒙电脑发布:MateBook Fold 非凡大师 MateBook Pro,擎云星河计划启动

文章目录 前言一、HUAWEI MateBook Fold 非凡大师&#xff08;一&#xff09;非凡设计&#xff08;二&#xff09;非凡显示&#xff08;三&#xff09;非凡科技&#xff08;四&#xff09;非凡系统&#xff08;五&#xff09;非凡体验 二、HUAWEI MateBook Pro三、预热&#xf…

OSA快速上手

我第一次接触OSA&#xff0c;第一感觉就是庞杂&#xff0c;相关的文档和资料基本都是英文&#xff0c;运行下示例场景&#xff0c;效果和效率确实很香。本文仅针对初次接触OSA、望而却步的朋友们进行快速运用的引导。 首先&#xff0c;找个安装包&#xff0c;导入项目后&#…

RK3568下编译解决未定义符号而报错终止链接

现象&#xff1a;我从rk3568板子上导出来了一个 libsqlite3.so 然后编译连接就会报这样的错误 解决办法有多种&#xff0c;以前我遇到这种情况&#xff0c;我都是使用sqlite3源码从新编译一份使用&#xff0c;并替换到板子上。 现在我是用另一种方法&#xff1a;增加编译参数 …

LSTM-Attention混合模型:美债危机与黄金对冲效率研究

摘要&#xff1a;本文依托多维度量化分析框架&#xff0c;结合自然语言处理&#xff08;NLP&#xff09;技术对地缘文本的情绪挖掘&#xff0c;构建包含宏观因子、风险溢价因子及技术面因子的三阶定价模型&#xff0c;对当前黄金市场的波动特征进行归因分析。实证结果显示&…

Spring Boot 多参数统一加解密方案详解:从原理到实战

Spring Boot 多参数统一加解密方案详解:从原理到实战 一、前言:为什么需要参数加解密? 在现代Web开发中,数据安全传输是基本要求。特别是涉及敏感数据(如用户隐私、支付信息等)时,仅靠HTTPS还不够,我们需要对关键参数进行二次加密。本文将详细介绍Spring Boot中实现多…

【css】【面试提问】css经典问题总结

第一章 CSS基础相关提问 1.1 选择器问题 1.1.1 选择器优先级疑问 1. 优先级规则 内联样式&#xff1a;直接写在 HTML 标签的 style 属性中的样式&#xff0c;优先级最高。例如&#xff1a; <p style"color: red;">这是一段红色文字</p>这里文字的颜…

Linux服务器配置深度学习环境(Pytorch+Anaconda极简版)

前言&#xff1a; 最近做横向需要使用实验室服务器跑模型&#xff0c;之前用师兄的账号登录服务器跑yolo&#xff0c;3张3090一轮14秒&#xff0c;我本地一张4080laptop要40秒&#xff0c;效率还是快很多&#xff0c;&#xff08;这么算一张4080桌面版居然算力能比肩3090&#…

【嵌入式】I2S音频接口3分钟入门

1. I2S接口入门 I2S&#xff08;Inter-IC Sound&#xff09;是一种专门用于数字音频数据传输的串行通信接口。以下是其核心要点&#xff1a; 1.1 基本概念 I2S是飞利浦公司开发的一种音频接口标准主要用于数字音频设备之间的数据传输采用串行通信方式 1.2 主要特点 支持立…

java spring -framework -mvc

工程demo&#xff1a;myapp011工程下“_05mvcboot01” model 目录 1、Spring MVC和MVC 2、创建项目&#xff1a; 3、处理请求 4、HTTP协议 超文本传输协议 4.1、 HTTP和HTTPS的区别 4.2、SSL证书 4.3、请求和响应 4.3.1、请求 4.3.2、响应 5、数据的传递与接收 5.1、客户端传…

没有屋檐的房子-038—田鼠的酷刑

秋天是收获的季节&#xff0c;收获之后的田野里不再是湿漉漉的。水稻此时已经了却了此生&#xff0c;他们的后代稻谷已经被搬进了打谷场&#xff0c;被蜕变成了大米&#xff0c;住进了生产队的粮仓然后又进入各家的粮食口袋或者米柜中。稻田里视野逐渐开阔&#xff0c;收割完水…

IntelliJ IDEA打开项目后,目录和文件都不显示,只显示pom.xml,怎样可以再显示出来?

检查.idea文件夹 如果项目目录中缺少.idea文件夹&#xff0c;可能导致项目结构无法正确加载。可以尝试删除项目根目录下的.idea文件夹&#xff0c;然后重新打开项目&#xff0c;IDEA会自动生成新的.idea文件夹和相关配置文件&#xff0c;从而恢复项目结构。 问题解决&#xff0…

Harmony开发 List、Grid拖动自定义排序实现

1. Harmony开发 List、Grid拖动自定义排序实现 1.1. List拖动功能 本示例基于显式动画、List组件实现了ListItem的上下拖动、ListItem切换以及ListItem插入的效果。   实现思路:List手势拖动 @Entry @Component struct ListDragPage {@State private arr: string[] = [0, …

Jules 从私有预览阶段推向全球公测

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

ubuntu上安装mysql

sudo apt update查看可用版本&#xff1a; apt-cache policy mysql-server返回&#xff1a; mysql-server: 已安装&#xff1a;(无) 候选&#xff1a; 8.0.42-0ubuntu0.24.04.1 版本列表&#xff1a; 8.0.42-0ubuntu0.24.04.1 500 500 http://cn.archive.ubuntu.com/ubuntu no…