package org.fastcatsearch.ir.search; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.fastcatsearch.ir.group.GroupsData; import org.fastcatsearch.ir.group.GroupDataMerger; import org.fastcatsearch.ir.io.FixedHitQueue; import org.fastcatsearch.ir.io.FixedHitReader; import org.fastcatsearch.ir.io.FixedMinHeap; import org.fastcatsearch.ir.query.Bundle; import org.fastcatsearch.ir.query.Groups; import org.fastcatsearch.ir.query.Metadata; import org.fastcatsearch.ir.query.Query; import org.fastcatsearch.ir.query.InternalSearchResult; import org.fastcatsearch.ir.query.Sorts; import org.fastcatsearch.ir.settings.Schema; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SearchResultAggregator { protected static Logger logger = LoggerFactory.getLogger(SearchResultAggregator.class); private Schema schema; private Query q; public SearchResultAggregator(Query q, Schema schema){ this.q = q; this.schema = schema; } public InternalSearchResult aggregate(List<InternalSearchResult> resultList) { int mergeSize = resultList.size(); if(mergeSize == 0){ //에러상황. return null; }else if(mergeSize == 1){ //머징할것이 없는 경우 그대로 리턴. return resultList.get(0); } else { Groups groups = q.getGroups(); Sorts sorts = q.getSorts(); Metadata meta = q.getMeta(); int start = meta.start(); int rows = meta.rows(); int totalCount = 0; int count = 0; GroupDataMerger dataMerger = null; if(groups != null){ dataMerger = new GroupDataMerger(groups, mergeSize); } //정렬을 다시한번 수행해서 top N을 뽑는다. FixedMinHeap<FixedHitReader> hitMerger = null; if(sorts != null){ try { hitMerger = sorts.createMerger(schema, mergeSize); } catch (IOException e) { logger.error("Merger생성중 에러발생.", e); return null; } }else{ hitMerger = new FixedMinHeap<FixedHitReader>(mergeSize); } List<Explanation> explanationList = null; for (int i = 0; i < resultList.size(); i++) { InternalSearchResult result = resultList.get(i); totalCount += result.getTotalCount(); FixedHitReader hitReader = result.getFixedHitReader(); //posting data if(hitReader.next()){ hitMerger.push(hitReader); } GroupsData groupData = result.getGroupsData(); if(groupData != null){ //Put GroupResult dataMerger.put(groupData); } if(result.getExplanations() != null){ if(explanationList == null){ explanationList = new ArrayList<Explanation>(); } for(Explanation exp : result.getExplanations()){ exp.setNodeId(result.getNodeId()); explanationList.add(exp); } } } //각 shard의 결과들을 rankdata를 기준으로 재정렬한다. FixedHitQueue totalHit = new FixedHitQueue(rows); int c = 1; while(hitMerger.size() > 0){ FixedHitReader r = hitMerger.peek(); HitElement el = r.read(); if(c >= start){ totalHit.push(el); count++; } c++; //결과가 만들어졌으면 일찍 끝낸다. if(count == rows) break; if(!r.next()){ //다 읽은 것은 버린다. hitMerger.pop(); } hitMerger.heapify(); } GroupsData groupData = null; if(dataMerger != null){ groupData = dataMerger.merge(); } return new InternalSearchResult(totalHit.getHitElementList(), count, totalCount, groupData, explanationList); } } }