第一次写CSDN的博客,感觉它的xhEditor用的不是那么顺手,这篇文章是我们课程WBIA(Web Based Information Architecture)的一个作业,是直接从作业报告word粘贴过来的,粘贴的时候挺不顺的,首先图片粘贴不过来得自己上传加上,其次格式粘贴过来有一些地方有点小问题得改。不管怎么样第一次写CSDN博客,希望大家多多包涵,有想要源码的在评论给我留言。
作业要求地址:http://net.pku.edu.cn/~wbia/2012Fall/project1.html,第一题Pagerank,本项目用Java实现。
本项目采用随机浏览模型计算Pagerank值,公式如下:
其中d为按照超链进行浏览的概率,1-d即为用户随机跳转一个新网页的概率。这里Pagerank的初始值设为1,以保证每次进行迭代计算Pagerank值时总的Pagerank值不变。
Page页面的Pagerank迭代更新时,若更新前后新老Pagerank值小于一个指定的阈值则表示Pagerank页面收敛。本项目在实现时给定一个阈值MAX_PAGERANK_ERROR,若新老页面Pagerank值差小于该阈值的页面个数小于MAX_ERROR_PAGE,则迭代收敛,算法结束。其中计算结果,当MAX_PAGERANK_ERROR=0.001,MAX_ERROR_PAGE=MAX_PAGE / 1000 + 1=12时,算法迭代37次后收敛。
所谓悬挂节点(dangling node)是出度为0的节点,即该节点没有任何到别的节点的链接。这样节点的出现导致的问题是每次迭代计算Pagerank值时,别的Page节点通过投票将自己的部分Pagerank值分配给该节点,而该节点由于没有到别的节点的链接,所以不用分配Pagerank值到别的节点。这样随着迭代计算Pagerank的进行,悬挂节点逐渐吸收Pagerank值,造成Pagerank黑洞,这对其他节点是很不公平的。
处理悬挂节点的方法主要有两种。第一种在Google发表的Pagerank论文中提到,具体如下:删除到悬挂节点的悬挂链接(这可能使一个非悬挂节点变成一个新的悬挂节点,所以得迭代删除),计算剩下非悬挂节点的Pagerank值直到收敛,然后再将删除的悬挂链接添加到LinkGraph里来,重新计算Pagerank直到收敛。这种方法将减少悬挂节点对Pagerank值的吸收。第二种方法是建立一个虚拟节点,让所有悬挂节点建立一条指向该虚拟节点的链接,然后再为虚拟节点分别建立到其他所有节点的一条链接。这样每次迭代计算Pagerank值时,悬挂节点吸收的Pagerank值将分配给虚拟节点,然后虚拟节点再将其Pagerank值分配给其他所有节点。本项目采用的是第二种方法。
本项目有类PagerankOnWiki,LinkGranphMaker,PagerankCalculator,TopNPagerank,其中类PagerankOnWiki是主要的类,包含着main()函数以及一些项目的参数变量,该类调用剩下三个类。其中项目的整体类视图如下。
PagerankOnWiki类是这个项目的主类,里面包含一些项目的参数及变量,并在类的main函数调用剩余3个类。
该类主要作用是通过从文件smallwiki-flattened.xml读入Wikipedia的数据,提取里面的Page跟该Page的Link信息,并将其存储在LinkGraph.txt中。该类主要有三个方法:BuildRawGraph(),CleanGraph(),PrintGraph()。
BuildRawGraph()通过从文件smallwiki-flattened.xml读入数据,提取Page跟对应的Link信息,建立初始的LinkGraph。其中Page通过正则表达式
CleanGraph()将BuildRawGraph()建立的LinkGraph进行处理,其中若Link对应的Page不是在本文件中则删除它(如链接到一些图片,或者非Wikipedia的数据)。并判断节点是否为悬挂节点,如果为悬挂节点则为其建立一条到虚拟节点的链接。
PrintGraph()打印建立的LinkGraph到文件LinkGraph.txt中。
该类主要在LinkGranphMaker类中建立的LinkGraph中,计算每个Page节点的Pagerank值,并将其储存在Pagerank.txt中。该类主要有方法CalPagerank(),InitPagerankValue(),IterationForPagerank(),PrintPagerank()。
CalPagerank()方法是这个类主要的方法,在这个方法里将调用InitPagerankValue()方法对Pagerank一些相关的变量进行初始化,循环调用IterationForPagerank()迭代计算Pagerank值直到算法收敛,并最终调用PrintPagerank()打印Pagerank值。
InitPagerankValue()方法对计算Pagerank值的一些变量进行初始化。
IterationForPagerank()更新Pagerank值。计算方法如下,每个Page节点将其Pagerank值平均分配到其链接的Page节点中,每个Page节点计算所有分配给它的Pagerank值总和PRFragment,并通过公式Pagerank =(1 - D) + D * PRFragment进行更新。其中为了减少所储存的链接数,LinkGraph里并没有为虚拟节点到每个节点建立一条实在的链接,所有在这里要为虚拟节点单独处理,将其pagerank值分配给所有其他节点。还有在该方法里,将对更新前后的Pagerank值进行比较,如果其差值超过MAX_PAGERANK_ERROR的Page节点个数不超过MAX_ERROR_PAGE,则算法收敛,返回程序结束标志到CalPagerank()通知其算法结束。
PrintPagerank()打印各个节点的Pagerank值到Pagerank.txt中。
该类将PagerankCalculator类计算所得到的Pagerank值从大到小进行排列,并输出前TopN个(TopN设置为10,可改变)。该类主要有方法sortPage()和PrintPagerank()。
SortPage()实现接口Comparable,对Pagerank值进行排序。
PrintPagerank()打印前TopN大Pagerank值的Page节点到TopNPagerank.txt中,其中虚拟节点不打印。
本图是通过遍历哈希表得到的,其中每行前三个数字依次为节点序号,节点存储在LinkGraph里的行号,节点的连接数,然后是Page节点Title,后面为Page的链接。
其中iterationNumber表示进行的迭代次数,MAX_ITERATION_NUMBER表示所允许的最大迭代次数,所以本项目结束是收敛结束。