不知道大家看了上一篇的关于IndexReader的粗浅介绍是否有所收获,如果感觉到有不明白的地方请@我。
好了,按照流程来,今天我们就来说说IndexSeacher,小二上茶~~~~~~~哈哈
到了IndexSearcher这里就应该到了离我们最近的地方了,也可以说是我们用的最多的地方了,下面代码相信大家都不会陌生:
IndexSearcher searcher=new IndexSearcher(new IndexReader(FSDirectory.open(new File("d:/index")))); searcher.query(.....);
这就是一个最简单的搜索步骤了,前两篇文章我们已经说了Directory和IndexReader了,这里我们就来好好看看IndexSearcher。
其实IndexSearcher也相当于一个门面模式,它把Lucene的许多搜索功能全部都整合在一起了供外部使用,相当于提供给外部使用的一个接口(但是它并非接口),有了Seacher我们就可以选择一个索引目录,然后打开进行相关的搜索操作了,什么查询、排序、过滤之类的全部都是在它里面完成的,但是它也是通过调一些其他的模块来达到这些功能的,所以我们可以看做它是一个整合功能的提供者。
我们首先来看一个完整的构造函数:
public IndexSearcher(IndexReader reader, IndexReader[] subReaders, int[] docStarts, ExecutorService executor) { this.reader = reader; this.subReaders = subReaders;//指定子IndexReader this.docStarts = docStarts;//当前Searcher的docId的起始值 if (executor == null) { subSearchers = null; } else {//如果要支持并行搜索,前面我们讲过的,这里就将每个子Reader包装成一个子Searcher,让他们可以独立搜索 subSearchers = new IndexSearcher[subReaders.length]; for(int i=0;i<subReaders.length;i++) { subSearchers[i] = new IndexSearcher(subReaders[i], docStarts[i]); } } closeReader = false;//是否在关闭的时候同时关闭IndexReader this.executor = executor; docBase = 0;//docBase的存在是指有时候我们可以指定这个Seacher从那个docId开始 }
还有另外一个构造函数,跟这个差不多,但是他的子Reader并不是由用户指定的,而是通过IndexReader.getSequentialSubReaders();方法来进行收集的,这个方法会返回当前IndexReader的所有子Reader,IndexSeacher会递归去获取他们的子Reader,直到这个方法返回null。
说到IndexSearcher,我们就来说说多目录索引。有时候我们查询索引的时候并不是从一个单一的目录里面去查询的(有时候我们的索引太大时我们也会分目录来存放提高索引效率),索引我们要获取的结果就并不是从一个目录里面获取了,这时候我们就可以一个类MultiIndexReader(这个貌似应该放到前一篇讲?),通过这个类我们就可以为每个目录实例化一个IndexReader然后用它将他们联合在一起组合成一个对IndexSearcher可用的IndexReader,然后IndexReader可以通过收集子Reader将这些目录分别收集起来,如果我们在初始化一个新的IndexSearcher的时候就提供一个线程池(ExecutorService),那么Lucene就会在搜索的时候对这些目录同时并行搜索,然后将每个目录获取的结果进行加工处理(排序,过滤...),返回给我们的就是一份可用的数据了,这个对分布式搜索来说意义是很大的。
关于IndexReader里面的方法我们用的最多的恐怕就是:
public TopFieldDocs search(Weight weight, Filter filter, final int nDocs, Sort sort) throws IOException; public void search(Weight weight, Filter filter, Collector collector) throws IOException;
这两个方法就是我们的搜索入口啦,其他的search方法或多或少就是对这两个方法的重载,这里search方法里面究竟有什么动作?或者是Seacher为我们做了些什么事情?我们是怎么从索引里面获得我们想要的数据的?这些问题我们在这里先卖个关子,等到下一篇Query文章中我会替大家介绍Lucene究竟是怎么做的,我们也会感叹Lucene的设计的精妙之处!
这一篇的篇幅比较少,希望在下一篇能够补上,其实Query能说的东西太多了,甚至每一个Query都可以用很长的篇幅来说名作用的工作原理,所以各位如果有兴趣请关注我的下一篇文章