2007年06月10日

Lucene 是一个基于 Java 的全文检索工具包,你可以利用它来为你的应用程序加入索引和检索功能。Lucene 目前是著名的 Apache Jakarta 家族中的一个开源项目,下面我们即将学习 Lucene 的索引机制以及它的索引文件的结构。

在这篇文章中,我们首先演示如何使用 Lucene 来索引文档,接着讨论如何提高索引的性能。最后我们来分析 Lucene 的索引文件结构。需要记住的是,Lucene 不是一个完整的应用程序,而是一个信息检索包,它方便你为你的应用程序添加索引和搜索功能。

架构概览

图一显示了 Lucene 的索引机制的架构。Lucene 使用各种解析器对各种不同类型的文档进行解析。比如对于 HTML 文档,HTML 解析器会做一些预处理的工作,比如过滤文档中的 HTML 标签等等。HTML 解析器的输出的是文本内容,接着 Lucene 的分词器(Analyzer)从文本内容中提取出索引项以及相关信息,比如索引项的出现频率。接着 Lucene 的分词器把这些信息写到索引文件中。

图一:Lucene 索引机制架构
图一:Lucene 索引机制架构


用Lucene索引文档

接下来我将一步一步的来演示如何利用 Lucene 为你的文档创建索引。只要你能将要索引的文件转化成文本格式,Lucene 就能为你的文档建立索引。比如,如果你想为 HTML 文档或者 PDF 文档建立索引,那么首先你就需要从这些文档中提取出文本信息,然后把文本信息交给 Lucene 建立索引。我们接下来的例子用来演示如何利用 Lucene 为后缀名为 txt 的文件建立索引。

1. 准备文本文件

首先把一些以 txt 为后缀名的文本文件放到一个目录中,比如在 Windows 平台上,你可以放到 C:\\files_to_index 下面。

2. 创建索引

清单1是为我们所准备的文档创建索引的代码。

清单1:用 Lucene 索引你的文档

package lucene.index;
            import java.io.File;
            import java.io.FileReader;
            import java.io.Reader;
            import java.util.Date;
            import org.apache.lucene.analysis.Analyzer;
            import org.apache.lucene.analysis.standard.StandardAnalyzer;
            import org.apache.lucene.document.Document;
            import org.apache.lucene.document.Field;
            import org.apache.lucene.index.IndexWriter;
            /**
            * This class demonstrates the process of creating an index with Lucene
            * for text files in a directory.
            */
            public class TextFileIndexer {
            public static void main(String[] args) throws Exception{
            //fileDir is the directory that contains the text files to be indexed
            File   fileDir  = new File("C:\\files_to_index ");
            //indexDir is the directory that hosts Lucene's index files
            File   indexDir = new File("C:\\luceneIndex");
            Analyzer luceneAnalyzer = new StandardAnalyzer();
            IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,true);
            File[] textFiles  = fileDir.listFiles();
            long startTime = new Date().getTime();
            //Add documents to the index
            for(int i = 0; i < textFiles.length; i++){
            if(textFiles[i].isFile() >> textFiles[i].getName().endsWith(".txt")){
            System.out.println("File " + textFiles[i].getCanonicalPath()
            + " is being indexed");
            Reader textReader = new FileReader(textFiles[i]);
            Document document = new Document();
            document.add(Field.Text("content",textReader));
            document.add(Field.Text("path",textFiles[i].getPath()));
            indexWriter.addDocument(document);
            }
            }
            indexWriter.optimize();
            indexWriter.close();
            long endTime = new Date().getTime();
            System.out.println("It took " + (endTime - startTime)
            + " milliseconds to create an index for the files in the directory "
            + fileDir.getPath());
            }
            }
            

正如清单1所示,你可以利用 Lucene 非常方便的为文档创建索引。接下来我们分析一下清单1中的比较关键的代码,我们先从下面的一条语句开始看起。

Analyzer luceneAnalyzer = new StandardAnalyzer();
            

这条语句创建了类 StandardAnalyzer 的一个实例,这个类是用来从文本中提取出索引项的。它只是抽象类 Analyzer 的其中一个实现。Analyzer 也有一些其它的子类,比如 SimpleAnalyzer 等。

我们接着看另外一条语句:

IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,true);
            

这条语句创建了类 IndexWriter 的一个实例,该类也是 Lucene 索引机制里面的一个关键类。这个类能创建一个新的索引或者打开一个已存在的索引并为该所引添加文档。我们注意到该类的构造函数接受三个参数,第一个参数指定了存储索引文件的路径。第二个参数指定了在索引过程中使用什么样的分词器。最后一个参数是个布尔变量,如果值为真,那么就表示要创建一个新的索引,如果值为假,就表示打开一个已经存在的索引。

接下来的代码演示了如何添加一个文档到索引文件中。

Document document = new Document();
            document.add(Field.Text("content",textReader));
            document.add(Field.Text("path",textFiles[i].getPath()));
            indexWriter.addDocument(document);
            

首先第一行创建了类 Document 的一个实例,它由一个或者多个的域(Field)组成。你可以把这个类想象成代表了一个实际的文档,比如一个 HTML 页面,一个 PDF 文档,或者一个文本文件。而类 Document 中的域一般就是实际文档的一些属性。比如对于一个 HTML 页面,它的域可能包括标题,内容,URL 等。我们可以用不同类型的 Field 来控制文档的哪些内容应该索引,哪些内容应该存储。如果想获取更多的关于 Lucene 的域的信息,可以参考 Lucene 的帮助文档。代码的第二行和第三行为文档添加了两个域,每个域包含两个属性,分别是域的名字和域的内容。在我们的例子中两个域的名字分别是"content"和"path"。分别存储了我们需要索引的文本文件的内容和路径。最后一行把准备好的文档添加到了索引当中。

