当BoboSubBrowser的browse()函数创建好filter和collector以后,那么就进入最后的阶段了,从索引中获取倒排表,进行过滤和收集,这一过程在类BoboSearcher2的search()函数中实现:
public void search(Weight weight, Filter filter, Collector collector, int start) throws IOException { final FacetValidator validator = createFacetValidator(); int target = 0; //没有过滤条件,那么 if (filter == null) { for (int i = 0; i < _subReaders.length; i++) { // search each subreader int docStart = start + _docStarts[i]; //初始化最终结果收集器,collector用于收集搜索结果中满足过滤条件的文档 collector.setNextReader(_subReaders[i], docStart); //初始化validtor,它用于收集各个Facet的各个属性的计数 validator.setNextReader(_subReaders[i], docStart); //得到该IndexReader的scorer Scorer scorer = weight.scorer(_subReaders[i], true, true); if (scorer != null) { collector.setScorer(scorer); target = scorer.nextDoc(); while(target!=DocIdSetIterator.NO_MORE_DOCS) { if(validator.validate(target)) { collector.collect(target); target = scorer.nextDoc(); } else { target = validator._nextTarget; target = scorer.advance(target); } } } } return; } for (int i = 0; i < _subReaders.length; i++) { //得到过滤后的文档列表 filterDocIdSet,与得到的搜索结果倒排表进行两路归并 DocIdSet filterDocIdSet = filter.getDocIdSet(_subReaders[i]); if (filterDocIdSet == null) return; int docStart = start + _docStarts[i]; //初始化最终结果收集器,collector用于收集搜索结果中满足过滤条件的文档 collector.setNextReader(_subReaders[i], docStart); //初始化validtor,它用于收集各个Facet的各个属性的计数 validator.setNextReader(_subReaders[i], docStart); Scorer scorer = weight.scorer(_subReaders[i], true, false); if (scorer!=null){ collector.setScorer(scorer); //得到过滤条件文档列表 DocIdSetIterator filterDocIdIterator = filterDocIdSet.iterator(); // CHECKME: use ConjunctionScorer here? int doc = -1; //从过滤列表中得到第一个文档号target target = filterDocIdIterator.nextDoc(); while(target < DocIdSetIterator.NO_MORE_DOCS) { if(doc < target) { //从搜索结果列表中取得下一个文档号,而且起点是从target开始找,即大于等于target的doc doc = scorer.advance(target); } if(doc == target) // permitted by filter { if(validator.validate(doc)) { collector.collect(doc); target = filterDocIdIterator.nextDoc(); } else { // skip to the next possible docid target = filterDocIdIterator.advance(validator._nextTarget); } } else // doc > target { if(doc == DocIdSetIterator.NO_MORE_DOCS) break; //在过滤列表中搜寻大于等于doc的target target = filterDocIdIterator.advance(doc); } } } }
这个search()的主要工作就是将满足query条件的搜索结果进行过滤,过滤条件是filter决定的。这个过滤的过程其实是一个两路归并算法,一个是搜索结果列表,另一个是过滤列表。最后在两个列表中重叠的文档被collector收集起来,并进行排序。
搜索结果与过滤条件的重合docId的文档,即上面代码中满足条件:
if(doc == target) // permitted by filter
这样的doc再经过FacetValidator处理,也就是计数
if(validator.validate(doc))//这里的validate()函数,实际上就是计数的过程 { //返回结果收集器对该doc进行收集 collector.collect(doc); target = filterDocIdIterator.nextDoc(); }
通常FacetSpec默认设置ExpandSelection为false ,那么CreateFacetValidator ()返回的是 new NoNeedFavalidator (FacetHitCollector[]),其validate()函数如下:
@Override public final boolean validate(int docid) throws IOException { //每个Facet的分组计数器对该doc进行计数,也就是_count[docid]++ for (FacetCountCollector collector : _countCollectors){ collector.collect(docid); } return true; }