当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;
}