当我们把文档添加到索引中后,不要忘记关闭索引,这样才保证 Lucene 把添加的文档写回到硬盘上。下面的一句代码演示了如何关闭索引。

indexWriter.close();
            

利用清单1中的代码,你就可以成功的将文本文档添加到索引中去。接下来我们看看对索引进行的另外一种重要的操作,从索引中删除文档。


从索引中删除文档

类IndexReader负责从一个已经存在的索引中删除文档,如清单2所示。

清单2:从索引中删除文档

File   indexDir = new File("C:\\luceneIndex");
            IndexReader ir = IndexReader.open(indexDir);
            ir.delete(1);
            ir.delete(new Term("path","C:\\file_to_index\lucene.txt"));
            ir.close();
            

在清单2中,第二行用静态方法 IndexReader.open(indexDir) 初始化了类 IndexReader 的一个实例,这个方法的参数指定了索引的存储路径。类 IndexReader 提供了两种方法去删除一个文档,如程序中的第三行和第四行所示。第三行利用文档的编号来删除文档。每个文档都有一个系统自动生成的编号。第四行删除了路径为"C:\\file_to_index\lucene.txt"的文档。你可以通过指定文件路径来方便的删除一个文档。值得注意的是虽然利用上述代码删除文档使得该文档不能被检索到,但是并没有物理上删除该文档。Lucene 只是通过一个后缀名为 .delete 的文件来标记哪些文档已经被删除。既然没有物理上删除,我们可以方便的把这些标记为删除的文档恢复过来,如清单 3 所示,首先打开一个索引,然后调用方法 ir.undeleteAll() 来完成恢复工作。

清单3:恢复已删除文档

File   indexDir = new File("C:\\luceneIndex");
            IndexReader ir = IndexReader.open(indexDir);
            ir.undeleteAll();
            ir.close();
            

你现在也许想知道如何物理上删除索引中的文档,方法也非常简单。清单 4 演示了这个过程。

清单4:如何物理上删除文档

File   indexDir = new File("C:\\luceneIndex");
            Analyzer luceneAnalyzer = new StandardAnalyzer();
            IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,false);
            indexWriter.optimize();
            indexWriter.close();
            

在清单 4 中,第三行创建了类 IndexWriter 的一个实例,并且打开了一个已经存在的索引。第 4 行对索引进行清理,清理过程中将把所有标记为删除的文档物理删除。

Lucene 没有直接提供方法对文档进行更新,如果你需要更新一个文档,那么你首先需要把这个文档从索引中删除,然后把新版本的文档加入到索引中去。


提高索引性能

利用 Lucene,在创建索引的工程中你可以充分利用机器的硬件资源来提高索引的效率。当你需要索引大量的文件时,你会注意到索引过程的瓶颈是在往磁盘上写索引文件的过程中。为了解决这个问题, Lucene 在内存中持有一块缓冲区。但我们如何控制 Lucene 的缓冲区呢?幸运的是,Lucene 的类 IndexWriter 提供了三个参数用来调整缓冲区的大小以及往磁盘上写索引文件的频率。

1.合并因子(mergeFactor)

这个参数决定了在 Lucene 的一个索引块中可以存放多少文档以及把磁盘上的索引块合并成一个大的索引块的频率。比如,如果合并因子的值是 10,那么当内存中的文档数达到 10 的时候所有的文档都必须写到磁盘上的一个新的索引块中。并且,如果磁盘上的索引块的隔数达到 10 的话,这 10 个索引块会被合并成一个新的索引块。这个参数的默认值是 10,如果需要索引的文档数非常多的话这个值将是非常不合适的。对批处理的索引来讲,为这个参数赋一个比较大的值会得到比较好的索引效果。

2.最小合并文档数

这个参数也会影响索引的性能。它决定了内存中的文档数至少达到多少才能将它们写回磁盘。这个参数的默认值是10,如果你有足够的内存,那么将这个值尽量设的比较大一些将会显著的提高索引性能。

3.最大合并文档数

这个参数决定了一个索引块中的最大的文档数。它的默认值是 Integer.MAX_VALUE,将这个参数设置为比较大的值可以提高索引效率和检索速度,由于该参数的默认值是整型的最大值,所以我们一般不需要改动这个参数。

清单 5 列出了这个三个参数用法,清单 5 和清单 1 非常相似,除了清单 5 中会设置刚才提到的三个参数。

清单5:提高索引性能

/**
            * This class demonstrates how to improve the indexing performance
            * by adjusting the parameters provided by IndexWriter.
            */
            public class AdvancedTextFileIndexer  {
            public static void main(String[] args) throws Exception{
            //fileDir is the directory that contains the text files to be indexed
            File   fileDir  = new File("C:\\files_to_index");
            //indexDir is the directory that hosts Lucene's index files
            File   indexDir = new File("C:\\luceneIndex");
            Analyzer luceneAnalyzer = new StandardAnalyzer();
            File[] textFiles  = fileDir.listFiles();
            long startTime = new Date().getTime();
            int mergeFactor = 10;
            int minMergeDocs = 10;
            int maxMergeDocs = Integer.MAX_VALUE;
            IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,true);
            indexWriter.mergeFactor = mergeFactor;
            indexWriter.minMergeDocs = minMergeDocs;
            indexWriter.maxMergeDocs = maxMergeDocs;
            //Add documents to the index
            for(int i = 0; i < textFiles.length; i++){
            if(textFiles[i].isFile() >> textFiles[i].getName().endsWith(".txt")){
            Reader textReader = new FileReader(textFiles[i]);
            Document document = new Document();
            document.add(Field.Text("content",textReader));
            document.add(Field.Keyword("path",textFiles[i].getPath()));
            indexWriter.addDocument(document);
            }
            }
            indexWriter.optimize();
            indexWriter.close();
            long endTime = new Date().getTime();
            System.out.println("MergeFactor: " + indexWriter.mergeFactor);
            System.out.println("MinMergeDocs: " + indexWriter.minMergeDocs);
            System.out.println("MaxMergeDocs: " + indexWriter.maxMergeDocs);
            System.out.println("Document number: " + textFiles.length);
            System.out.println("Time consumed: " + (endTime - startTime) + " milliseconds");
            }
            }
            

