IT计算机基于Lucene的桌面搜索引擎.doc
目录目录1摘要3Abstract41 前言51.1 什么是全文检索与全文检索系统51.2 使用Lucene能做什么61.3 本课题研究的意义62 Lucene搜索引擎的分析与研究62.1 Lucene分析器Analyzer72.1.1 Analyzer的概述72.1.2 Lucene内建的分析器72.2 索引建立的过程82.2.1 提取文本82.2.2 构建Document92.2.3 分析并建立索引92.3 Lucene的文档格式92.3.1 文档(Document)92.3.2 字段(Field)102.4 索引的添加IndexWriter类122.4.1 初始化122.4.2 向索引添加文档122.5 Lucene的索引文件格式简述122.5.1 索引的存放位置132.5.2 Lucene的索引优化132.6 搜索的流程132.6.1 初始化Lucene的检索工具IndexSearcher132.6.2 构建Query142.6.3 搜索并处理返回结果142.7 搜索与结果142.7.1 检索工具IndexSearcher类142.7.2 检索结果Hits152.8 Lucene的评分机制152.8.1 理解评分的概念152.8.2 Lucene评分算法162.9 倒排索引163 lucene搜索引擎的中文分词问题173.1 Lucene 中文分词算法选择173.2 词典构造183.3 具体实现194 lucene桌面全文搜索引擎系统的分析与设计214.1 桌面搜索引擎系统的功能介绍214.2 lucene桌面搜索引擎系统使用的技术214.3 lucene桌面搜索引擎系统分析214.4 lucene桌面全文搜索引擎系统的设计234.4.1 创建windows窗体应用程序234.5 为本机的文件创建索引244.5.1 选择要建立索引的目录和索引存放的位置244.5.2 建立索引244.6 搜索的效果274.6.1 运行搜索275 总结31致谢31参考资料31基于lucene的桌面全文搜索引擎研究学 生: 杨刚指导教师: 钱涛咸宁学院 计算机科学与技术学院 湖北 咸宁 437100摘要Lucene是一个用Java/C#写的全文搜索引擎工具包,支持多用户访问,访问索引速度快,可以跨平台使用.全文检索技术是信息检索领域广泛使用的基本技术.它是一个优秀的开源全文本搜索技术框架.按照Lucene的框架规范,扩展Lucene的功能,可以将Lucene很好地嵌入到自己的搜索引擎中.本文研究了Lucene的中文切分词技术,Lucene的索引原理, 根据 Lucene的系统结构详细分析了Lucene分析器、索引包、文档等结构, 描述了利用Lucene开发定制的中文全文搜索引擎的方法,实现了一个基于Lucene的桌面搜索应用实例.关键词: Lucene 全文检索技术 搜索引擎 索引 中文分词Desktop search engine based on luceneStudent: Yang GangSupervisor: Tao QianSchool of computer Science & Technology, Xianning College,Xianning Hubei, 437000AbstractLucene is a full text using Java/C# to write search engine toolkit , which supports multiaccess , visits index speed quickly ,and can stride over platform usage. The full text search technology is the fundamental technology that the information retrieval field uses broadly. It is that one is excellent hold source full text searching for the technology frame originally. According to the Lucene frame norm , the function expanding Lucene's, in the search engine being able to Lucene be implanted very good to self。Unwieldy culture has studied the Lucene Chinese segments the word technology , the Lucene index principle , the system structure according to Lucene has analysed the Lucene analyzer , index structure such as bag , document detailedly , has described search engine method making use of Lucene to develop custom-built Chinese full text , has realized a example applying owing to that the Lucene full text searches for.Key words: Lucene,Full text Search technology, Search engine, Index, Segment word1 前言Lucene开始是作为个人项目。1997年,Lucene的作者Doug Cutting编写了Lucene。几年以后,2000年,他将Lucene放到了自己的网站上。一些人马上开始使用Lucene。2001年,Apache的人提出采用Lucene。Lucene的代码捐助也慢慢开始了,Lucene开始成为真正的合作项目。到2004年,Lucene已经有了一个强有力的开发团队。这些年来,Lucene已经被翻译为其它多种语言版本,包括C+,C#,Perl和Python。在最初的Java以及其它各版本中,Lucene的应用相当广泛。它在各种应用中为搜索提供动力,如财富100的讨论组、商业的Bug跟踪、微软提供的邮件搜索还有数十亿页面级的 WEB搜索引擎。越来越多的人开始使用Lucene。下面我将更详细的介绍Lucene,并用它来构建一个自己的搜索引擎。1.1 什么是全文检索与全文检索系统全文检索是指计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当我们查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给我们的检索方式。这个过程类似于通过字典中的检索字表查字的过程。全文检索的方法主要分为按字检索和按词检索两种。按字检索是指对于文章中的每一个字都建立索引,检索时将词分解为字的组合。对于各种不同的语言而言,字有不同的含义,比如英文中字与词实际上是合一的,而中文中字与词有很大分别。按词检索指对文章中的词,即语义单位建立索引,检索时按词检索,并且可以处理同义项等。英文等西方文字由于按照空白切分词,因此实现上与按字处理类似,添加同义处理也很容易。中文文字则需要切分字词,以达到按词索引的目的,关于这方面的问题,是当前全文检索技术尤其是中文全文检索技术中的难点,在此不做详述。全文检索系统是按照全文检索理论建立起来的用于提供全文检索服务的软件系统。一般来说,全文检索需要具备建立索引和提供查询的基本功能,此外现代的全文检索系统还需要具有方便的用户接口、面向WWW的开发接口、二次应用开发接口等。功能上,全文检索系统具有建立索引、处理查询返回结果集、增加索引、优化索引结构等功能,外围则由各种不同应用具有的功能组成。结构上,全文检索系统具有索引引擎、查询引擎、文本分析引擎、对外接口等,加上各种外围应用系统共同构成了全文检索系统。 图1.1 全文检索系统结构1.2 使用Lucene能做什么Lucene可以对任何的数据做索引和搜索。Lucene不管数据源是什么格式,只要它能被转化为文字的形式,就可以被Lucene所分析利用。也就是说不管是Word、Html、PDF还是其他什么形式的文件只要你可以从中抽取出文字形式的内容就可以被Lucene所用,就可以用Lucene对它们进行索引以及搜索。1.3 本课题研究的意义本课题研究在于用户对本机硬盘的搜索。由于技术的进步,硬盘容量越来越大,用户在寻找某个急需的文件时难免会花费大量时间在上面,作为桌面搜索引擎,可以很好的帮用户解决这一问题。对于普通用户来说,桌面搜索系统可以对本地硬盘上大量的文本数据进行筛选,获得文件的位置信息并可打开文件进行操作,给普通用户带来极大的方便。另外用户可以将感兴趣的站点进行下载分析,选择含有关键字的网页浏览。对于计算机相关人员尤其是网站维护管理人员来说,可以在收集的资源中快速找到需要的信息发布到网站上,另外在无版权问题时,可下载网页资源进行分析找到所需的信息,然后摘录到自己的网站上。2 Lucene搜索引擎的分析与研究建立索引是使用搜索引擎功能的第一步。关于Lucene建立索引的这一部分内容比较多,从索引的建立到索引的优化, 索引的同步机制都是非常重要的内容,而且Lucene索引这部分内容与Lucene的搜索模块也是密切相关的。除了检索这个必不可少的步骤外,搜索也是非常重要的一步。只有能够搜索到用户需要的内容,才算是一个好的搜索引擎。在建立索引和检索过程中,分析是很重要的一个环节。Lucene使用分析器(Analyzer)来对各种各样的输入进行分析,可以说Analyzer在Lucene开发包中占有举足轻重的地位,它的运行性能和分析能力直接影响到搜索引擎的许多环节。2.1 Lucene分析器Analyzer2.1.1 Analyzer的概述Analyzer中文可以翻译成“分析器”,是Lucene中内置的一种工具。它主要用于分析搜索引擎遇到的各种文本。所谓分析,用更具体的话说其实就是“分词”和“过滤”。从图4-1中可以看出,分析器位于索引和文本资源之间,这样所有进入索引库的文本资源都应当经过分析器的分析,以此来控制索引中的内容。未经过分析器分析的文本如果直接进入索引,可能会引起各种各样数据的一致性问题,同时会降底索引的效率,进而影响整个搜索引擎的性能。正如前面所述,在Lucene中,一个分析器主要包括分词器和过滤器两种组件。分词器就是用于对文本资源进行切分,将文本按规则切分为一个个可以进入索引的最小单位。而过滤器的功能则是对这种最小单位进行预处理,比如大写转小写,复数转单数等。这种操作可以简单(如最简单的大写转小写),也可以相当复杂(如根据语义改写拼写错误的单词)。 图2.1 分析器的位置2.1.2 Lucene内建的分析器Lucene提供了几种不同环境和需求下使用的Analyzer,最常用的如StandardAnalyzer,另外还有SimpleAnalyzer,WhitespaceAnalyzer,GermanAnalyzer等,这些都是被统一称为是Lucene内置的Analyzer。这其中的每一种Analyzer都有它自己独特的功能和用途,因此在使用时可根据不同的需要选择适合的Analyzer。2.2 索引建立的过程在Lucene所公开的API中,仅有为数不多的方法可以在建立索引时使用。从这一方面来看,大大简化了使用Lucene建立索引的过程,提高了Lucene的易用性;从另一方面来看,在简单的API的背后,隐藏着更为复杂的操作,并且只有熟悉并掌握了这些更为复杂的操作过程,才能更加灵活地使用Lucene建立索引,逐步成为以为使用Lucene的高手。从整体来看,Lucene建立索引的过程有以下4步:提取文本;构建Document;分析;建立索引。2.2.1 提取文本为了使用Lucene对文档数据建立索引,第一步就是要把这些需要建立索引的文档数据转换成Lucene可以处理的类型。在使用Lucene过程中不得不面对一些更为复杂的文档数据类型,如图4-2所示。 图2.2 面对多种文档类型的处理假设现在的任务是对一系列的PDF文档数据建立索引。首先为了使Lucene能够对这些文档数据建立索引,必须先想办法从这些PDF文档中提取出文本信息,并且使用这些提取出来的信息来构建Lucene中的Document和Field。同样,当我们在需要对Word文档或者其它任何类型的文档建立索引时也面临着类似的问题。2.2.2 构建Document构建Document是索引建立过程的第二步。有关Lucene Document的概念在后面会有详细说明,此处不再熬述。这一步的主要目的就是将前面所提取出来的文本组装成Lucene可以识别的格式来为索引的建立做准备。2.2.3 分析并建立索引在提取了需要Lucene建立索引的数据并且创建了Document之后,接下来就可以调用IndexWriter类的addDocument()方法来使Lucene建立索引了。在这样的调用中,Lucene会首先对所要建立索引的数据进行分析(analysis)以使得在建立索引时可以更加容易地处理这些数据,然后索引器会按Lucene所规定的索引格式将数据写入索引文件。2.3 Lucene的文档格式在前面已经提到了两个概念:Document(文档)和Field(字段)。Document和Field在Lucene的索引过程中占有举足轻重的地位,而且,在Lucene的搜索部分也会涉及到相应的概念,因此可以说深入理解它们是使用Lucene的基础,下面将分别进行介绍。2.3.1 文档(Document)假设现在要对一些文本文件建立索引,首先需要确定索引的数据源。对文本文件来说,数据源可以是文件名,文件的内容,文件的最后修改时间等。对于每个不同的文件,这些数据源将提供出不同的内容,以便将来存储在索引中。在Lucene中,可以把一个Document看作是这些不同内容的集合,而“文件名”,“文件内容”等名称可以看成是对不同数据源进行分类的标记,在Lucene中我们把这些标记称为Field。从根本上来讲,Lucene的Document代表了一个需要进行索引的“单元”,任何需要进行索引的“文件”都必须被转化成Document对象才能够被索引和搜索到。需要注意的是,此处在“文件”二字上加了引号,这是因为并非只有文件才能转化为Document类型,任何数据源经过组织都可以构建一个Document类型。更进一步说,Lucene并不为任何实际物理文件建立索引,而只对Document对象建立索引。所以,建立索引的第一步就是将不同的数据源组织为一个Document类型的对象。其实,可以把Document对象看成一种虚拟的文件,它自身带有多个数据源。从文件能够提供数据源这个角度上来看,Document对象与实际的物理文件基本相似,不同之处仅仅在于Lucene无法识别普通的物理文件而能识别一个Document类型的对象而已。假设现在需要对一个网页执行建立索引的操作,以便在将来可以搜索到这个网页的相关内容,那么我们就需要先把这个网页转换成一个Document对象。经过分析可以知道,该网页主要有几个属性(也就是数据源)可能在将来检索时会用到,分别是网页的标题,网页的URL,网页的内容和网页的最后修改时间。因此,在为这网页构建Document对象时就应当包含这几个不同的Field。Document的基本使用方法:在document()方法中首先构造了一个Document类型的实例,然后依次往Document对象中添加了path,modified和contents 3个Field,这些Field在以后搜索时都将用到,最后返回生成的Document类型的对象doc。在对Document添加Field时,使用的是Document对象的add(Field fld)方法,例如,在添加path信息到doc对象中时,先通过f.getpath()方法获取到了文件的路径,再用Field类自带的静态方法构造出一个Field实例,然后将其传给add方法以完成添加。2.3.2 字段(Field)正如前面所述,字段(Field)是与文档(Document)紧密相连的一个概念,在一个Document中,它代表了不同数据源的名称。然而,在现实中,数据源所提供的数据并不是以一种一成不变的方式进行处理,对于不同的字段,人们所希望处理的方式并不相同。对于每个Field,Lucene提供了3种方式以供用户选择进行处理,这3种方式分别是被称为“是否切词”,“是否索引”和“是否存储“。从意义上我们并不难理解这3种方式。a.“是否切词”表示在这个Field中的数据是否需要被切词。b.“是否索引”表示在这个Field中的数据是否在将来检索时需要被我们检索到,一个“不索引”的Field通常仅提供辅助信息储存的功能。c.“是否存储”则表示该Field内的信息是否要被原封不动的保存在索引中。Lucene的Field类提供的构造方法支持用户构造不同类型的Field,但更为常见的是使用Field类所提供的静态方法来构造所需要的字段。在Field中,通过静态方法定义了4种不同类型的字段Text、Keyword、UnIndexed和UnStored可供使用,这4种字段在是否切词、是否索引以及是否存储等方面都有所不同,因此四种字段各有不同的用途。下面是详细介绍:(1) TextText类型的字段代表一段需要被切词和索引的内容,这也就说明了这种类型的字段可被搜索。但是,对于这个字段的大小一定要格外小心,因为Text类型的字段有两个不同的构造函数:Field. Text(String, String)和Field. Text(String, Reader)。如果被索引的字段是java中的String类型,那么它不仅会被索引,同时也会被存储起来,但如果是由java里面的Reader类型来为该字段提供数据源,那么它就会被索引,而不会被存储起来了。这一点在使用中往往引起一些混淆,因此在使用Text类型的字段时一定要注意这些区别。通常,Field. Text(String,Reader)用在从某个文本流数据源中获取数据,数据量一般会比较大,而在将来用户可能并不需要重现它的内容,仅是希望对其中的内容做全文检索,所以不需要去存储数据源的内容。但是希望存储数据源的内容,则只能先将其中的内容取出来保存在一个String中,再使用Field. Text(String, String)来构建需要的字段。(2) KeywordKeyword(关键字)类型的字段不会被切词,但是会被索引并且完整的存储在索引中。这种类型的字段适合于连接地址URLs、文件系统路径信息、时间日期、人名、居民身份证号码,电话号码等。例如,需要存储一个文件的路径名信息,因为文件的路径名信息是不需要切分词的(而且切分词后反而失去了其意义),但是文件的路径名信息是需要索引和存储的,因此就可以把文件的路径名信息存储到Keyword类型的字段中。通常情况下,可以通过Field. Keyword(String fieldname, String Keyword)或Field. Keyword(String fieldname, Data data)(专门针对日期型的关键字)这两个静态方法来构造Keyword类型的字段。(3) UnIndexedUnIndexed类型的字段既不会被切词,也不会被索引,但是它的值还是会原封不动的存储在索引中。在Field中使用Field. UnIndexed(String, String)静态方法来构建这种类型的字段。这种类型适合于处理需要和搜索结果显示在一起的内容,比如说在一个网页建立索引时可以将这个网页的URL引用地址添加到UnIndexed类型的字段中。这样在搜索到与这个网页相关的内容时,就可以将这个引用地址与搜索结果一起显示出来。(4) UnStoredField中通过Field. UnStored(String, String)方法来构造一个UnStored类型的字段。UnStored类型的字段与UnIndexed类型的字段刚好相反,它会被切词也会被索引,但是并不会被存储在索引中。这种字段适合于索引那些并不需要以原有的形式来重视原始数据的大规模文本,比如网页的主体部分或者是内容庞大的文本文档。在表2.1中对不同类型的字段进行了比较,表格中包含各个字段的特性以及通常使用的例子。字段类型/方法是否被分词是否被索引是否被存储用途Field. Keyword(String name, String value)Field. Keyword(String, Data)否是是电话号码、居民身份证号码、人名、地名、日期Field. UnIndexed(String, String)否否是文档的类型,例如:Word、PDF、HtmlField. UnStored(String, String)是是否文档的标题和内容Field. Text(String, String)是是文档的标题和内容Field. Text(String, Reader)是是否文档的内容表2.1 不同字段类型比较、特性以及用途当使用Field类所提供的静态方法来构造不同的字段时,所有的字段类型都有两个构造参数,分别代表字段名和值,也就是我们在前面提到的“键/值”对。另外,正如表格中所列举的,Keyword类型的字段除了可以接受String类型的参数作为字段值外,还可以接受Data类型的参数作为字段值,而Text类型的字段也可以接受String类型或者Data类型参数作为字段值。假设现在需要对一个网页建立索引,该网页已经被封装为一个Page类型的对象。我们可以从这个Page类型的对象中得到的信息包括:网页的标题、网页的创建时间、网页的URL地址和网页的内容信息。Lucene的索引部分是为Lucene的搜索部分服务的,因此与Lucene的搜索部分密切相关,所以在建立索引时就应该考虑到搜索时的操作,这样才能够建立起恰当的索引字段类型。而且关于Lucene字段类型的使用也并没有统一的法则,每个人对如何使用各个字段类型都会有不同的理解,所以要深刻理解并能够灵活应用各个字段类型还需要在实际使用中逐渐积累经验。2.4 索引的添加IndexWriter类IndexWriter类是Lucene中最重要的类之一,它的功能就是将文档加入索引,同时控制索引过程中的各种参数。2.4.1 初始化IndexWriter类的初始化过程并不复杂,它本身提供了多种构造函数。可以很方便地构造一个IndexWriter的对象。通常情况下,IndexWriter的构造函数包括了以下3个参数。a.索引存放的路径IndexWriter需要知道它要把索引创建在什么地方,因此,索引存放的路径也就必不可少。这个路径可以是一个String型的目录位置,也可以是经过封装的.Index对象,同时,还可以是Lucene自带的Directory类型的对象。b.分析器前面说过,建立索引前首先要对文本进行分析。因此,一个合适的分析器也就必不可少了。IndexWriter的构造函数中不可缺少的一项就是一个继承字Analyzer类的分析器。它的主要功能是在IndexWriter将文档写入索引前,把文本信息切分成一个个可以进行索引的词条。c.是否重新建立索引IndexWriter在建立索引时,需要知道是重新建立索引,还是进行增量的索引。通过指定一个布尔型的值,就可以完成这一任务。当该布尔型的值为ture时,IndexWriter不管目录内是否已经有索引了,一律清空,重新建立;而当布尔型的值为false时,则IndexWriter会在原有基础上增量添加索引。2.4.2 向索引添加文档在前面已经了解了Lucene中的Document和Field的概念,同时,也知道了Lucene是借助与IndexWriter的帮助来向索引中添加数据的。接下来,就来看看IndexWriter四如何把一个个Document对象加入索引中的。首先创建Document对象,并分别为每个对象创建字段。然后,初始化一个IndexWriter的对象,并确定一个目录作为索引的存放目录,同时使用StandardAnalyzer作为其默认的分析器,并且设置IndexWriter清除原目录内的所有已有索引重新建立。接下来,调用IndexWriter的addDocument方法来向索引中添加文档。向索引中添加文档相当方便,只需要重复使用IndexWriter的addDocument方法就可以完成一切建立索引的过程。需要特别注意的是,当执行完addDocument方法后,千万不能忘记调用IndexWriter的close方法来关闭它。因此会发现索引目录内除了一个Segment文件外什么都没有。只有在调用了close方法后,索引器才会将存放于内存中的所有内容写入磁盘并关闭输出流。2.5 Lucene的索引文件格式简述Lucene的索引有其固定的格式,下面就简单的进行介绍。段(Segment)Segment是Lucene索引文件中最基本的一个单位。一个Segment是一个独立的索引,可以由IndexSearcher进行单独的查找。Lucene的工作其实就是不停地往磁盘中加入新的Segment,然后再按一定的算法合并不同的Segment以创建一个新的段。在每个目录下都有一个“Segments”文件,该文件在每个目录中有且仅有一个,而且它的文件名只能为“Segments”。它中间保存了该目录内相关的段信息,比如有多少个Segment,每个Segment有多大等。每个Segment的所有相关文件都有相同的前缀,这个前缀通常是用三十六进制表示的索引中包含文档的数量。2.5.1 索引的存放位置 Lucene提供了两种索引存放的位置,一种是磁盘,一种是内存。很显然,只有将索引存放在磁盘上才是最佳方案。FSDirectory就是File System Directory的缩写,顾名思义,它指的就是将Lucene的索引直接建立在文件系统中。通常,在使用FSDirectory时,Lucene会自动在内存中建立缓存,然后到一定时候就将索引写入磁盘。这一步操作对我们来说其实是透明的,因为我们看不见内存中的操作,而只能看见写好的索引文件系统中的内容。2.5.2 Lucene的索引优化索引建立完以后,并不是原封不动地放置在文件系统中,而是需要对其进行适当的优化。优化索引就是通过合并磁盘上的索引文件,以便减少文件的数量,从而也减少搜索索引的时间。虽然可以通过控制各种各样的性能参数来改变磁盘上的Segment数量,但是,在索引建立完毕后,仍然可能存在大量未进行合并的Segment。在搜索的时候,搜索工具需要和磁盘上的所有索引文件打交道,如果索引Segment的数量太多,则必然一个搜索器要同时打开的文件数量也会增多,因此很容易降低检索时的效率。如果是在一个多线程的环境下,多个用户同时打开这些索引进行检索,那么服务器的效率更是会显著的降低,所以,需要对索引进行优化,以增加检索速度。IndexWriter的optimize()方法就是对索引进行优化的,它会将磁盘上多个Segment进行合并,组成一个全新的Segment。需要注意的是optimize()方法并不会增加建索时的速度,反过来,它会降低建索的速度,而且由于在合并索引时,需要额外的磁盘空间来创建新的Segment,因此它对磁盘空间的要求也会增加。通常情况下,optimize()方法不应当在索引建立的过程中被调用,而应当是在对大批量索引建立完成后再进行调用。这是因为在对索引进行优化时,磁盘的I/O操作频繁,如果太过频繁的进行索引的优化,会导致系统吞吐量大幅降低。2.6 搜索的流程如果检索的过程过于复杂,那么搜索引擎也就失去了其优势。本小节主要介绍使用Lucene进行检索的流程。2.6.1 初始化Lucene的检索工具IndexSearcherIndexSearcher是Lucene中最基本的检索工具,所有的检索工具都会用到IndexSearcher检索工具,但是在使用IndexSearcher之前,还要做一些准备工作,即对检索工具IndexSearcher进行初始化。初始化IndexSearcher,需要设置索引存放的路径,这样才能让查询器定位索引,用于后面进行搜索。如下为一个实例化IndexSearcher的过程:Searcher searcher = new IndexSearcher(indexDir);返回的结果是IndexSearcher类的一个实例,indexDir表示索引文件的存放路径。当然,初始化IndexSearcher不止这一种方式。2.6.2 构建QueryQuery的中文意义就是“查询”。在Lucene中,它是一个很重要的概念,就是指对于需要查询的字段采用什么样的方式进行查询,如模糊查询、语义查询、短语查询、范围查询、组合查询等。正是因为Query的存在,Lucene才有了非常丰富的查询语言。在使用Query前,需要首先生成一个Query对象。Lucene既允许直接生成一个Query型的对象,也允许使用QueryParser类的Parse ()方法来返回一个Query 型的对象。这两种方法在功能上是完全一样的,只是后者在使用时更方便一些,而前者则更为灵活。2.6.3 搜索并处理返回结果 在构建完Query对象后,就可以使用前面已经IndexSearcher工具来进行检索了。IndexSearcher提供了良好的检索接口,用户只需简单地将Query对象传入,就可以得到一个返回结果。当然,这个过程看似简单,其中也有许多值得思考的问题,如检索的结果排序,过滤等。2.7 搜索与结果在本节将介绍如何使用Lucene进行索引的检索。同时,又如何对返回的结果进行处理。2.7.1 检索工具IndexSearcher类Lucene中使用IndexSearcher类来对索引进行检索。IndexSearcher类继承自Searcher基类,是Lucene中最重要的一个检索用类。前面说过,在初始化一个IndexSearcher类时最重要的就是要告诉它索引存放的路径,只有这样,检索工具才可以定位索引,从而完成查找的任务。以下是IndexSearcher的所有构造函数:public IndexSearcher (String path) throws IOException this (IndexReader.open(path),true);public IndexSearcher(Directory directory)throws IOException this (IndexReader.open(directory),true);public IndexSearcher(IndexReader r) this (r, false);private IndexSearcher (IndexReader r, Boolean closeReader) reader = r; this. closeReader = closeReader; 可以看到,IndexSearcher一共提供了四种构造函数来初始化一个IndexSearcher对象。第一个方法最为简单,它直接使用了索引存放的路径作为参数来构造对象。第二种方式则是使用Directory类型的对象来构建IndexSearcher。第三种是直接使用IndexReader来初始化一个IndexSearcher对象。第四种则是在第三种的基础上加一个布尔型的开关,用于判断在关闭IndexSearcher时是否要关闭所带的IndexReader对象。可以看出,实际上,无论传入的参数类型是什么,IndexSearcher最终都还是使用IndexReader来作为实际的索引目录读取器。前三种构造函数均首先根据传入的参数生成一个IndexReader对象,然后调用了第四种构造方法来完成IndexSearcher的初始化工作。在初始化的工作完成之后,在进行搜索之前还需要构建一个Query对象。在IndexSearcher类中也有一个close方法。事实上,它关闭的并非Searcher对象本身,而是关闭Searcher对象内部所带的IndexReader对象。2.7.2 检索结果Hits在搜索完成之后,就需要把搜索结果返回并显示给我们,只有这样才算是完成了搜索的任务。在Lucene中搜索结果的集合是用Hits类的实例来进行表示的。所有的search方法都返回一个类型为Hits的对象。Hits对象中主要有以下几个经常使用的方法。length():返回搜索到结果的总数量。doc(int n):返回第n个文档。id(int n):返回第n个文档的内部ID号。score(n):返回第n个文档的得分。其中,1ength()方法和doc(int n)方法共同使用,就可以遍历结果集中的所有文档记录。不过有一点值得注意,如果一个结果集含有100000条记录,而Hits对象一次性就把检索结果全部返回,那么这个Hits对象的结果就会大不一样。对这个问题做了细致的考虑,它并不是一次性将所有的结果返回,而是采取一种懒惰(Lazy)的方式来加载返回结果,即当用户将要访问某个文档的时候,Hits对象在内部对Lucene的索引又进行了一次检索,才将这个最新的结果返回给我们。关于Hits对象的使用,在前面的章节中已经给出了许多例子,在建立完索引后,初始化一个IndexSearcher来进行检索。对于检索结果,在代码中使用了Hits对象所提供的大多数方法,比如获取文档、获取文档ID和获取文档评分等。代码在运行时,首先要求输入要查询的字符串,然后根据输入的查询字符串进