Bobo源码笔记4(collector的创建)
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自己的ComparatorBoboCustomSortField 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 relevancecompSource = 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 fieldcompSource = 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; }??
?
?
?