通过这个例子,我们注意到在调整缓冲区的大小以及写磁盘的频率上面 Lucene 给我们提供了非常大的灵活性。现在我们来看一下代码中的关键语句。如下的代码首先创建了类 IndexWriter 的一个实例,然后对它的三个参数进行赋值。

int mergeFactor = 10;
            int minMergeDocs = 10;
            int maxMergeDocs = Integer.MAX_VALUE;
            IndexWriter indexWriter = new IndexWriter(indexDir,luceneAnalyzer,true);
            indexWriter.mergeFactor = mergeFactor;
            indexWriter.minMergeDocs = minMergeDocs;
            indexWriter.maxMergeDocs = maxMergeDocs;
            

下面我们来看一下这三个参数取不同的值对索引时间的影响,注意参数值的不同和索引之间的关系。我们为这个实验准备了 10000 个测试文档。表 1 显示了测试结果。

表1:测试结果
表1:测试结果

通过表 1,你可以清楚地看到三个参数对索引时间的影响。在实践中,你会经常的改变合并因子和最小合并文档数的值来提高索引性能。只要你有足够大的内存,你可以为合并因子和最小合并文档数这两个参数赋尽量大的值以提高索引效率,另外我们一般无需更改最大合并文档数这个参数的值,因为系统已经默认将它设置成了最大。


Lucene 索引文件结构分析

在分析 Lucene 的索引文件结构之前,我们先要理解反向索引(Inverted index)这个概念,反向索引是一种以索引项为中心来组织文档的方式,每个索引项指向一个文档序列,这个序列中的文档都包含该索引项。相反,在正向索引中,文档占据了中心的位置,每个文档指向了一个它所包含的索引项的序列。你可以利用反向索引轻松的找到那些文档包含了特定的索引项。Lucene正是使用了反向索引作为其基本的索引结构。


索引文件的逻辑视图

在Lucene 中有索引块的概念,每个索引块包含了一定数目的文档。我们能够对单独的索引块进行检索。图 2 显示了 Lucene 索引结构的逻辑视图。索引块的个数由索引的文档的总数以及每个索引块所能包含的最大文档数来决定。

图2:索引文件的逻辑视图
图2:索引文件的逻辑视图


Lucene 中的关键索引文件

下面的部分将会分析Lucene中的主要的索引文件,可能分析有些索引文件的时候没有包含文件的所有的字段,但不会影响到对索引文件的理解。

1.索引块文件

这个文件包含了索引中的索引块信息,这个文件包含了每个索引块的名字以及大小等信息。表 2 显示了这个文件的结构信息。

表2:索引块文件结构
表2:索引块文件结构

2.域信息文件

我们知道,索引中的文档由一个或者多个域组成,这个文件包含了每个索引块中的域的信息。表 3 显示了这个文件的结构。

表3:域信息文件结构
表3:域信息文件结构

3.索引项信息文件

这是索引文件里面最核心的一个文件,它存储了所有的索引项的值以及相关信息,并且以索引项来排序。表 4 显示了这个文件的结构。

表4:索引项信息文件结构
表4:索引项信息文件结构

4.频率文件

这个文件包含了包含索引项的文档的列表,以及索引项在每个文档中出现的频率信息。如果Lucene在索引项信息文件中发现有索引项和搜索词相匹配。那么 Lucene 就会在频率文件中找有哪些文件包含了该索引项。表5显示了这个文件的一个大致的结构,并没有包含这个文件的所有字段。

表5:频率文件的结构
表5:频率文件的结构

5.位置文件

这个文件包含了索引项在每个文档中出现的位置信息,你可以利用这些信息来参与对索引结果的排序。表 6 显示了这个文件的结构

表6:位置文件的结构
表6:位置文件的结构

到目前为止我们介绍了 Lucene 中的主要的索引文件结构,希望能对你理解 Lucene 的物理的存储结构有所帮助。


总结

目前已经有非常多的知名的组织正在使用 Lucene,比如,Lucene 为 Eclipse 的帮助系统,麻省理工学院的 OpenCourseWare 提供了搜索功能。通过阅读这篇文章,希望你能对 Lucene 的索引机制有所了解,并且你会发现利用 Lucene 创建索引是非常简单的事情。


参考资料

学习

获得产品和技术

  • 下载 Lucene 最新版本。

讨论


关于作者

周登朋,上海交通大学研究生,目前在IBM上海国际化实验室(SGL)实习,对Java技术以及信息检索技术非常感兴趣,你可以通过 zhoudengpeng@yahoo.com.cn来联系他.

1、查询处理:百度怎么处理用户查询的呢?归纳如下:首先根据分割符号将查询分开,然后看看是否有重复的字符串,如果有,就抛弃多余的,只保留一个,接着判断是否有英文或者数字,如果有的话,把英文或者数字当作一个整体保留并把前后的中文切开.

