PageRank 算法及实例分析

article/2025/9/25 19:25:54

本文一部分是针对图的PageRank 的实现,以及具体数据集的分析过程的记录

另一部分是BFS的实现,并记录每一层的节点数

数据集下载地址  soc-Slashdot0811 、 roadNet-CA 、 soc-LiveJournal1

1. java 实现代码

Main.java

import java.util.List;public class Main{public static void main(String args[]){long start = System.currentTimeMillis();List<List<Integer>> graph = PageRank.file_to_matrix();System.out.println("开始PageRank算法...");PageRank.pagerank(graph);System.out.println("PageRank算法结束,总共用时:" + (System.currentTimeMillis() - start) + "ms");start = System.currentTimeMillis();System.out.println();System.out.println("开始进行BFS遍历...");System.out.println();BFS.bfs(graph);System.out.println();System.out.println("BFS结束,总共用时:" + (System.currentTimeMillis() - start) + "ms");}
}

PageRank.java

import java.io.*;
import java.sql.Time;
import java.util.*;public class PageRank {//    public static final int N = 77360;
//    public static final int N = 1971281;public static final int N = 4847571;
//    public static final int N = 5;private static final double AFA = 0.85;private static final double DELTA = 1;private static final double MAX_TIMES = 100;
//    private static final String FILE = "/home/jkbao/Slashdot0811.txt";
//    private static final String OUT = "/home/jkbao/result.txt";
//    private static final String FILE = "/home/jkbao/roadNet-CA.txt";
//    private static final String OUT = "/home/jkbao/result_roadNet.txt";private static final String FILE = "/home/jkbao/soc-LiveJournal1.txt";private static final String OUT = "/home/jkbao/result_LiveJournall.txt";public static void pagerank(List<List<Integer>> graph){//        List<List<Integer>> graph = new ArrayList<>();
//        List<Integer> list0 = Arrays.asList(1,2,3);
//        List<Integer> list1 = Arrays.asList(3,4);
//        List<Integer> list2 = Arrays.asList(4);
//        List<Integer> list3 = Arrays.asList(4);
//        List<Integer> list4 = Arrays.asList(0);
//        graph.add(list0);
//        graph.add(list1);
//        graph.add(list2);
//        graph.add(list3);
//        graph.add(list4);double [] Prnew = new double[N];for (int i = 0; i < N; i++) {Prnew[i] = 1.0/N;}double [] Pr;//迭代至|Pn+1−Pn|<ϵlong start = System.currentTimeMillis();long now = 0;for (int i = 1; i < MAX_TIMES; i++) {//保留迭代前的PrPr = Prnew;//迭代后Prnew = get_Prnew(graph,Pr);double delta = get_DELTA(Prnew,Pr);now = System.currentTimeMillis() - start;System.out.println("第" + i + "次迭代完成,DELTA = " + delta + ", 用时 " + now + "ms");if(delta < DELTA)break;}//打印前十个pr节点System.out.println();System.out.println("开始计算前十节点...");System.out.println();double [][] big = getBiggestPr(Prnew);for (int j = 0; j < 10; j++) {System.out.println("第" + (j+1) + "大节点, node: " + (int)big[j][0] + " pr: " + big[j][1]);}//写文件
//        BufferedWriter bw = null;
//        try {
//            bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(OUT)));
//            double sum = 0;
//            for (int j = 0; j < N; j++) {System.out.println(Prnew[j]);
//                sum+=Prnew[j];
//                bw.write(String.valueOf(Prnew[j]));
//                bw.newLine();
//            }
//            System.out.println(sum);
//
//        }catch (Exception e){
//            e.printStackTrace();
//        }}public static double [][] getBiggestPr(double [] Pr){double [][] biggestPr = new double[10][2];for (int i = 0; i < N; i++) {if (Pr[i] > biggestPr[9][1]){biggestPr[9][0] = i;biggestPr[9][1] = Pr[i];for (int j = 8; j >= 0; j--) {if (biggestPr[j+1][1] > biggestPr[j][1]){//交换biggestPr[j+1][0] = biggestPr[j+1][0] + biggestPr[j][0];biggestPr[j][0] = biggestPr[j+1][0] - biggestPr[j][0];biggestPr[j+1][0] = biggestPr[j+1][0] - biggestPr[j][0];biggestPr[j+1][1] = biggestPr[j+1][1] + biggestPr[j][1];biggestPr[j][1] = biggestPr[j+1][1] - biggestPr[j][1];biggestPr[j+1][1] = biggestPr[j+1][1] - biggestPr[j][1];}else{break;}}}}return biggestPr;}//计算|Pn+1−Pn|public static double get_DELTA(double[] Prnew,double [] Pr){double temp = 0;for (int i = 0; i < N; i++) {temp += (Prnew[i] - Pr[i])*(Prnew[i] - Pr[i]);}return Math.sqrt(temp);}//一次迭代过程public static double [] get_Prnew(List<List<Integer>> list,double [] Pr){double [] Prnew = new double[N];List<Integer> _list;int _list_size;for (int i = 0; i < N; i++) {if(i%100000 == 0)System.out.println("pr值更新到:" + i);for (int k = 0; k < N; k++) {_list = list.get(k);if (_list.size() == 0){Prnew[i] += Pr[k] * (AFA * (1.0 / N) + (1 - AFA) / N);break;}_list_size = _list.size();int has = 0;for (int j = 0; j < _list_size; j++) {if (_list.get(j) == i) {Prnew[i] += Pr[k] * (AFA * (1.0 / _list_size) + (1 - AFA) / N);has = 1;break;}}if (has == 0)Prnew[i] += Pr[k] * ((1 - AFA) / N);}}return Prnew;}//读取图,处理后得到矩阵public static List<List<Integer>> file_to_matrix(){List<List<Integer>> graph = new ArrayList<>(N);for (int i = 0; i < N; i++) {graph.add(new ArrayList<>());}BufferedReader br = null;try {br = new BufferedReader(new InputStreamReader(new FileInputStream(FILE)),65536);int delete4 = 0;while(br.readLine() != null && delete4 < 3){delete4++;}String line;String []str;
//            int max = 0;int num = 0;long start = System.currentTimeMillis();long now = 0;while((line = br.readLine()) != null){num++;if(num%1000000 == 0){now = System.currentTimeMillis() - start;System.out.println("已读取 " + num + "行! 用时 " + now + "ms");}str = line.split("\t");
//                max = Math.max(max,Integer.parseInt(str[1]));graph.get(Integer.parseInt(str[0])).add(Integer.parseInt(str[1]));}System.out.println("文件读取结束,共 " + num + "行,开始迭代!");System.out.println();
//            System.out.println(max);}catch (Exception e){e.printStackTrace();}finally {try {if (br != null)br.close();}catch (IOException e){br = null;e.printStackTrace();}finally {br = null;}}return graph;}}

BFS.java

广度优先遍历,记录每一层的节点数

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;public class BFS {public static void main(String args[]){List<List<Integer>> graph = PageRank.file_to_matrix();System.out.println();System.out.println("BFS 第一层:");bfs(graph);}public static void bfs(List<List<Integer>> graph){int flag[] = new int[PageRank.N];
//        System.out.println(flag[0]);Queue<Integer> queue = new LinkedList<>();Queue<Integer> tempQueue = new LinkedList<>();List<Integer> layer_Nodes = new ArrayList<>();queue.offer(0);flag[0] = 1;layer_Nodes.add(1);//System.out.print(0 + " ");int node;List<Integer> node_li;int sum = 0;int layer_now = 1;while(!queue.isEmpty()){node = queue.poll();sum++;if(sum%100000 == 0)System.out.println("已遍历节点数: " + sum);node_li = graph.get(node);for (int i = 0; i < node_li.size(); i++) {if (flag[node_li.get(i)] == 0){tempQueue.offer(node_li.get(i));flag[node_li.get(i)] = 1;}}if (queue.isEmpty() && !tempQueue.isEmpty()){if (layer_Nodes.size() > layer_now)layer_Nodes.set(layer_now,layer_Nodes.get(layer_now) + tempQueue.size());elselayer_Nodes.add(tempQueue.size());queue = tempQueue;tempQueue = new LinkedList<>();layer_now++;}if (queue.isEmpty() && tempQueue.isEmpty()){for (int i = 0; i < PageRank.N; i++) {if (flag[i] == 0){queue.offer(i);flag[i] = 1;layer_Nodes.set(0,layer_Nodes.get(0) + 1);layer_now = 1;//System.out.print(i + " ");break;}}}}System.out.println();System.out.println("总遍历节点数: " + sum);int check = 0;for (int i = 0; i < layer_Nodes.size(); i++) {System.out.println("第" + (i+1) + "层节点数: " + layer_Nodes.get(i));check+=layer_Nodes.get(i);}//System.out.println(check);}
}

2. 机器配置

主板:Intel HM70

Cpu:Intel 赛扬双核 B830

内存:4G

3. 实验中遇到的问题及解决方式

1.  图的存储方式问题

一开始使用邻接矩阵的方式存储图,第一个数据集就跑不过,jvm堆内存溢出,想了想问题出现在内存上,简单分析一下,第一个数据集7万多个节点,转化成矩阵就是70000 * 70000,double类型占用8个字节,矩阵存储需要的内存就是70000 * 70000 * 8个字节,大约40G,明显是不现实的。想了想发现矩阵很稀疏,所以改用邻接表存储,并且改为存储int类型数据,只在计算过程中再对图进行处理。

 

2.  Jvm堆内存溢出问题

在改变存储方式之后对于前两个数据集可以跑过,但是soc-LiveJournal1.txt跑不过,分析得知内存不够,然后调jvm参数,堆内存上限设置为3G(电脑内存一共就4G),虽然机器变得很卡但最终还是跑过了。

 

3.  BFS记录每一层节点数时复杂度不够优的问题

一开始实现BFS分层节点数记录时,对于非连通节点的处理时部分代码复杂度为O(n²),结果导致遍历到第4400000个节点附近,遍历速度急剧下降。后来发现是找根节点那部分代码复杂度太大,每次都可能要从头遍历几百万个节点,后将算法优化成上面那样,速度就极快了。

4. 实验结果与分析

相关声明:对于0出链的节点,处理方式为默认对所有节点都有出链。

数据集中的节点数目认为是最大节点号,对于既无出链又无入链的节点,认为它处于第一层。

这里用最大的那个数据集进行分析(只迭代一次):


数据集:soc-LiveJournal1.txt

已读取 1000000行! 用时 1577ms

已读取 10000000行! 用时 18901ms

已读取 20000000行! 用时 35951ms

已读取 30000000行! 用时 57776ms

已读取 40000000行! 用时 76494ms

已读取 50000000行! 用时 96713ms

已读取 60000000行! 用时 130695ms

已读取 68000000行! 用时 167051ms

文件读取结束,共 68993773行,开始迭代!

 

开始PageRank算法...

第1次迭代完成,DELTA = 4.541775462128287E-4, 用时 240438ms

 

开始计算前十节点...

 

第1大节点, node: 0 pr: 1.032699925450267E-6

第2大节点, node: 95 pr: 2.8993879389509924E-7

第3大节点, node: 4 pr: 1.1840549493809759E-7

第4大节点, node: 58 pr: 1.0603261637036512E-7

第5大节点, node: 57 pr: 7.16700270292102E-8

第6大节点, node: 12 pr: 6.907658456699886E-8

第7大节点, node: 38 pr: 6.733933106100371E-8

第8大节点, node: 150 pr: 6.573782802059104E-8

第9大节点, node: 59 pr: 6.332023896500434E-8

第10大节点, node: 12519 pr: 5.844952926088428E-8

 

PageRank算法结束,总共用时:415479ms

 

开始进行BFS遍历...

总遍历节点数: 4847571

 

第1层节点数: 397380

第2层节点数: 42274

第3层节点数: 8577

第4层节点数: 102305

第5层节点数: 1175114

第6层节点数: 2166755

第7层节点数: 811143

第8层节点数: 122072

第9层节点数: 17878

第10层节点数: 3177

第11层节点数: 684

第12层节点数: 165

第13层节点数: 28

第14层节点数: 15

第15层节点数: 4

 

BFS结束,总共用时:4736ms

Process finished with exitcode 0

 

因为电脑配置低,导致读取文件花费了大量时间,后来在我的台式机上跑,图的存储过程耗时只用了17秒,这里文件读取用的BufferedReader,默认缓存8096,后增加到65536,达到些许优化效果。

第一层节点数397380个是因为对于孤立节点,认为它们在第一层。BFS复杂度O(n),四百多万节点几秒钟遍历完。

第二个数据集roadNet-CA.txt,层数有五百多层,实验结果不再展示。

5. CPU与内存使用情况分析

根据sar记录的cpu使用情况数据绘制如下表格,蓝色曲线是cpu使用率,红色曲线是iowait。

针对表中数据相应变化情况的简单分析:

第一个阶段:内存足够,cpu使用率几乎100%,结合top命令实时监控的进程占用cpu及内存情况分析,如下图:

此时内存才使用了大概700M,java进程占用了70%的CPU资源。

 

第二个阶段:内存不足,开始换入换出虚拟内存,此时的cpu会发生iowait,如图:


此时内存已经使用了2G多(JVM堆内存分配最大只有3G),java只占用了不多的CPU资源,iowait情况严重。


第三个阶段:图存储完毕,进行迭代等过程,如图:


此时还是需要换入换出内存的,但大部分时间都在处理迭代等操作,此时内存占用2.3G左右,双核CPU有一个被完全占用,CPU使用率稳定在50%左右。时不时的会发生iowait。




http://chatgpt.dhexx.cn/article/HPgyumah.shtml

相关文章

PageRank算法(二)

原文地址&#xff1a;https://blog.csdn.net/monkey_d_meng/article/details/6556295 说明&#xff1a;这是我学习过程中看到对PageRank来龙去脉解释非常清晰的博客&#xff0c;博主很厉害&#xff0c;大家可以关注一下原创作者&#xff01; 一、PageRank算法的简单举例 Goo…

PageRank 算法实现

大数据管理与分析实验报告 实验一 大数据系统基本实验 实验二 文档倒排索引算法实现 实验三 PageRank 算法实现 实验目的 PageRank 网页排名的算法&#xff0c;曾是Google 发家致富的法宝。用于衡量特定网页相对于搜索引擎索引中的其他网页而言的重要程度。通过对PageRank 的…

(简单介绍)PageRank算法

文章目录 前言引入形式化PageRank 前言 这个是一个经典算法&#xff0c;还是有必要了解的&#xff0c;这里由于讲得不会很详细&#xff0c;所以要求你有一点数学知识&#xff0c;如果有&#xff0c;看完这篇就大概明白PageRank是个啥了。本篇不涉及证明之类的&#xff0c;而是…

算法--PageRank

概念 PageRank是Google提出的算法&#xff0c;用于衡量特定网页相对于搜索引擎索引中的其他网页而言的重要程度。是Google创始人拉里佩奇和谢尔盖布林于1997年创造的PageRank实现了将链接价值概念作为排名因素。 GOOGLE PageRank并不是唯一的链接相关的排名算法&#xff0c;而…

pagerank以及个性化的pagerank算法

pagerank以及个性化的pagerank算法 pagerank最开始是Google提出来用来衡量网页重要度排行的算法。 她的思想是基于网页之间互相的链接作为加权投票。假如网页a指向b&#xff0c; 那么网页b的重要程度受网页a的影响&#xff0c;a越重要&#xff0c;则b就越重要。假如网页c也指…

PageRank算法原理详解

&#xfeff;&#xfeff; 转自&#xff1a;http://blog.csdn.net/hguisu/article/details/7996185 1. PageRank算法概述 PageRank,即网页排名&#xff0c;又称网页级别、Google左侧排名或佩奇排名。 是Google创始人拉里佩奇和谢尔盖布林于1997年构建早期的搜索系统原型时提出…

PageRank算法改进

PageRank算法的应用 PageRank 算法是 Google 搜索引擎进行网页排名的一种算法&#xff0c;那么它如何映射到其他领域&#xff1f; 比如&#xff0c;我们如何在文献排名中应用PageRank算法呢&#xff1f; 对文献的质量进行排序是对文献价值进行评估的一种重要手段&#xff0c…

什么是Pagerank?Pagerank算法介绍与计算公式

一、什么是Pagerank&#xff1f; PageRank&#xff0c;网页排名&#xff0c;又称网页级别、Google左侧排名或佩奇排名&#xff0c;是一种由根据网页之间相互的超链接计算的技术&#xff0c;而作为网页排名的要素之一&#xff0c;而我们SEO简称为PR&#xff0c;以Google公司创办…

PageRank算法 -- 从原理到实现

本文整理自博文PageRank算法 – 从原理到实现 1. 算法来源 这个要从搜索引擎的发展讲起。最早的搜索引擎采用的是 分类目录1的方法,即通过人工进行网页分类并整理出高质量的网站。那时 Yahoo 和国内的 hao123 就是使用的这种方法。 后来网页越来越多,人工分类已经不现实了…

第4关: 网页排序——PageRank算法

要求&#xff1a;编写实现网页数据集PageRank算法的程序&#xff0c;对网页数据集进行处理得到网页权重排序。 ####相关知识 ######PageRank算法原理 1.基本思想&#xff1a; 如果网页T存在一个指向网页A的连接&#xff0c;则表明T的所有者认为A比较重要&#xff0c;从而把T的一…

PageRank算法--从原理到实现

本文将介绍PageRank算法的相关内容&#xff0c;具体如下&#xff1a; 算法来源算法原理算法证明PR值计算方法 1 幂迭代法2 特征值法3 代数法 算法实现 1 基于迭代法的简单实现2 MapReduce实现 PageRank算法的缺点写在最后参考资料 1. 算法来源 这个要从搜索引擎的发展讲起。最…

PageRank算法原理与实现

正文共835个字&#xff0c;8张图&#xff0c;预计阅读时间6分钟。 1、PageRank 1.1.简介 PageRank&#xff0c;又称网页排名、谷歌左侧排名&#xff0c;是一种由搜索引擎根据网页之间相互的超链接计算的技术&#xff0c;而作为网页排名的要素之一&#xff0c;以Google公司创办人…

PageRank算法原理及代码

本文内容出自帅器学习的课程内容&#xff0c;讲得原理清晰&#xff0c;概念深入&#xff0c;链接&#xff1a; PANKRANK算法视频 另有一篇知乎文章&#xff0c;PAGERANK讲得系统透彻&#xff0c;链接在此&#xff1a;关键词提取和摘要算法TextRank详解与实战 PAGERANK算法是一…

PageRank算法 -- 图算法

一、简述&#xff1a; PageRank算法是一个迭代求解算法&#xff0c;可以处理网页排名&#xff08;根据网页的重要性进行排序&#xff09;、社会影响力分析、文本摘要 等问题。 PageRank算法在1996年由Page和Brin提出 PageRank适用于解决用有向图表示的图数据 二、各节点重要性…

PageRank算法

一、算法原理&#xff1a; 1、如果一个网页被很多其他网页链接到的话说明这个网页比较重要&#xff0c;也就是PageRank值会相对较高 2、如果一个PageRank值很高的网页链接到一个其他的网页&#xff0c;那么被链接到的网页PageRank值也会相应提高。 例子&#xff1a; 如果一…

pagerank算法详解

目录 一、pagerank简介两个重要假设 二、pagerank算法公式定义计算演示矩阵化计算 三、存在的两个问题问题1.Dead Ends问题2.Spider Traps 一、pagerank简介 PageRank算法的基本想法是在有向图上定义一个随机游走模型&#xff0c;即一阶马尔可夫链&#xff0c;描述随机游走者沿…

整车CAN网络拓扑图

什么是智能硬件与ECU ? 何为智能硬件, 就是包含智能控制单元的硬件, 比如发动机, 发动机上有一块儿专门负责控制发动机进气量, 喷油量, 排气量的控制单元, 这块单元相当于发动机的大脑. 他具有信号发送, 信号接收, 参数存储等基本功能, 这个控制单元就是ECU. ECU(Electronic …

如何利用CANoe在两路CAN通道之间创建网关(gateway)

1 目的 利用CANoe在两路CAN通道之间创建一个网关&#xff0c;通过CAPL实现CAN1、CAN2通道间的报文转发&#xff0c;并进行故障注入测试&#xff08;通过改变某些信号的值&#xff09;。 &#xff08;本实例仅用于博主学习记录&#xff09; 2 步骤 创建一个两路通道&#xf…

CANoe-如何模拟CAN总线网关通信(满满都是细节)

网络上有不少的文章介绍使用canoe工具模拟网关把can1总线上的报文转发到can2上,那我为什么要写这篇文章呢?大家知道,我的文章不可能完全照搬别人的内容,肯定要夹带私货,有自己的理解的。所以我会从网关在can总线中的工作方式到所起的作用进行分析,学习如何在canoe中实现模…

CAN/CANopen转PROFINET网关TCO-151

型号&#xff1a;TCO-151 基本说明&#xff1a;TCO-151可实现 PROFINET网络与CANopen或CAN网络之间的数据通信。网关在PROFINET网络作为从站&#xff0c;CANopen端既可以做主站也可以做从站&#xff0c;CAN端支持CAN2.0A/CAN2.0B协议&#xff0c;支持对CAN帧进行过滤处理。 特…