Bobo的收集器基类是SortCollector继承于lucene的Collector类,其中函数是获取收集器的外部接口:
public static SortCollector buildSortCollector(Browsable browser,Query q,SortField[] sort,int offset,int count,boolean forceScoring,boolean fetchStoredFields){
boolean doScoring=forceScoring;
if (sort == null || sort.length==0){
if (q!=null && !(q instanceof MatchAllDocsQuery)){
sort = new SortField[]{SortField.FIELD_SCORE};
}
}
if (sort==null || sort.length==0){
sort = new SortField[]{SortField.FIELD_DOC};
}
Set<String> facetNames = browser.getFacetNames();
for (SortField sf : sort){
if (sf.getType() == SortField.SCORE) {
doScoring= true;
break;
}
}
DocComparatorSource compSource;
if (sort.length==1){
//对sort[]记性转换
SortField sf = convert(browser,sort[0]);
compSource = getComparatorSource(browser,sf);
}
else{
DocComparatorSource[] compSources = new DocComparatorSource[sort.length];
for (int i = 0; i<sort.length;++i){
compSources[i]=getComparatorSource(browser,convert(browser,sort[i]));
}
//可以对结果以多个field进行排序,排序的优先级由sort[]中的位置确定,例:sort[0]优先于sort[1]
compSource = new MultiDocIdComparatorSource(compSources);
}
return new SortCollectorImpl(compSource, sort, browser, offset, count, doScoring, fetchStoredFields);
}
其中convert(browsable , sortField[])函数是对sortField进行转换,如果有该field的facetHandler,那么就必须使用该facetHandler自定义的Comparator(比较器)进行收集(collect):
private static SortField convert(Browsable browser,SortField sort){
String field =sort.getField();
FacetHandler<?> facetHandler = browser.getFacetHandler(field);
if (facetHandler!=null){
//有该sortField所在域的FacetHandler的时候使用facet自己的Comparator
BoboCustomSortField sortField = new BoboCustomSortField(field, sort.getReverse(), facetHandler.getDocComparatorSource());
return sortField;
}
else{
return sort;
}
}
上面的转换的影响从下边函数里可以体现出来,上面有facet的SortField被转换成BoboCustomSortField,在下面函数中
if (sf instanceof BoboCustomSortField){
BoboCustomSortField custField = (BoboCustomSortField)sf;
DocComparatorSource src = custField.getCustomComparatorSource();
assert src!=null;
compSource = src;
}
使用了facetHandler的比较器的产生器来生产Comparator
private static DocComparatorSource getComparatorSource(Browsable browser,SortField sf){
DocComparatorSource compSource = null;
//按照文档的id进行排序收集
if (SortField.FIELD_DOC.equals(sf)){
compSource = new DocIdDocComparatorSource();
}//按照文档的得分进行收集
else if (SortField.FIELD_SCORE.equals(sf) || sf.getType() == SortField.SCORE){
// we want to do reverse sorting regardless for relevance
compSource = new ReverseDocComparatorSource(new RelevanceDocComparatorSource());
}
else if (sf instanceof BoboCustomSortField){
BoboCustomSortField custField = (BoboCustomSortField)sf;
DocComparatorSource src = custField.getCustomComparatorSource();
assert src!=null;
compSource = src;
}
else{
Set<String> facetNames = browser.getFacetNames();
String sortName = sf.getField();
if (facetNames.contains(sortName)){
FacetHandler<?> handler = browser.getFacetHandler(sortName);
assert handler!=null;
compSource = handler.getDocComparatorSource();
}
else{ // default lucene field
compSource = getNonFacetComparatorSource(sf);
}
}
boolean reverse = sf.getReverse();
if (reverse){
compSource = new ReverseDocComparatorSource(compSource);
}
compSource.setReverse(reverse);
return compSource;
}
SortCollectorImpl是sortCollector类的一个实现类,实现Collector类的接口SetNextReader()函数:
@Override
public void setNextReader(IndexReader reader, int docBase) throws IOException {
assert reader instanceof BoboIndexReader;
_currentReader = (BoboIndexReader)reader;
//得到当前Reader下的比较器
_currentComparator = _compSource.getComparator(reader,docBase);
//用于收集当前Reader搜索结果的最小堆,用上面的比较器
_currentQueue = new DocIDPriorityQueue(_currentComparator, _numHits, docBase);
MyScoreDoc myScoreDoc = (MyScoreDoc)_tmpScoreDoc;
myScoreDoc.queue = _currentQueue;
myScoreDoc.reader = _currentReader;
myScoreDoc.sortValue = null;
_pqList.add(_currentQueue);
_queueFull = false;
}
最后对多个IndexReader的结果进行merge(合并)
@Override
public BrowseHit[] topDocs() throws IOException{
ArrayList<Iterator<MyScoreDoc>> iterList = new ArrayList<Iterator<MyScoreDoc>>(_pqList.size());
for (DocIDPriorityQueue pq : _pqList){
int count = pq.size();
MyScoreDoc[] resList = new MyScoreDoc[count];
for (int i = count - 1; i >= 0; i--) {
resList[i] = (MyScoreDoc)pq.pop();
}
//将每个IndexReader的结果从最小堆转移到List中,将每个List的iterator添加到一个List<iterator>中去
iterList.add(Arrays.asList(resList).iterator());
}
//对多个IndexReader的搜索结果队列进行多路归并
ArrayList<MyScoreDoc> resList = ListMerger.mergeLists(_offset, _count, iterList, MERGE_COMPATATOR);
Map<String,FacetHandler<?>> facetHandlerMap = _boboBrowser.getFacetHandlerMap();
return buildHits(resList.toArray(new MyScoreDoc[resList.size()]), _sortFields, facetHandlerMap, _fetchStoredFields);
}
//将搜索结果转换成BrowseHit
protected static BrowseHit[] buildHits(MyScoreDoc[] scoreDocs,SortField[] sortFields,Map<String,FacetHandler<?>> facetHandlerMap,boolean fetchStoredFields)
throws IOException
{
BrowseHit[] hits = new BrowseHit[scoreDocs.length];
Collection<FacetHandler<?>> facetHandlers= facetHandlerMap.values();
for (int i =scoreDocs.length-1; i >=0 ; i--)
{
MyScoreDoc fdoc = scoreDocs[i];
BoboIndexReader reader = fdoc.reader;
BrowseHit hit=new BrowseHit();
if (fetchStoredFields){
hit.setStoredFields(reader.document(fdoc.doc));
}
Map<String,String[]> map = new HashMap<String,String[]>();
Map<String,Object[]> rawMap = new HashMap<String,Object[]>();
for (FacetHandler<?> facetHandler : facetHandlers)
{
map.put(facetHandler.getName(),facetHandler.getFieldValues(reader,fdoc.doc));
rawMap.put(facetHandler.getName(),facetHandler.getRawFieldValues(reader,fdoc.doc));
}
hit.setFieldValues(map);
hit.setRawFieldValues(rawMap);
hit.setDocid(fdoc.doc+fdoc.queue.base);
hit.setScore(fdoc.score);
hit.setComparable(fdoc.getValue());
hits[i] = hit;
}
return hits;
}