2、中文分词
百度对于少于3个字符的串没有切分;百度应该采取了两套索引机制,一种是按照单词索引,一种是按照N-GRAM索引;判断一个分词系统好不好,关键看两点,一个是消除歧义能力;一个是词典未登录词的识别比如人名,地名,机构名等.那么百度用的是什么方法?我的判断是用双向最大匹配算法,在这种情况下,百度采取最短路径方法,也就是切分的片断越少越好,比如< 古巴,比,伦理>和< 古巴比伦,理>相比选择后者,< 北京,华,烟云>和< 北,京华烟云>相比选择后者.还有类似的一些例子,这样基本可以解释这些输出结果.如果正向反向分词不一致,而且最短路径也相同,那怎么办?百度的可能选择是这种情况下选择单字少的那组切分结果.

百度一直宣传自己在中文处理方面的优势,从上面看,分词算法并无特殊之处,消歧效果并不理想,即使百度采取比上述分词算法复杂些的算法也难以说成是优势,如果说百度有优势的话,唯一的优势就是那个很大的专用词典,这个专用词典登录了人名(比如大长今),称谓(比如老太太),部分地名(比如阿联酋等),估计百度采用学术界公布的比较新的命名实体识别算法从语料库里面不断识别出词典未登录词,逐渐扩充这个专门词典.如果这就是优势的话,那么这个优势能够保持多久就是个很明显的问题.

3、拼写检查错误提示:
  后台作业: 
  (1)前面的文章我们说过,百度分词使用的词典至少包含两个词典一个是普通词典,另外一个是专用词典(专名等),百度利用拼音标注程序依次扫描所有词典中的每个词条,然后标注拼音,如果是多音字则把多个音都标上,比如”长大”,会被标注为”zhang da/chang da”两个词条.
  (2)通过标注完的词条,建立同音词词典,比如上面的”长大”,会有两个词条: zhang daà长大” , chang daà长大.
  (3)利用用户查询LOG频率信息给予每个中文词条一个权重;
  (4)OK,同音词词典建立完成了,当然随着分词词典的逐步扩大,同音词词典也跟着同步扩大;

  拼写检查:
  (1)用户输入查询,如果是多个子字符串,不作拼写检查;
  (2)对于用户查询,先查分词词典,如果发现有这个单词词条,OK,不作拼写检查;
  (3)如果发现词典里面不包含用户查询,启动拼写检查系统;首先利用拼音标注程序对用户输入进行拼音标注;
  (4)对于标注好的拼音在同音词词典里面扫描,如果没有发现则不作任何提示;
  (5)如果发现有词条,则按照顺序输出权重比较大的几个提示结果;

  拼音提示:
  (1)对于用户输入的拼音在同音词词典里面扫描,如果没有发现则不作任何提示;
  (2)如果发现有词条,则按照顺序输出权重比较大的几个提示结果;

4、中文分词改进:上面说过,经过分析得出百度的分词系统采用双向最大匹配分词,但是后来发现推理过程中存在一个漏洞,而且推导出来的百度分词算法步骤还是过于繁琐,所以进一步进行分析,看看是否前面的推导有错误.

总结:
   重新归纳一下百度的分词系统:首先用专有词典采用最大正向匹配分词,切分出部分结果,剩余没有切分交给普通词典,同样采取正向最大匹配分词,最后输出结果.
   另外,GOOGLE也是采用正向最大匹配分词算法,不过好像没有那个专用词典,所以很多专名都被切碎了.

1. 什么是PageRank
2. PageRank的决定因素
3. 如何查知PageRank
4. PageRank的重要性
5. Google的前1,000项搜索结果
6. PageRank与其它影响网站排名因素间的区别
一:什么是PageRank(网页级别)
PageRank(网页级别)是Google用于评测一个网页“重要性”的一种方法。在揉合了诸如Title标识和Keywords标识等所有其它因素之后,Google通过PageRank来调整结果,使那些更具“重要性”的网页在搜索结果中另网站排名获得提升,从而提高搜索结果的相关性和质量。

  简单说来,Google通过下述几个步骤来实现网页在其搜索结果页(SERPS)中的排名:
  1) 找到所有与搜索关键词匹配的网页
  2) 根据页面因素如标题\关键词密度等排列等级
  3) 计算导入链接的锚文本中的关键词
  4) 通过PageRank得分调整网站排名结果
  事实上,真正的网站排名过程并不是这么简单,我们会在后面进行详细深入的阐述。

二:PageRank的决定因素
Google的PageRank是基于这样一个理论:若B网页设置有连接A网页的链接(B为A的导入链接时),说明B认为A有链接价值,是一个“重要”的网页。当B网页级别(重要性)比较高时,则A网页可从B网页这个导入链接分得一定的级别(重要性),并平均分配给A网页上的导出链接。

导入链接(也叫逆向链接)指链至你网站的站点,也就是我们一般所说的“外部链接”。而当你链至另外一个站点,那么这个站点就是你的“导出链接”,即你向其它网站提供的本站链接。

PageRank反映了一个网页的导入链接的级别(重要性)。所以一般说来,PageRank是由一个网站的导入链接的数量和这些链接的级别(重要性)所决定的。

三:如何知道一个网页的PageRank得分
可从http://toolbar.google.com上下载并安装Google的工具栏,这样就能显示所浏览网页的PageRank得分了。PageRank得分从0到10,若不能显示PageRank得分,可检查所安装版本号,需将老版本完全卸载,重启机器后安装最新版本即可。

四:PageRank的重要性
搜索引擎网站排名算法中的各排名因子的重要性均取决于它们所提供信息的质量。但如果排名因子具有易操纵性,则往往会被一些网站管理员利用来实现不良竞争。例如初引入的排名因子之一–关键词元标识(Meta Keywords),是由于理论上它可以很好地概括反映一个页面的内容,但后来却由于一些网站管理员的恶意操纵而不得不黯然退出。所以“加权值”–即我们对该因子提供信息的信任程度是由排名因子的易操纵程度和操纵程度共同决定的。

