一、概述Lucene3.0(以下简称3.0)已于2009-11-25发布,3.0版本是重大的版本,改动很大。在API上做了很多的调整,已经删除了很多之前废弃的方法以及类,并支持了很多Java5 的新特性:包括泛型、可变参数、枚举和autoboxing等。
因此,此版本和2.x版本不能兼容,如要使用3.0版本,最好是在新项目中去使用,而不是去升级2.x或之前的版本!
二、2.9版本介绍
由于新版本变动很大,官方是不推荐从旧版本升级到新版本的。因为改动会很大。
其实在2.9版本时改动就很大,因为2.9版本就是为3.0做准备的,但是为了向下兼容,2.9并没有抛弃之前的旧方法,所以可以直接向下兼容。2.9版本主要是在性能方面的优化,包括在Lucene对Lucene底层的内部结构改进、索引的管理方式等多个方面。
1、索引文件改进
Lucene的索引数据是存放在独立的文件中的,这些文件就是存储着索引数据库一些列分离的“片段”。当我们想索引中增加文档时,便会不断的创建一些可以合并的新片段,因为读写文件的开销比较大,因此这些字段信息Lucene并非每次都直接加到索引文件里面去,而是先缓存,等到一定量的时候再一次写到文件中。在2.9以后,Lucene会为每个片段分别管理FieldCache以此避开跨片段加载FieldCatch的需求,这样就解决了Lucene跨片段加载FieldCatch的效率很低下问题,这个改动大为提高了性能。Lucid Imagination的Mark Miller运行了一个简单的性能测试,表明在5,000,000个不同字符串下的情况下,Lucene 相对于2.4版本会获得15倍左右的性能提高: Lucene 2.4: 150.726s Lucene 2.9: 9.695s
2、重开搜索
新版本引入了IndexWriter.getReader()方法,它可用于搜索目前完整的索引,包括当前IndexWriter会话中还没有提交的改变,这带来了接近于实时搜索的能力。此外,你还可以调用IndexWriter.setMergedSegmentWarmer()方法进行“预热”,这样那些片断便可以立即投入使用了。
3、数字处理
2.9版本之前的版本,都是基于文本搜索的,因为对于很多数字的处理方式就很头疼,例如在我们项目中遇到的很多问题都是由于把数字当作了文本处理出现的BUG:1、搜索价格的5,把包含.5的也搜索出来了;2、排序(降序)时,把800排到5000前面;……这些都是由于Lucene把所有的都作为文本处理的方式造成的问题。Lucene 2.9以后已经自带对数字的处理方式。Field和Query类会采取合适的精度进行索引和搜索,这样大大降低了需要搜索的关键字数量,使查询的响应能力得以显著提高。
4、其他优化
引入了新的查询类型和适用性更广的多关键字查询(通配、前缀等等)方式,以及新的针对波斯语,阿拉伯语及中文的分析器。此外,这次更新还包括更好Unicode支持,一个新的查询分析框架,以及对地理位置的查询,它允许根据距离信息对文档进行过滤和排序(如“找出我家5公里范围内的所有超市”)。
三、2.9版本和3.0比较
虽然2.9是为3.0做准备的一个版本,但是3.0和2.9相比较,变化还是比较大的,这处要体现在:
1.1、3.0抛弃了在2.9声明废弃的方法,因此3.0无法向下兼容;
2.2、3.0放弃了对Java1.4的支持,改为对高版本Java1.5和ant 1.7.0支持;
3.3、其他内核的一些变化,如oalLock.isLocked()现在会抛出IOException异常,对于一些静态变量的改变等。
四、3.0主要方法的改变
这里这种讲下目前新版本后使用建立索引以及搜索的不同。
1、建立索引
新版本在建立索引时抛弃了很多未用的方法,见下图,所有声明被抛弃的IndexWriter构造函数都在3.0中被删除。
3.0版本的IndexWriter构造函数:
在增加索引时,每个field的常量也有改变,具体如下:
2、查询
删除了Hits类,增加了TopScoreDocCollector去取得“Hits”,实际上在3.0给了个新命名:collector。使用方式和hits类同,同时删除了Search以及QueryParser的几个构造方法,QueryParser删除了 QueryParser(String f, Analyzer a)构造方法。
新查询例子如下(蓝色部分是与以往不同的部分):[CODE=java]
QueryParser parser = new QueryParser(Version.LUCENE_CURRENT, field,
new StandardAnalyzer(Version.LUCENE_CURRENT));
Query query = parser.parse(q);
TopScoreDocCollector collector = TopScoreDocCollector.create(100, true);
IndexSearcher is = new IndexSearcher(FSDirectory.open(file), true);
is.search(query, collector);
ScoreDoc[] docs = collector.topDocs().scoreDocs;
for (int i = 0; i < docs.length; i++) {
Document doc = is.doc(docs[i].doc);// new method is.doc()
System.out.println(doc.getField(“name”) + ” ” + docs[i].toString() + ” “);
}
3.0版本的Search构造方法:
3.0前的构造方法:
五、3.0总体图
3.0版本的结构和之前的版本(2.9之前)相比,在程序结构上表现出来就只是多了一个message包,用来专门处理国际化。
可以看到,3.0和之前的版本一样还是由对外接口、索引核心以及基础结构封装三大部分共八个模块(也即包package),详细介绍详见附件一。 我们从上图也可以看到Lucene搜索时的调用关系:当我们要查询一个词时,在查询模块(search)会先调用语法分析器(queryParser)对查询语句进行分析,语法分析模块调用了词法分析器(analysis)进行词法分析,如对搜索关键字分词、过滤等,词法分析器在使用时会根据实际情况调用国际化模块(message)进行一些国际化的处理。当这些前置工作做完之后,才真正进入到搜索核心,首先会调用索引模块(index),它负责向底层的存储类(store)去读取索引文件里面的数据,然后返回给查询模块。其他模块在整个搜索过程中是作为公共类存在的。