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