PageRank无疑是颇难被操纵的一个排名因子了。但在它最初推出时针对的只是链接的数量,所以被一些网站管理员钻了空子,利用链接工厂和访客簿等大量低劣外部链接轻而易举地达到了自己的目的。Google意识到这个问题后,便在系统中整合了对链接的质量分析,并对发现的作弊网站进行封杀,从而不但有效地打击了这种做法,而且保证了结果的相关性和精准度。

五:Google的前1,000项搜索结果
一般说来,网站排名因素包括网页标题(META TITLE),网页正文中的关键词密度,锚文本(也叫链接文本,指链接或超链的文本内容)和PageRank所决定的。

请记住:单靠PageRank是无法使你获得比较理想的网站排名的。PageRank只是网站排名算法中的一个乘积因子,若你网站的其它排名因子的得分是零,就算你的PageRank是两百亿,最后的得分还是零。但这并不是说PageRank就毫无价值,而是在什么情况下PageRank才能完全发挥其功力。

如果在Google上进行广泛搜索,看起来好象有几千个结果,但实际显示最多前1,000项结果。例如对“car rental”,显示搜索结果为5,110,000,但实际显示结果只有826个。而且用时只有0.81秒。试想一下,0.84秒的时间就可以计算这五百万搜索结果的每个排名因子得分,然后给出最终我们所看到的网站排名结果吗?
答案就在于:搜索引擎选取与查询条件最相关的那些网页形成一个子集来加速搜索的速度。例如:假设子集中包含2,000个元素,搜索引擎所做的就是使用排名因子中的两到三个因素对整个数据库进行查询,找到针对这两三个排名因子得分较高的前2,000个网页。(请记住,虽然可能有五百多万搜索结果,但最终实际显示的1,000项搜索结果却是从这个2,000页的子集中提炼出来的。) 然后搜索引擎再把所有排名因子整合进这2,000项搜索结果组成的子集中并进行相应的网站排名。由于按相性进行排序,子集中越靠后的搜索结果(不是指网页)相关性(质量)也就越低,所以搜索引擎只向用户显示与查询条件最相关的前1,000项搜索结果。

请注意,在搜索引擎生成这2,000项网页的子集中我们强调了“相关性”这个词。即搜索引擎找寻的是与查询条件有共同主题的网页。如果这时候我们把PageRank考虑进去,就很可能得到一些PageRank很高但主题只是略微相关的一些搜索结果。显然这有违搜索引擎为用户提供最为相关和精准的搜索结果的原则。

一旦理解了为什么会如此,就说明了为什么你应当首先努力在“页面”因子和锚文本上下足工夫,最后才是PageRank。所以关键在于:

你必须首先在页面因素和/或锚文本上下足工夫,使这些排名因子能够获得足够的得分,从而使你的网站能够按目标关键词跻身于这2,000项搜索结果的子集中,否则PageRank再高也与事无补。

六:PageRank和其它排名因子之间的不同

网页Title标识 仅能被列出一次。
正文中的关键词 连续的重复只会降低关键词的重要性,重要的是接近度。
锚文本 加权值极高,但存在上限,超过上限的锚文本信息将被忽略或降低权值。
PageRank 潜质无穷,没有上限的限制,但需要大量工作。
备注 其它排名因子都存在一个上限(阙值),超过上限部分其权值将降低或不再计分。PageRank则不存在此问题。

Google–PageRank(网页级别)技术解密(二)

7. 非PageRank因素阙值
8. 使用阙值推知两种排名策略的价值
9. PageRank的计算

七:非PageRank因子的上限阙值(Non-PageRank Factor Threshold)
除了PageRank外,其它排名因子都存在一个阙值,也叫临界值或差值。即当增长到一定值时,因子的重要性反而开始慢慢降低,则该值就是非PageRank因子的阙值。

设阙值为1,000,如果网页A和B是我们对某一查询条件的其中两个查询结果,且A的总分数(包括页面因子得分和PageRank得分)是900,B是500,则显然A会排在B的前面。但由于A和B的分数均低于我们上面假设的非PageRank因子阙值,因而在不改变PageRank的情况下,我们可以通过对B页进行精心的页面优化使页面因子分数得到提高来使其排名超过A。但如果A的总得分升至1,100分,则B若还只是一味优化页面因子是远远不够的。在这种情况下,提升PageRank就成为首要任务了。

一般说来,Google的查询结果页中既可能包含一些分数超过阙值的网页,也可能包含一些分数低于阙值的网页。所以:

为了提高竞争能力,必须在阙值范围内尽可能提高页面的搜索引擎排名得分,否则会降低页面的竞争力。“页面因子”是接近和达到阙值最迅捷的方式,它与PageRank的结合使用才是提升网站排名得分的最佳优化策略。

八:使用阙值推知两种排名策略的价值
阙值解释了搜索引擎商所遵循的原则和不同的实施途径,同时亦阐述了为什么会产生关于PageRank的一些误解。我们可以把这两种策略当成两个人A和B。

A认为“PageRank”并不重要。他们已有数年网页优化经验并知道如何完美地利用“页面因素”来达到优化的目的。他们亦理解基本的锚文本,但对PageRank得分毫不在意。结果如何呢?由于最大化地使用了“页面因子”,从而使A迅速达到“非PageRank因子的阙值”。所以通过精心选择关键词可使他们获得较好的网站排名。而且只要网站内容比较好,随着时间推移总会有排名高的站点链接,涓涓细流汇成河。A最后亦得到了PageRank得分,并籍此巩固了排名。

B认为“PageRank”十分重要。他掌握了很多关于提升PageRank得分的信息,并为提高该得分下足了工夫。结果又如何呢?B的做法和A相反,但A在非PageRank因子上下工夫,结果却得到了PageRank得分。而B在PageRank因子上下工夫,结果却得到非PageRank因子得分。究其原因,就是由于提高PageRank得分需要外部链接,链接又具有锚文本,从而通过精心挑选外部链接的锚文本,B自发提高了其非PageRank因子的得分,从而赢得了较高的PageRank得分。

