一、引言
谷歌从1998年至今逐渐成为一家最有创造力、影响力的公司,其中离不开其创始人提出的PageRank算法。
在给出PageRank算法之前,我们先来回顾一下搜索引擎的工作。
PageRank算法的魅力在于提出了“链接关系”用来处理网页之间的关系,而不是早 期搜索引擎的仅利用关键字匹配和简单的布尔运算来给出搜索结果。
PageRank通过网络浩瀚的超链接关系来确定一个页面的等级。Google把从A页面到B页面的链接解释为A页面给B页面投票,Google根据投票来源(甚至来源的来源,即链接到A页面的页面)和投票目标的等级来决定新的等级。简单的说,一个高等级的页面可以使其他低等级页面的等级提升。----来自维基百科http://zh.wikipedia.org/wiki/PageRank
至于外链的关系何以这样重要也是好理解的,就像就好比一篇论文被诺贝尔奖得主所引用, 显然要比被普通研究者所引用更说明其价值。
先给大家一个直观的列子,网页B,C,D都有外链到网页A,同时网页B也有外链到C, 且网页D有外链到B和C.
这样我们粗糙的得到A的PageRank的值,PR(A) = PR(B)/2 + PR(C) + PR(D)/3.
二、数学推导
假设一个虚拟用户在互联网上的漫游过程。 假定: 虚拟用户一旦访问了一个网页后, 下一步将有相同的几率访问被该网页所链接的任何一个其它网页。 换句话说, 如果网页 Wi 有 Ni 个对外链接, 则虚拟用户在访问了 Wi 之后, 下一步点击这些链接中任何一个的几率均为 1/Ni。 初看起来, 这一假设并不合理, 因为任何用户都有偏好, 怎么可能以相同的几率访问一个网页的所有链接呢? 但虚拟用户实际上是对互联网上全体用户的一种平均意义上的代表, 这条假设就不象初看起来那么不合理了。 那么网页的排序由什么来决定呢? 是由该用户在漫游了很长时间 (理论上为无穷长时间) 后访问各网页的几率分布来决定, 访问几率越大的网页排序就越靠前。
pi(n) 表示虚拟用户在进行第 n 次浏览时访问网页 Wi 的概率,则
其中,Nj表示页面Wj的所有外链数,Pj->i表示若Wj有到Wi的外链则为1,否则为0.
为符号简洁起见, 我们将虚拟用户第 n 次浏览时访问各网页的几率合并为一个列向量 ,并引进一个只与互联网结构有关的矩阵 H, 它的第 i 行 j 列的矩阵元为Hij = pj->i / Nj,上面公式,即:
上面的数学表达是个典型的马尔可夫过程(维基百科上链接),即他的条件概率仅同系统的当前状态相关,而与他的历史与未来无关,矩阵H代表的概率就是一个转移概率。
上面的公式还得解决几个问题:
- 是否能在N足够大时得到收敛?
- 若能收敛,和给定的初始值是否有关?
还有一种情况是,我们之前假设的是用户会顺着链接一路访问下去,但实际的情况是用户中途能够离开等概率的去其他网页,设不离开的概率是a,把S修正为:
不难看出,G矩阵一定是正的,也就是个素矩阵,按照马尔可夫链基本定理,马尔可夫过程中, 如果转移矩阵是素矩阵,极限 limn→∞pn 存在,与 p0 的选取无关。这样前面的两个问题也有了解决。
至于矩阵G里面a的选取,google给出的值是0.85。因为a过大不易收敛,过小难以反映“链接分析”的本质,这是个精度和效率的折中。
这样,所有的问题就是求解下面矩阵的解,
在实际的算法里,当P(N)和P(N+1)的差值在给定的阈值内,就认为完成了收敛。
三、算法实现
在介绍算法之前,先介绍一个分析网页信息较好的一个jar包,htmlparser.jar,目前最新版是1.6。
先新建7个.html文件,只需反映其链接关系即可,如
<html>
<body>
<h1> Hello world </h1>
To Test2: <a href="test2.html">Test2</a>
<br/>
To Test3: <a href="test3.html">Test3</a>
</body>
</html>
关系用表格展示如下:
载入页面的函数:其中HtmlBean是笔者写的一个Html的javaBean,内容很简单,有该网页的路径,外链,排名。
public static void loadHtml() throws IOException, ParserException
{
System.out.println("载入页面...");
File file = new File(HtmlPath);
// 过滤文件,只寻找html文件
File[] htmlsFiles = file.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
if(pathname.getName().endsWith(".html"))
return true;
return false;
}
});
init = new double[htmlsFiles.length];
for(int i = 0;i<htmlsFiles.length;i++)
{
File f = htmlsFiles[i];
@SuppressWarnings("resource")
BufferedReader bReader = new BufferedReader(new InputStreamReader(
new FileInputStream(f)));
//读入文件
String line = bReader.readLine();
StringBuffer html = new StringBuffer();
while(line!=null)
{
html.append(line);
line = bReader.readLine();
}
HtmlBean bean = new HtmlBean();
bean.setPath(f.getName());
// System.out.println("filename: "+f.getName());
// System.out.println("absPath: "+f.getAbsolutePath());
bean.setContent(html.toString());
//HtmlPage Parser处理
Parser parser = Parser.createParser(html.toString(), "utf-8");
HtmlPage page = new HtmlPage(parser);
parser.visitAllNodesWith(page);
NodeList nodeList = page.getBody();
//在NodeList中执行过滤器时,第二个参数为True
nodeList = nodeList.extractAllNodesThatMatch(new TagNameFilter("A"),
true);// 寻找<a>节点
for(int j=0;j<nodeList.size();j++)
{
LinkTag outLinkTag = (LinkTag) nodeList.elementAt(j);
//寻找外链的href的值
bean.getOutLinks().add(outLinkTag.getAttribute("href"));
}
map.put(bean.getPath(), bean);
list.add(bean);
// 初始值
init[i] = 0.0;
}
}执行PageRank的方法:其中DAMP的阻尼系数,0.85,即上文提到的概率a.
private static double[] doPageRank()
{
double[] pr = new double[init.length];
for(int i=0;i<init.length;i++)
{
double temp = 0.0;
HtmlBean htmlBean = list.get(i);
for(int j=0;j<init.length;j++)
{
HtmlBean htmlBean2 = list.get(j);
// 计算对本页面的链接
if(i!=j&&htmlBean2.getOutLinks().size()!=0
&&htmlBean2.getOutLinks().contains(htmlBean.getPath()))
{
temp = temp + init[j]/htmlBean2.getOutLinks().size();
}
}
pr[i] = DAMP + (1-DAMP)* temp;
}
return pr;
}
/**
* 若前后两次的值相差小于阈值,认为完成收敛
* @return
*/
private static boolean check()
{
boolean flag = true;
for(int i=0;i<pr.length;i++)
{
if(Math.abs(pr[i]-init[i])>MAX)
{
flag = false;
break;
}
}
return flag;
}主函数的核心代码:
loadHtml();
pr = doPageRank();
while(!check())
{
System.arraycopy(pr, 0, init, 0, init.length);
pr = doPageRank();
}
排序过程:
// 比较器的实现
Collections.sort(list,new Comparator() {
@Override
public int compare(Object o1, Object o2) {
HtmlBean h1 = (HtmlBean) o1;
HtmlBean h2 = (HtmlBean) o2;
int em = 0;
if(h1.getPr()>h2.getPr())
{
em = -1;
}
else
{
em = 1;
}
return em;
}
});
结果:
本文介绍了PageRank算法,它是谷歌搜索引擎排名的核心技术。PageRank通过网页间的链接关系来确定页面的等级,高等级页面可以提升低等级页面的价值。算法基于马尔可夫过程,考虑用户随机浏览网页的行为,通过不断迭代收敛得到网页排名。Google设定的超链接概率a为0.85,以平衡收敛性和链接分析效果。最后,文章提到了算法的实现和htmlparser.jar库在处理网页信息中的应用。

被折叠的 条评论
为什么被折叠?



