JAVALuceneinAction教程完整版.docx
《JAVALuceneinAction教程完整版.docx》由会员分享,可在线阅读,更多相关《JAVALuceneinAction教程完整版.docx(51页珍藏版)》请在冰豆网上搜索。
JAVALuceneinAction教程完整版
LuceneinAction(简体中文版)
共10部分
第一部分Lucene核心
1. 接触Lucene
2. 索引
3. 为程序添加搜索
4. 分析
5. 高极搜索技术
6. 扩展搜索
第二部分Lucene应用
7. 分析常用文档格式
8. 工具和扩充
9. Lucene其它版本
10. 案例学习
[序章]
Lucene开始是做为私有项目。
在1997年末,因为工作不稳定,我寻找自己的一些东西来卖。
Java是比较热门的编程语言,我需要一个理由来学习它。
我已经了解如何来编写搜索软件,所以我想我可以通过用Java写搜索软件来维持生计。
所以我写了Lucene。
几年以后,在2000年,我意识到我没有销售天赋。
我对谈判许可和合同没有任何兴趣,并且我也不想雇人开一家公司。
我喜欢做软件,而不是出售它。
所以我把Lucene放在SourceForge上,看看是不是开源能让我继续我想做的。
有些人马上开始使用Lucene。
大约一年后,在2001年,Apache提出要采纳Lucene。
Lucene邮件列表中的消息每天都稳定地增长。
也有人开始贡献代码,大多是围绕Lucene的边缘补充:
我依然是仅有的理解它的核心的开发者。
尽管如些,Lucene开始成为真正的合作项目。
现在,2004年,Lucene有一群积极的深刻理解其核心的开发者。
我早已不再每天作开发,这个强有力的工作组在进行实质性的增加与改进。
这些年来,Lucene已经翻译成很多其它的语言包括C++、C#、Perl和Python。
在最开始的Java和其它这些语言中,Lucene的应用比我预想的要广泛地多。
它为不同的应用(如财富100公司讨论组、商业Bug跟踪、Microsoft提供的邮件搜索和100页面范围的Web搜索引擎)提供搜索动力。
在业内,我被介绍为“Lucene人”。
很多人告诉我他们在项目中使用到Lucene。
我依然认为我只听说了使用Lucene的程序的小部分。
如果我当初只是出售它,Lucene应用得不会这么广泛。
程序开发人员看来更喜欢开源。
他们在有问题时不用联系技术支持而只需查看一下源代码。
如果这还不够,邮件列表中的免费支持比大多商业支持要好得多。
类似Lucene的开源项目使得程序开发人员更加有效率。
Lucene通过开源已经变得比我想象的伟大的多。
我见证了它的发展,是Lucene社区的努力才使得它如此兴旺。
Lucene的未来怎样?
我无法回答。
有了这本书,你现在也是Lucene社区的一员,现在由您将Lucene带往新的高地。
旅途顺利!
DOUGCUTTING
Lucene和Nutch的作者
前言
来自ErikHatcher
在Internet早期我就对搜索和索引感兴趣。
我已经建立了用majordomo、MUSH(MailUser’sShell)和少量Perl、awk及shell脚本来管理邮件列表的存储结构。
我实现了一个CGI的web接口,允许用户搜索这个列表和其它用户的信息,其内部使用了grep。
然后相继出现了Yahoo!
、AltaVista和Excite,这些我都经常访问。
在我有了第一个儿子Jakob之后,我开始了数字照片档案的设计。
我想开发一套管理图片的系统,可以给图片附加元数据,如关键字、拍摄日期。
当然用我选择的尺寸定位图片是很容易的。
在19世纪90年代末,我构建了基于文件系统的原型,使用了Microsoft的技术,包括MicrosoftIndexServer、ActionServerPages及处理图片的第三方COM组件。
从那时起,我的职业生涯都消耗在这些类似的技术上了。
Iwasabletocobbletogetheracompellingapplicationinacoupleofdaysofspare-timehacking.
我的职业转向Java技术,并且我越来越少地利用MicrosoftWindows。
为了以系统无关的方式用Java技术重新实现我的个人照片档案系统及搜索引擎,我使用了Lucene。
Lucene的简单易用远远超过了我的期望—我所期望的其它开源库或工具在概念上简单,但是却难以使用。
在2001年,SteveLoughran和我开始编写JavaDevelopmentwithAnt(Manning)。
我们采用图片搜索引擎的思想,并把它推广为一个文档搜索引擎。
这个程序示例在那本Ant书中使用,而且可被定制为图片搜索引擎。
Ant的责任不仅来自于简单的编译打包的构建过程,也来自于定制的任务,,我们在构建过程中使用Lucene创建索引文件。
Ant任务现在生存在Lucene的Sandbox(沙箱)中,将在本书8.4节描述。
Ant已经应用在我的博客系统中,我称为BlogScene(http:
//www.blogscene.org/erik)。
在建立一个博客实体之后,我运行一个Ant构建过程,索引新的实体并将它们上传到我的服务器上。
我的博客服务器由一个Servlet、一些验证模板和一个Lucene索引组成,允许(rich)查询,甚至联合查询。
与其它博客系统相比,BlogScene在特色和技巧上差很多,但是它的全文检索能力非常强大。
我现在效力于维吉尼亚大学对Patacriticism的应用研究小组(http:
//www.patacriticism.org)。
我用对文本分析、索引和搜索的经验通过讨论量子力学与艺术的关系来测试及拓展我的思路。
“诗人是世界上不被认可的最伟大的工程师”。
来自OtisGospodnetic
我对信息搜索与管理的兴趣和热情开始于在Middlebury大学的学生时代。
那时候,我发现了信息的广大资源,即Web。
尽管Web仍然刚开始发展,但是对收集、分析、索引和搜索的长期需求是很明显的。
我开始对建立来自Web的信息库感到困惑,开始编写Web爬行器梦想有种方法可以对这些收集的信息进行搜索。
我认为在巨大的未知领域中搜索是杀手级软件。
有了这种思想以后,我开始了一系列收集和搜索项目。
在1995年,和同学MarshallLevin一起创建了WebPh,一个用来收集和找出个人联系信息的开源程序。
基本上,这是一个简单的具有Web接口(CGI)的电话本,那时排在首位的类型。
(实际上,它在19世纪90年代末的案例学习中被引用为一个示例。
)大学和政府机构是这个程序的主要用户,现在还有很多在使用它。
在1997年使用我的WebPh,我继续创建了Populus,一个当时很流行的白页。
尽管技术(与WebPh类似)很普通,但是Populus有很重的负担,并且能够与WhoWhere、Bigfoot和Infospace等大角色相媲美。
在两个关于个人联系信息的项目之后,是该探索新的领域了。
我开始了下一个冒险,Infojump,用来在网上时事通讯、杂志、报纸中选择高质量的信息。
我拥有的软件由大量的Perl模块和脚本组成,Infojump利用一个称作Webinator的Web爬行器和一个全文搜索的产品叫作Texis。
在1998年Infojump提供的服务很像今天的FindA。
尽管WebPh、Populus和Infojump达到了它们的目的并是功能很完善,但它们都有技术的局限性。
它们缺少的是一个用反向索引来支持全文搜索强大的信息搜索库。
为了不重复相同的工作,我开始搜寻一个我认为不可能存在的解决方案。
在2000年早期,我发现了Lucene,我正在寻找的缺少的部分,并且我一下子就喜欢上了它。
我在Lucene还在SourceForge的时候就加入了这个项目,后来2002年Lucene转移到Apache软件基金会。
我对Lucene的热爱是因为这些年来它已经成为我很多思想的核心组件。
这些思想中的一个是Simpy,我最近的一个项目。
Simpy是个有许多特点的个性Web服务,可以让用户加标签、索引、搜索和共享在网上找到的信息。
它主要使用了Lucene,上千条索引,由DougCutting的另一个项目Nutch(见第10章)提供动力支持。
我对Lucene的积极参与导致我被邀请与ErikHatcher共同编写LuceneinAction。
LuceneInAction有关于Lucene最全面的信息。
接下来的10章包含的信息围绕你使用Lucene创建优秀程序所需的所有主题。
这是它平坦且轻快的协作过程的结果,就像Lucene社区一样。
Lucene和LuceneinAction证明了有类似兴趣的人们可以完成什么,不管在人生中会碰到什么情况,都会积极地为全球知识的共享做出贡献。
致谢朋友!
首先并且是最重要的,我们感谢我们的妻子Carole(Erik)和Margaret(Otis),一直支持这本书的写作。
没有她们的支持,这本书就不可能出版。
Erik感谢他的两个儿子,Ethan和Jakob,因为他们的忍耐和理解,Erik写这本书时没有时间陪他们玩耍。
我们真诚感谢DougCutting。
没有Doug的贡献,就不可能有Lucene。
没有其他Lucene的贡献者,Lucene就会少很多特征、更多的Bug,Lucene的成长就会花更长的时间。
感谢所有的贡献者,包括PeterCarlson、TalDayan、ScottGanyo、EugeneGluzberg、BrianGoetz、ChristophGoller、MarkHarwook、TimJones、DanielNaber、AndrewC.Oliver、DmitrySerebrennikov、KelvinTan和MattTucher。
同时,我们感谢所有贡献在第10章的案例的人:
DionAlmaer、MichaelCafarella、BobCarpenter、KarstenKonrad、TerenceParr、RobertSelvaraj、RalfSteinbach、HolgerStenzhorn和CraigWalls。
…
…
本书简介
LuceneinAction为使用最好的Java开源搜索引擎的用户提供所有细节、最好的实践、警告、技巧。
本书假设读者熟悉基本的Java编程。
Lucene本身是个Java档案(JAR)文件并能集成到简单的命令行程序和大型企业级应用程序中。
Roadmap
我们在本书第1部分覆盖Lucene核心编程接口(API)使你在将Lucene整合到你的程序中时愿意使用它:
n 第1章,接触Lucene。
我们介绍了一些基本的信息搜索术语和Lucene的主要竞争对手。
我们很快地构建了一个你马上能用或修改以适应需要的简单索引和搜索程序。
这个示例程序向你打开了探索Lucene其它能力的大门。
n 第2章使你熟悉Lucene基本的索引操作。
我们描述了索引数值和日期的不同字段类型和各种技术。
包括调整索引过程、优化索引以及如何处理线程安全。
n 第3章向你介绍基本的搜索,包括Lucene如何根据查询来排列文档的细节。
我们讨论基础的查询类型及它们如何通过用户输入的查询表达式创建。
n 第4章深入研究Lucene的索引核心,分析过程。
分析器创建块及单词、单词流和单词过滤器。
我们创建了一些定制的分析器,showcasingsynonyminjectionandmetaphone(likesoundex)replacement.也分析了非英语语言,典型的分析汉字文本的示例。
n 第5章讲述搜索章节剩余的。
我们描述了一些高级的搜索特征,包括排序、过滤及使用词向量。
高级的查询类型在此出现,包括SpanQuery家族。
最后,我们讨论了Lucene对查询多索引的内建支持,并行的及远程的。
n 第6章超越高级搜索,向你展示了如何扩展Lucene的搜索能力。
你将学到如何定制搜索结果的排序、扩展查询表达式分析、实现Hit收集和调整查询性能。
第2部分超越Lucene内建的工具并向你展示围绕Lucene可以做什么。
n 第7章,我们创建了可重用、可扩展的用来分析Word、HTML、XML、PDF及其它格式文档的框架。
n 第8章包括围绕Lucene的扩展和工具。
我们描述了一些Lucene的索引查看和开发工具以及Lucene沙箱中的好东西。
高亮搜索项就是这种你想要的沙箱扩展,还有在Ant构建过程中创建索引的其它工具。
使用noncore分析器,并使用类似WordNet的索引。
n 第9章描述Lucene翻译成其它各种语言的版本,如C++、C#、Perl和Python。
n 第10章将Lucene的技术细节带到大量优秀的案例学习中。
这些案例由那些创建了以Lucene为核心的有趣的、快速的、可升级的程序的开发者提供。
谁应该阅读本书?
在程序中需要强大搜索能力的开发人员需要阅读这本书。
LuceneinAction也适合于那些对Lucene或索引和搜索技术好奇的开发人员,他们可能不会马上就用到它。
把Lucene添加到你的工具箱对以后的项目来说是值得的—搜索是个热门的话题并且将来也会是。
这本书主要使用Java版的Lucene(来自ApacheJakarta),并且大多数示例使用Java。
最适合熟悉Java的读者。
Java经验是很有帮助的,然而Lucene已经翻译成很多其它的语言包括C++、C#、Python和Perl。
概念、技术甚至API本身都和Java版Lucene差不多。
代码示例
本书的源代码可以从Manning的网站
书中出现的大多数代码是由我们编写并包含在代码包中。
某些代码(尤其是案例代码)不在我们的代码包中提供。
书中的代码片断归贡献者所有。
同时,我们包含了Lucene代码库的部分代码,基于Apache软件许可协议(http:
//www.apache.org/licenses/LICENSE-2.0)。
代码示例不包括package和import语句,以节省空间;具体请参照实际代码。
为什么是JUnit?
我们相信书中的代码示例应该都是高质量的。
典型的“helloworld”例子经常帮助读者测试他们的环境。
我们使用独特的方法来使用书中的代码示例。
大部分示例是实际的JUnit测试用例(http:
//www.junit.org)。
JUnit,是Java单元测试框架,可以断言一个特殊情况是否能以可重复的方式出现。
通过IDE或Ant进行自动JUnit测试用例可以一步一步地构筑系统。
我们在本书用使用JUnit是因为平时都在其它项目中使用,并想让你看看我们如何编码。
测试驱动开发(TestDrivenDevelopment,TDD)是我们强烈推荐的开发模式。
如果你对JUnit不熟,请阅读以下基础。
我们也建议你阅读DaveThomas和AndyHunt编著的《PragmaticUnitTestinginJavawithJUnit》,还有VincentMassol和TedHusted编著的《JUnitinAction》。
JUnit基础
这部分是对JUnit快速但当然不完整的介绍。
我们将提供理解我们示例代码所需的基础知识。
首先,我们的JUnit测试用例继承junit.framework.TestCase并且很多通过部LiaTestCase基类间接继承它。
我们的具体测试类附合这个命名习惯:
给类名加后缀Test。
例如,我们的QueryParser的测试是QueryParserTest.java。
JUnit自动执行所有类似publicvoidtestXXX()的方法,此处XXX是个任意有意义的名称。
JUnit测试方法必须简洁,保持好的设计。
(例如创建可重复的功能模块等等)
断言
JUnit建立在一组assert语句上,使你自由编写简洁的测试代码并使JUnit框架处理失败状态及指出细节。
最常用的assert语句是assertEquals;一些是为不同的数据类型而重载的assertEquals方法。
一个示例测试方法如下:
publicvoidtestExample(){
SomeObjectobj=newSomeObject();
assertEqueals(10,obj.someMethod());
}
如果指定的值(在本例中的10)不等于真实值(本例中是调用obj的someMethod的返回值),assert方法抛出运行时异常。
除了assertEquals,为了方便还有一些其他assert方法。
我们也使用assertTrue(expression)、assertFalse(expression)和assertNull(expression)语句。
这些测试分别判断这个表达式是否是true、false和null。
assert语句有个接受一个附加的String参数的重载表示。
String参数都是用来汇报的,在测试失败时向开发人员指出更多信息。
我们使用这个String消息参数以更好的描述。
通过以这种风格编写我们的测试用例,可以从我们构建大系统的复杂中解放出来,而且可以每次只关注更少的细节。
利用合适的测试用例,我们能够增强信心和灵活性。
信心来自于我们知道代码的变化如优化算法不会破坏系统的其它部分,因为出现这种情况的话,自动测试组件能让我们在它影响产品之前发现。
重构是一种改变代码内部结构的艺术(或者说科学),所以它能够适应变化的需求而又不影响系统的对外接口。
在上下文中的JUnit
让我们看一下到目前为止谈论的JUnit并把它放到本书的上下文中。
JUnit测试用例继承于junit.framework.TestCase,且测试方法都类似publicvoidtestXXX()形式。
我们的测试用例之一(第3章)如下:
publicclassBasicSearchingTestextendsLiaTestCase{
publicvoidtestTerm()throwsException{
IndexSearchersearcher=newIndexSearcher(directory);
Termt=newTerm(“subject”,“ant”);
Queryquery=newTermQuery(t);
Hitshits=searcher.search(query);
assertEquals(“JDwA”,1,hits.length());
Onehitexpectedfor
searchfor“ant”
t=newTerm(“subject”,“junit”);
hits=searcher.search(newTermQuery(t));
assertEquals(2,hits.length());
Twohitsexpectedfor“junit”
searcher.close();
}
}
当然,我们将在之后解释这个测试用例中使用的LuceneAPI。
现在我们只关注JUnit的细节。
testTerm方法中的directory变量没在此类中定义。
JUnit提供一个在执行每个测试方法之前的初始化钩子;这个钩子是名为publicvoidsetUp()的方法。
我们的LiaTestCase基类以这种方式实现setUp:
publicabstractclassLiaTestCaseextendsTestCase{
privateStringindexDir=System.getProperty(“index.dir”);
protectedDirectorydirectory;
protectedvoidsetUp()throwsException{
directory=FSDirectory.getDirectory(indexDir,false);
}
}
如果testTerm中的第一个断言失败,我们会得到一个异常:
junit.framework.AssertionFalsedError:
JDwAexpected:
<1>butwas:
<0>
atlia.searching.BasicSearchingTest.
→ testTerm(BasicSearchingTest.java:
20)
这个失败指出我们的测试数据与预期的结果不同。
测试Lucene
本书中的大部分测试都是测试Lucene本身的。
实际上,这是否现实呢?
难道要测的不是我们自己写的代码而是库本身?
有个TestDrivenDevelopment的姊妹篇是用来学习API的:
TestDrivenLearning。
它为新API写测试以了解它是如何工作以及你能从中得到什么时非常有帮助。
这正是我们在大部分代码示例中所做的,所以测试都是测试Lucene它本身。
但是不要把这些为学习而做的测试抛开。
保留它们以确保你在升级到新版的API或因API改变而重构时,它们能够保持真值。
模型对象
在一些用例中,我们使用模型对象来测试。
模型对象用来作为探测器传入真实的业务逻辑,以判断这个业务逻辑是否正常工作。
例如,第4章中有个SynonymEngine接口(4.6节)。
使用这个接口的真实业务逻辑是个分析器。
当我们想测试这个分析器本身时,SynonymEngine使用什么类型就不重要,我们只想使用一个定义良好并有可预见行为的对象。
模型对象可以使得测试用例尽可能简单,这样它们每次只测试系统的一个方面,在测试失败要修正什么错误时没有纠缠的依赖。
使用模型对象的一个好处来自于设计的变动,例如关系的分离和设计使用接口代替直接具体实现。
我们的测试数据
为了避免每个小节都要用完全不同的数据,书中大部多都是围绕一组公共的示例数据以提供一致性。
这些示例数据由书籍详细资料组成。
表1显示了这些数据,你可以参考它来理解我们的例子。
表1本书中用到的示例数据
Title/Author
Category
Subject
AModernArtofEducation
RudoifSteiner
/education/pedagogy
educationphilosophy
psychologypracticeWaldorf
ImperialSecretsofHealth
andLogevity
BobFlaws
/health/alternative/Chinese
dietchinesemedicineqi
gonghealthherbs
TaoTeChing道德經
StephenMitchell
/philosophy/ea