虽然这只是两个极端,但我们可以利用它们来推知这两种途径各自的优缺点:

对象
优点
缺点
A:忽略PageRank
  • 网站排名在短期内就可得到提升
  • 自我生成链接节省了工作量
  • 需投入大量工作维持网站排名
  • 对新竞争者的应变速度较慢
  • B:忽略页面排名因子
  • 可获得可靠网站排名,并可在需要时轻松修改页面因素使排名迅速提升
  • 极可能从非搜索类引擎来源上获得更高访问量
  • 网站排名提升较慢
  • 操作难度较大
  • 容易为SPAM过滤程序所制
  • 对象 优点 缺点
    A:忽略PageRank 网站排名在短期内就可得到提升

    自我生成链接节省了工作量
    需投入大量工作维持网站排名

    对新竞争者的应变速度较慢

    B:忽略页面排名因子 可获得可靠网站排名,并可在需要时轻松修改页面因素使排名迅速提升

    极可能从非搜索类引擎来源上获得更高访问量
    网站排名提升较慢

    操作难度较大

    容易为SPAM过滤程序所制

    事实上,我们前面说过,最终排名得分=所有非PageRank因子实际得分x实际PageRank得分。亦即二者相辅相成,再加上随着网上营销方式的发展壮大,关键词的竞争也变的愈来愈激烈,这种情况下只靠非PageRank因子得到好排名显然是不可能的。而且非PageRank因子存在着阙值的局限性。同时,对于竞争性极高的关键词,还存在着PageRank下限的问题。也就是说,除非网站的PageRank得分超过这个下限标准,否则网站排名很难上去。PageRank的下限由关键词的竞争度所决定。竞争性一般的关键词PageRank下限也不高,而对竞争较为激烈的关键词来说,它所要求的PageRank下限相应就要高。而PageRank得分的提升又非常有难,这时候非PageRank因子就变的非常重要了。
    综上所述:我们需要充分发挥各排名因子的优势来赢取理想的综合排名得分。同时关键词(竞争度适宜)的精心选择亦变的非常重要,它可以节省大量的支出。

    九:PageRank的计算方法
      PageRank (A) = (1-d) + d(PageRank (T1)/C(T1) + … + PageRank (Tn)/C(Tn))
      其中PageRank (A)表示给定页面A的PageRank得分;
      D为阻尼因子,一般设为0.85;
      PageRank (T1)表示一个指向A页的网站其本身的PageRank得分;
      C(T1)表示该页面所拥有的导出链接数量;
      PageRank (Tn)/C(Tn)表示为每一个指向A页的页面重复相同的操作步骤。

     

    事实上,计算某个页面的PageRank得分需要大量繁复计算。例如若计算A页的PageRank得分则首先要知道所有链至A页的网页(导入链接)的PageRank得分。要想知道这些外部链接页的PageRank得分,又需要先知道这些页面的外部链接的PageRank得分,等等。我们只需要知道:

    A页的外部链接B能够带给A的PageRank得分与B的导出链接数量成反比,即随着B上导出链接数的增加,带给A的PageRank得分亦随之降低。这同样表明了一个网页的PageRank得分是该网页对其它页面投票的一个基本的度量形式。一个网页可以投票给一个或多个导出链接,但其总投票权一定,并被平均分配给所有的导出链接。假设B的PageRank得分是5,且B上只有一条指向A的链接,那么A将获得B全部的PageRank得分(B没有损失任何东西,而A赢得了B的PageRank得分)。但如果B上有N个链接,则A只能得到B的PageRank得分的N分之一。

    我们可以用图表来阐述其工作原理。假设有四个网页A,B,C和D,它们相互链接,如表-1所示:

    表-1:链接前的PageRank得分

    表-2:链接后的PageRank得分

    假设这四个网页初始PageRank得分均为0。则根据上面的公式它们的PageRank得分都是0.15。我们计算一下链接后各自的PageRank得分情况。
    1.A链向B、C和D。A的初始PageRank得分是0.15,所以A的导出链接获得PageRank得分总数为 0.85 * 0.15 = 0.1275。B,C和D三个网页各得0.0425分。
    2.B链向C、B的初始PageRank得分也是0.15,所以其唯一链接页面C所能够获得的PageRank得分是0.85 * 0.15 = 0.1275分。
      C链向A,其0.1275的PageRank得分传递给唯一链接对象A。
      D链向C,其0.1275的PageRank得分传递给了C。
      现在各网页的PageRank得分结果如下:
      A:0.15 + 0.1275 (得自C) = 0.2775
      B:0.15 + 0.0425 (得自A) = 0.1925
      C:0.15 + 0.0425 (得自A) + 0.1275 (得自B) + 0.1275 (得自D) = 0.4475
      D:0.15 + 0.0425 (得自A) = 0.1925(如表-2所示)
    继续这样的计算,直到每个页面的数值逼近一个定值(PageRank属收敛函数)。最后可以发现,C的PageRank最高。而且外部链接的数量显著地改变了PageRank得的分布。

    表-3:最后的PageRank得分结果

    表-4:外部链接与PageRank得分对照表:

     
    导入链接
    数量
    导出链接
    数量
    最终PageRank得分
    C
    A/B/D
    3
    A
    1
    1.4860614724
    A
    C
    1
    B/C/D
    3
    1.4131522515
    B
    A
    1
    C
    1 0.5503931379
    D
    A
    1
    C
    1 0.5503931379

    十:PageRank的反馈性[出自chinaseo]
      
    PageRank的反馈机制说明了为什么一个网站的导出链接能够使网站自身受益。
    假设A页链向B,根据PageRank计算公式,其初始PageRank为0.15,链接后的PageRank变为1。如果A链向C,而C又链回A,则A此时的PageRank变成了1.4594594595。也就是说若A链向一个外部网页,而那个网页又回链向A的话,则使A的PageRank会增加。(如果A链向一个网页,而该网页又链向C,C再链向A的话,也会发生同样的情形)。如果把所有相互链接的页面看做是一个系统整体的话,其实链接前后系统总的PageRank并没有发生改变,只是由于不同链接关系的发生导致了PageRank对系统内每个链接页面的重新分布。

    表-6-1:无链接交换时:A到E页都是已被Google收录的页面。其中A和B是我们网站的内页

    表-7 未提供导出链接前 提供导出链接后
    A的PageRank得分: 1 1.3599321536
    B的PageRank得分: 1 0.7279711653
    网站的PageRank总分: 2 2.0879033189

    其增量比较小,整体则视情况而定。但有一点是显而易见的 – 提供导出链接的网页往往会通过一种叫做PageRank反馈的机制提升了自身的PageRank。

    结论:
    这表明和一些大型站点进行互惠链接交换是比较明智的。这些大网站均采用链接结构,并对链接页给予高度关注。你所链接的对象站点所包含的网页数量及其设计结构对于你网站的PageRank反馈总数有着显著的影响。

    十一:如何控制PageRank
    虽然PageRank因子很难控制,但我们可以通过其它技术来得到理想的结果。而且,良好优化过的页面因子整合较高的PageRank得分无疑会使网站更具竞争力。

    PageRank因子的优化可从下面三个方面着手:
      1. 导入链接。包括如何选取导入链接,获得导入链接所付出的努力是与收获呈正比的。
      2. 导出链接。包括导出链接的选取及它们在你网站上的合适位置,应使PageRank得到最大回馈(Feedback) 和最小损耗(Leakage)。
      3. 网站内部导航结构和内部页面的联接。实现PageRank在网站内部的良好分布。

    十二:导入链接(Links to Your Site)
    寻找导入链接时,一般总是容易陷入这样的误区:只看链接页的PageRank得分,得分越高就越好。而事实上,一个链接页的PageRank得分遵循平均分配原则被平均分配给该页面上的所有链接。所以,只注重外部链接的PageRank得分的链接策略无疑是片面的。正确的做法应该是既要考虑链接页的PageRank,又要考虑该页的链接数量(应注意:PageRank的单位是网页而不是网站,即每个页面都有其特定的PageRank。所以在寻找链接时应查看“链接”页面的PageRank,也就是说,需要考虑的是放置你网站链接的那个页面的PageRank得分情况。) 而且PageRank较高的站点对链接请求一般总是比较挑剔的。

    结论:
      那些看起来较为适宜,具有良好质量的网站都是理想的链接对象。先别去管它们的PageRank到底是多少,倘若它们既与你的网站相关,又具有较高的质量,那么总是会有益你的PageRank,只是个时间问题罢了。另外,网站被DMOZ和Yahoo收录亦能相当有效地提升PageRank。

    十三:导出链接(Links out of your site)
    导出链接并不会损失PageRank,但网站整体的PageRank将会降低。所以,选择导出链接时宜遵循这样的定律:
      1. 尽量保持自己网站的PageRank
      2. 尽量使内部页面分得尽可能多的PageRank

    向大家推荐一种方法:可以在网站上设立一个对导出链接的“评审”页。用于放置对外部链接站点的评审内容。每条评审内容应包括指向其相应外部站点的超链。(注意:由于搜索引擎的SPIDERS无法支持JAVASCRIPT,所以不宜用JAVA程序打开这些页面。)

    “评审”页应链回网站内部等级较高的一个页面 (最好是主页,其它重量级页也可)。这样做可显著降低网站PageRank的流失。放置外部链接的页面亦需链回主页及其它重要内部页面。但“评审”页上只要放置一个重量级内部页面即可(最好是主页)。此外,可以告诉你的”评审“链接对象你已经”评审“过他们的网站,这样一来他们很有可能会把你的这个”评审“页链接到他们自己的网站上,这样就可以从他们那里得到两个导入链接。自然效果就更好了。用文字描述太麻烦了,我们还是用图表来说明吧。(下表包括主页A,外部链接页页D和其它两个内页B和C)

    如果进行相同的计算,但包括review pages,则结果如下:
    表-9:加“评审”页后的各网页PageRank得分情况

    如果只看A,B,C和D页,则结果如下:

    无评审(Review)页 有评审(Review)页
    主页的PageRank: 0.9536152797 2.439718935
    B/C/D页的PageRank: 0.4201909959
    0.4201909959
    0.4201909959
    0.8412536982
    0.8412536982
    0.8412536982
    PageRank总计: 2.2141882674 4.9634800296

    在放置导出链接的页面上同时放一些网站的内部链接是提高PageRank的相当重要的内部因素之一。这种收益虽然无法和网站所从导入链接上获得的收益相提并论,但却极易操作,并可有益于网站读者。

    十四:网站的内部结构和联接

    一:网站的内部页面
    说完了“外部链接”,现在让我们来看看“内部链接”。如果PageRank确由页面投票的质量和数量所决定,那么我们立即就可以得出网站内链与PageRank的关系的一个重要结论:

    网站上每个已被Google收录的内部网页(内链)都是对该网站的一记投票,不过投票份量很小。因而,一个网站若能拥有更多已被Google收录的内部网页,就有可能获得更多的总投票。

    这样一来,我们可以通过创建大量内部网页来提高网站整体的PageRank。但这还远远不够。因为我们此处所指的内部网页是指已被Google收录,即拥有自己的PageRank的那些内链页面。这些网页之所以被Google检索是由于它们具备丰富充实的内容。所以应尽力充实和丰富你的网站,一旦网站内容得到充实和丰富,会有更多的内页得到检索,从而带来更多的PageRank。同时“升值”的网站也会获得更多站点的青睐,从而会有更多的站点主动链接你。

    简言之,就提升PageRank而言,对“内”最需要做的就是为网站填充更加丰富和有价值的内容。应确保网页内容不会过长或过短,如有必要可将网页内容分割成若干网页。

    二:网站的内部结构&联接
    网站有三种内部联方式,宜结合使用这三种联接方式进行网站的建设。假设一个网站由“主页”,“关于我们”页,“产品介绍”页和“更多信息”页这四个页面组成,通过下表我们可以看出每种结构对网站PageRank的影响度。

    表-11:层级结构(Hierarchical)

    表-12:环路网站结构(Looping)

    表-13:内页广泛互联的网站结构(Extensive Interlinking)

    表14-16是内部页面在不同结构网站上的PageRank分布情况。了解了这一点我们就可以从“内部链接”着手来获得最大的PageRank反馈。

     

    表-14:层级结构的PageRank分布(总PageRank=4)

    表-15: 环路结构的PageRank分布(总PageRank=4)

    表-16:内页广泛互联结构的PageRank分布(总PageRank=4)

    在未考虑外部链接因素的前提下,可以看出类层级结构(Hierarchical-Like)能够改变网站内部页面的PageRank分布。(注意:我们所指的并不一定是严格意义上的层级结构,不过必须比环路结构(Looping)或广泛互联(Extensive Interlinking)结构包含更多层级结构的属性。)

    若PageRank均匀分布于网站内部页中,那么网站管理员可以通过层级结构这种能够使PageRank发生转移的性能来有选择地转移内部网页的PageRank:即把一些不太重要的页面的PageRank适当地转移到那些关键词竞争性比较强的网页上,或想提高特定关键词排名的网页上去,从而使网站获得最大的收益。

    上面只是封闭网站设计结构(即无导入也无导出链接的结构)下内部各网页的分布情况,如果加入外部链接–即导入和导出链接后情况又会怎样呢?如表17-19所示:

    表-17:非封闭层级网站结构的PageRank分布

    表-18:非封闭环路网站结构的PageRank分布

    表-19:非封闭内页广泛互联网站结构的PageRank分布

      无导入/导出链接PageRank分布 有无导入/导出链接PageRank分布
    网站结构 主页的PR 其它各页的PR PR总数 主页PR 其它各页PR PR总数
    层级 1.9189189189 0.6936936937
    0.6936936937
    0.6936936937
    4 1.49842 0.57455
    0.57455
    0.57455
    3.222094
    环路 1 1
    1
    1
    4 0.68369 0.73113
    0.47787
    0.77146
    2.664173
    广泛互联 1 1
    1
    1
    4 0.95411 0.85476
    0.85476
    0.90469
    3.568342
    结论: 内页广泛互联(Extensive Interlinking)的网站结构(表13)可以最大程度地保留一个网站内部的PageRank,其次是层级(Hierarchical)结构(表11),最后才是环路(Looping)的网站结构(表12)。
    注意: 理论上是这样,但实际上如果让上万个内部网页互联起来又不太可能。所以还必须为网站各分枝选择合适的结构。不过对层级结构来说,越是增加子页数量效果越好。这是由于在导出链接页上增加了更多内部链接,按照PageRank平均分配给所有内/外链接的原则,受益最多的还是你。不过,如果增加太多内页,也会明显影响主页的PageRank。

    十五:Google如是说
    关于PageRank,最权威的发言人自然还是Google。虽然Google不会也不可能提供相关的技术信息,但我们亦可从中窥得一斑
    Chris:PageRank的命名是基于“Page”,还是和某个创始人有关?
    Google:PageRank是以Google的联合创始人兼总裁Larry Page的名字命名的。
    Chris:Google是否把PageRank视做显著区别于其它搜索引擎的一个特性?
    Google:PageRank是一种能够使Google在搜索速度和搜索结果的相关性上区别于其它搜索引擎的技术。不唯如此,在排名公式中Google还使用了100种其它的算法。
    Chris:Google是否认为引入PageRank可以显著提高搜索结果的质量?以后是否仍将继续使用PageRank?
    Google:由于PageRank使用了量化方法来分析链接,所以它仍将是决定Google搜索结果页排名的一个重要因素。
    Chris:您认为Google工具栏上的PageRank的信息对普通用户/网站管理员/搜索引擎优化专家来说各有什么意义?
    Google:Google工具栏上所提供的PageRank信息仅作为一种网站评估信息使用。用户们会觉得它很有趣,网站管理员一般用它来衡量网站性能。不过,由于PageRank只是一个大体评估,所以对搜索引擎专家的价值并不大。
    Chris:常有网站试图通过“链接工厂”和访客簿的手段达到提升PageRank的目的。对这样的网站Google有什么举措?
    Google:Google的工程师会经常更新Google的排名算法以防止对Google排名的恶意操纵。

    结束语:
    选择导入链接时应首先考虑对方网站的内容如何,然后再考察其导出链接的数量进行决策。而在建立本站的导出链接时则应尽量使自己网站的PageRank维持在最大回馈和最小流失上。

    应确保合理的网站设计结构和内部联接方式。网站的结构和内部联接方式也会对PageRank产生影响,可利用其特性有效进行PagaRank在网站内部页面的再分布及尽可能保持网站整体的PageRank。

    网站的PageRank的提升应与该网站的访问者体验息息相关。即使获得再高的PageRank,如果没有客户访问,一样毫无价值。所以网站的内容始终是提升PageRank最关键的因素之一