高玉良 张济强 白瑶
摘要:Lucene是一个高性能、易扩展的基于Java技术的开源信息检索工具包,它可以为多种应用程序提供索引和搜索功能。该文探讨了Lucene中在多个索引上进行搜索的方式,分析了每种方式的性能以及应用范围,引进Java的线程池技术对多索引上的多线程搜索算法进行改进,并且通过实验验证改进算法的优越性。
关键词:Lucene;多索引;线程池
中图分类号:TP311文献标识码:A文章编号:1009-3044(2012)07-1470-03
Research and Application of Multi-index Based Lucene
GAO Yu-liang, ZHANG Ji-qiang, BAI Yao
(Dalian JiaoTong University, Dalian 116028, China)
Abstract: Lucene is a tool based on Java technology, it is an open source,and possess character of high performance and being easy to expand.Lucene provide a function to searcher for application.The paper discuss a searching method about mutile index in lucene,and its performance and range of application. Java Thread Pool are used to improve multile index ing searcher , and certify that this algorithm is higher performance.
Key words: Lucene; multi index; thread pool
对于大型的检索系统,索引文件可能存在于多个目录中,每次进行检索请求时,检索系统可能要对存在于多个目录中的索引文件进行检索。在这种情况下,Lucene主要提供两种方式,即MultiSearcher和ParalellMultiSearcher对存在于多目录中的索引进行搜索。MultiSearcher是用一个循环把存在于不同目录中的索引取出,然后逐个检索并合并搜索结果。ParalellMultiSearcher是用多线程的方式,对于不同目录中的索引建立不同的线程进行并行的搜索,同时动态的合并搜索结果。但以前的Lucene开发包中的ParalellMultiSearcher检索方式的性能低于MultiSearcher,本文对ParalellMultiSearcher的多线程实现方式进行改进,引入了线程池技术。
1 Lucene的构成及检索机制
1.1 Lucene的构成
Lucene是Apache基金会Jakarta的一个子项目,完全按照面向对象的思想设计而成。各个类之间满足低耦合的原则,是一个高效率的搜索工具包。Lucene完全由Java JDK开发而成,没有用到任何第三方开发包。基于Java语言良好的可移植性,Lucene也具有良好的跨平台特性。最新的Lucene开发包在2011年3月份发布,版本为3.0。
1.2 Lucene主要由以下部分组成
1) Analysis包。包括Lucene的语言分词器。最新的开发包提供很好的多语言分词器适应多语言检索系统的开发。
2) Index包。此包为Lucene的非常关键的一个包,包换Lucene中各种索引文件的生成以及索引的删除、更新等类。
3) Document包。包括Lucene中建立索引的数据结构,构成Lucene中索引文件的组成部分。
4) Messages包。提供一个消息接口。
5) QueryParse包。Lucene的查询分析包,提供各种查询间的各种运算,包括与,或,非等。
6) Store包。提供有关索引文件存储方式的包。
7) Search包。Lucene的检索包,这个包主要是提供在已经生成的索引(也就是用Index生成的各种类型的索引)之上进行检索的各个类。
8) Util包。一个工具包。
1.3 Lucene的索引机制
在Lucene中,索引(Index)由Segment组成,Segment由Document组成,Document由Field组成,Field由Term组成。生成的索引有三种存储方式:内存(RAM),文件系统(FS),数据库系统(DB)。RAM方式适用于小型的系统,FS方式适应于中型的搜索系统,DB方式适应于大型分布式的搜索系统。
以FS文件系统方式开发的搜索系统,会生成相应的索引文件。对于大中型的搜索系统,索引文件可能会存储于不同的目录中。Lucene的索引文件是以倒排文件的形式生成的。倒排文件直观上说就好像一本书的目录,这种结构的文件格式有利于Lucene提供高性能的检索服务。
1.4 Lucene中的多索引搜索
事实上,在一些成熟的商业系统中,索引并非总是存放在一个目录中。很多时候,系统会按照某种散列算法将文档分散地放置在不同的索引目录下[]。另外,还有可能在多个目录中存在着用户想要查找的内容。在Lucene中,有两种方式可以用于多目录索引的查找。
2 MultiSearcher方式
使用MultiSearcher方式查找,首先要构建一个IndexSearcher数组,该数组中包括了若干的IndexSearcher对象,分别用于查找不同的索引目录。这个数组被传入MultiSearcher的构造函数中。当MultiSearcher构造完毕后,可以调用searcher方法来进行查找。实际上,MultiSearcher的实现方式是用一个循环来遍历传入的IndexSearcher数组,进行查找,并把结果集返回。
下面是MultiSearcher方式的关键代码:
1)建立IndexSearcher对象
IndexSearcher searcher1 = new IndexSearcher(INDEX_PATH1);
IndexSearcher searcher2 = new IndexSearcher(INDEX_PATH2);
IndexSearcher searcher3 = new IndexSearcher(INDEX_PATH3);
2)建立SearcherIndex对象数组
IndexSearcher[] searchers = {searcher1,searcher2,searcher3};
3)应用MultiSearcher
MultiSearcher msearcher = new MultiSearcher(searchers);
ScoreDoc[] hits = msearcher.searcher(qurey,filter,n).scoreDocs;
For (int i = 0; i < hits.length(); i++) {
Document hitDoc msearcher.doc(hits[i].doc);
System.out.println(hitDoc.get(fieldname));
}
2.1 ParalellMultiSearcher方式
MultiSearcher实际上是用一个循环来遍历IndexSearcher的对象数组,然后把查询结果合并到一起。在这个过程中,只有一个索引被搜索,其他的索引一直处于等待状态。为了充分利用计算机并行处理问题的能力,Lucene中引入了具备多线程能力的ParalellMultiSearcher类提供对多个索引进行并行查询。在最新的Lucene 3.0中,ParalellMultiSearcher使用了线程池技术,下面先对Java中的线程池做一个简单的介绍。
2.2 Java线程池介绍
newFixedThreadPool创建一个指定工作线程数量的线程池。每当提交一个新任务就创建一个工作线程,当线程数量达到线程池的初始设置的数量时,则将任务存入到池队列中。
newCacheThreadPool创建一个可缓存的线程池,这类线程池的工作线程的数量只受到系统中最大数量的限制,并且长时间没有新线程加入到池中的时候,线程池中的工作线程将自动中止。如果再有新的任务提交,则线程池重新创建新的工作线程。
newSingleThreadExecutor创建一种线程数量为1的FixthreadPool,适用于对一个连续事务的处理。
newScheduleThreadPool创建一个支持定长的线程池,最重要的是支持定时的任务执行。
2.3 ParallelMultiSearcher的具体实现
通过以上对Java线程池的介绍,笔者认为,newCacheThreadPool这种线程池比较适合Lucene中多线程的查询应用。因为在Lucene的查询中,查询请求往往是间断的提交。比如一次请求对200个索引查询,然后间隔五分钟又有一个对300个索引的查询。由于这种间断性,如果选择newFixedThreadPool这种线程池,当没有查询请求时,线程池中的线程不会得到释放,会造成系统资源的大量占用。另一个原因,newFixedThreadPool的线程池大小在初始化的时候设定,而且不可以改变,线程池的初始值大小的选择可能对系统性能造成影响。
关键代码:
ParallelMultiSearcher searcher =
new ParallelMultiSearcher(searchers);
ParallelMultiSearcher的构造函数:
public ParallelMultiSearcher(Searchable... searchables)
throws IOException {
super(searchables);
this.searchables = searchables;
this.starts = getStarts();
executor = Executors.newCachedThreadPool(new namedThreadFactory(this.getClass().getSimpleName()));
}
通过对以上两种方式的分析,让我们对Lucene中多线程检索有了更深的认识。下面是具体的实验情况。
3实验结果分析
表1
表1的数据是分别对10到1000个索引以两种方式进行查询时所用的时间比较,可以看出,多線程查询方式的优势还是比较明显的。
4结束语
该文对Lucene中多索引查找的两种方式进行了介绍。在以前的Lucene版本中,多线程的搜索方式没有引入线程池,这样,线程每次都要进行初始化,造成多线程方式的性能低于Mutil方式。通过引入线程池,解决了这一问题,通过对实验数据的分析,验证了加入线程池技术的多索引搜索方式的优良性能。但通过实验也发现这种方式存在的问题,当线程数目很大时,可能会造成内存的溢出,在实际应用中,应该通过上层程序避免此种情况的发生。
参考文献:
[1] Gospodnetic O,Hatcher E. Lucene in action[M]. Man2ning Publications Co ,2005.
[2]邱哲,符滔滔,王学松.开发自己的搜索引擎Lucene+Heritrix.[M]. 2版.北京:人民邮电出版社,2010.
[3]李晓明,朱家稷,闫宏飞.互联网上主题信息的一种收集与处理模型及其应用[J].计算机研究与发展,2003,40(12).
[4]张敏,高剑峰,马少平.基于链接描述文本及其上下文的Web信息检索.计算机研究与发展,2004,41(1).
[5]孙建涛,沈科,陆玉昌等网页分类技术[J].清华大学学报:自然科学版,2004,44(1).
[6]李晓明,李星.搜索引擎与Web挖掘进展[M].北京:高等教育出版社,2003.
[7]徐宝文,张卫丰.搜索引擎与信息获取技术.[M].北京:清华大学出版社,2003.
[8]李盛涛,吴丽辉,于满泉,等.主题Web信息采集的研究与设计[C]//语言计算与基于内容的文本处理.北京:清华大学出版社,2003.