在browse()函数中有这样一段代码。这段代码做了两件事:一,根据每个facet的过滤条件创建filter;二,根据每个facet的分组计数规则创建FacetHitCollector :
for (String name : fields)//对应于每一个Facet { //得到该facet的筛选条件 BrowseSelection sel = req.getSelection(name); //得到该facet分组计数规则 FacetSpec ospec = req.getFacetSpec(name); FacetHandler<?> handler = getFacetHandler(name); if (handler == null){ logger.warn("facet handler: "+name+" is not defined, ignored."); continue; } FacetHitCollector facetHitCollector = null; RandomAccessFilter filter = null; //如果该Facet下有selection,那么构建该facet的filter if (sel != null) { filter = handler.buildFilter(sel); } if (ospec == null) {//若ospec为空,那么不对该facet进行分组计数 if (filter != null) { preFilterList.add(filter); } } else { FacetSpec fspec = ospec; //创建FacetHitCollector facetHitCollector = new FacetHitCollector(); facetHitCollector.facetHandler = handler; if (isDefaultSearch) {//不做query,无过滤条件,相当于将索引中的各个facet的计数分组显示出来 facetHitCollector._collectAllSource=handler.getFacetCountCollectorSource(sel, fspec); } else {//得到分组计数产生器,并将它赋值给facetHitCollector facetHitCollector._facetCountCollectorSource = handler.getFacetCountCollectorSource(sel, fspec); if (ospec.isExpandSelection()) { if (isNoQueryNoFilter && sel!=null && selCount == 1) { facetHitCollector._collectAllSource=handler.getFacetCountCollectorSource(sel, fspec); if (filter != null) { preFilterList.add(filter); } } else { if (filter != null) { facetHitCollector._filter = filter; } } } else { if (filter != null) { preFilterList.add(filter); } } } } if (facetHitCollector != null) {//对每一个设置了FacetSpec的facet,都有一个FacetHitCollector,将它们整理到一个list中 facetHitCollectorList.add(facetHitCollector); } }
类FacetValidator是基类,_collectors是BoboSubBrowser维护的List<FacetHitCollector>列表赋值过来的,也就是上面代码
facetHitCollectorList.add(facetHitCollector);
中的facetHitCollectorList
下边看一下FacetValidator类用于针对于不同的IndexReader进行初始化的函数:
abstract static class FacetValidator { public void setNextReader(BoboIndexReader reader,int docBase) throws IOException{ ArrayList<FacetCountCollector> collectorList = new ArrayList<FacetCountCollector>(); sortPostCollectors(reader); for (int i=0;i<_collectors.length;++i){ //对每个Facet对应的FacetHitCollector进行初始化工作,下面会提到 _collectors[i].setNextReader(reader, docBase); FacetCountCollector collector = _collectors[i]._currentPointers.facetCountCollector; if(collector != null) { collectorList.add(collector); } } _countCollectors = collectorList.toArray(new FacetCountCollector[collectorList.size()]); } }
接下来看一下FacetHitCollector这个类,其成员FacetCountCollectorSource用于创建 FacetCountCollector。那么FacetCountCollector是用来做什么的呢?它主要是用于统计在搜索结果以及过滤条件下,在 每个facet下每一个属性(对于设置了selection的facet,只有过滤条件对应的属性count才有值)所命中的文档的个数 ,其函数SetNextReader由FacetValidator的setNextReader函数调用:
public final class FacetHitCollector{ public FacetCountCollectorSource _facetCountCollectorSource;//分组计数器的产生器 public FacetCountCollectorSource _collectAllSource = null; public FacetHandler<?> facetHandler;//该分组计数器对应的Facet public RandomAccessFilter _filter; public final CurrentPointers _currentPointers = new CurrentPointers(); // public LinkedList<FacetCountCollector> _countCollectorList = new LinkedList<FacetCountCollector>(); public LinkedList<FacetCountCollector> _collectAllCollectorList = new LinkedList<FacetCountCollector>(); public void setNextReader(BoboIndexReader reader,int docBase) throws IOException{ if (_collectAllSource!=null){ FacetCountCollector collector = _collectAllSource.getFacetCountCollector(reader, docBase); _collectAllCollectorList.add(collector); collector.collectAll(); } else{ if (_filter!=null){ _currentPointers.docidSet = _filter.getRandomAccessDocIdSet(reader); _currentPointers.postDocIDSetIterator = _currentPointers.docidSet.iterator(); _currentPointers.doc = _currentPointers.postDocIDSetIterator.nextDoc(); } if (_facetCountCollectorSource!=null){ //根据产生器创建分组计数器FacetCountCollector,并把它赋给_currentPointers(当前Reader的配置) _currentPointers.facetCountCollector = _facetCountCollectorSource.getFacetCountCollector(reader, docBase); //同一个facet下,每一个IndexReader的facetCountCollector都被记录起来,放到一个list中,收集计数的时候用来做合并 _countCollectorList.add(_currentPointers.facetCountCollector); } } } //当前的IndexReader下对应的一些配置,每个IndexReader下使用的分组计数器都是不同的 public static class CurrentPointers{ public RandomAccessDocIdSet docidSet=null; public DocIdSetIterator postDocIDSetIterator = null; public int doc; public FacetCountCollector facetCountCollector; } }
FacetValidator的validate(docid)用于对facet进行分组计数:
通常FacetSpec默认设置ExpandSelection为false ,那么CreateFacetValidator ()返回的是 new NoNeedFavalidator (FacetHitCollector[]),其validate()函数如下:
@Override
public final boolean validate(int docid) throws IOException {
for (FacetCountCollector collector : _countCollectors){
collector.collect(docid);
}
return true;
}
分组计数器的基类是FacetCountCollector,只定义了几个接口,它的abstract子类:
public abstract class DefaultFacetCountCollector implements FacetCountCollector { protected final FacetSpec _ospec; public int[] _count;//存放计数结果的int数组,长度对应于FacetDataCache中的freqs[],也就是属性的个数 public int _countlength;//计数数组长度 protected FacetDataCache _dataCache;//facet的缓存数据 private final String _name;//facet的名称 protected final BrowseSelection _sel;//过滤条件 protected final BigSegmentedArray _array;//<docid , index> 的映射 }
具体的FacetCountCollector实现类 ,有很多实现,这里只看一下常用的SimpleFacetCountCollector :
public static final class SimpleFacetCountCollector extends DefaultFacetCountCollector { public SimpleFacetCountCollector(String name,FacetDataCache dataCache,int docBase,BrowseSelection sel,FacetSpec ospec) { super(name,dataCache,docBase,sel,ospec); } //主要函数 public final void collect(int docid) { //根据docid,查到index,再将该属性的计数加一 _count[_array.get(docid)]++; } public final void collectAll() { _count = _dataCache.freqs; } }