Bobo源码笔记5(结果的筛选和收集)

当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()函数如下:

扫描二维码关注公众号,回复: 808206 查看本文章
   @Override
    public final boolean validate(int docid) throws IOException {
       //每个Facet的分组计数器对该doc进行计数,也就是_count[docid]++
       for (FacetCountCollector collector : _countCollectors){
        collector.collect(docid);
      }
      return true;
    }
 

猜你喜欢

转载自eric-gcm.iteye.com/blog/1671702