Index: src/java/org/apache/lucene/search/FieldDocSortedHitQueue.java =================================================================== --- src/java/org/apache/lucene/search/FieldDocSortedHitQueue.java (revision 721755) +++ src/java/org/apache/lucene/search/FieldDocSortedHitQueue.java (working copy) @@ -93,6 +93,9 @@ return ret; } + protected FieldDoc asFieldDoc (Object obj) { + return (FieldDoc)obj; + } /** * Returns whether a is less relevant than b. @@ -100,9 +103,9 @@ * @param b ScoreDoc * @return true if document a should be sorted after document b. */ - protected final boolean lessThan (final Object a, final Object b) { - final FieldDoc docA = (FieldDoc) a; - final FieldDoc docB = (FieldDoc) b; + protected boolean lessThan (final Object a, final Object b) { + final FieldDoc docA = asFieldDoc(a); + final FieldDoc docB = asFieldDoc(b); final int n = fields.length; int c = 0; for (int i=0; i hitB.score; + } + } + } + public TopDocs search(Weight weight, Filter filter, int nDocs) throws IOException { - HitQueue hq = new HitQueue(nDocs); + SubsearcherHitQueue shq = new SubsearcherHitQueue(searchables.length); int totalHits = 0; for (int i = 0; i < searchables.length; i++) { // search each searcher TopDocs docs = searchables[i].search(weight, filter, nDocs); totalHits += docs.totalHits; // update totalHits - ScoreDoc[] scoreDocs = docs.scoreDocs; - for (int j = 0; j < scoreDocs.length; j++) { // merge scoreDocs into hq - ScoreDoc scoreDoc = scoreDocs[j]; - scoreDoc.doc += starts[i]; // convert doc - if(!hq.insert(scoreDoc)) - break; // no more scores > minScore + if (docs.totalHits > 0) { + final SubsearcherTopDocs subsearcherTopDocs = new SubsearcherTopDocs(docs, i); + subsearcherTopDocs.convertTopDoc(starts); + shq.put(subsearcherTopDocs); } } - ScoreDoc[] scoreDocs = new ScoreDoc[hq.size()]; - for (int i = hq.size()-1; i >= 0; i--) // put docs in array - scoreDocs[i] = (ScoreDoc)hq.pop(); - + // merge top nDocs sorted results into scoreDocs + ScoreDoc[] scoreDocs = new ScoreDoc[Math.min(totalHits, nDocs)]; + + for (int i = 0; i < scoreDocs.length; i++) { + // using the top(), top().change(), adjustTop() optimized form + final SubsearcherTopDocs topSubsearcherHits = (SubsearcherTopDocs) shq.top(); + final ScoreDoc topDoc = topSubsearcherHits.topDoc(); + scoreDocs[i] = topDoc; + + topSubsearcherHits.hitIdx++; + + if (topSubsearcherHits.hasNext()) { + topSubsearcherHits.convertTopDoc(starts); + shq.adjustTop(); + } else { + shq.pop(); + } + } + float maxScore = (totalHits==0) ? Float.NEGATIVE_INFINITY : scoreDocs[0].score; - + return new TopDocs(totalHits, scoreDocs, maxScore); } + static class SubsearcherFieldDocSortedHitQueue extends FieldDocSortedHitQueue { + SubsearcherFieldDocSortedHitQueue(SortField[] fields, int size) { + super(fields, size); + } + + protected FieldDoc asFieldDoc (Object obj) { + final SubsearcherTopDocs subsearcherTopDocs = (SubsearcherTopDocs)obj; + final FieldDoc hit = (FieldDoc) subsearcherTopDocs.topDoc(); + return hit; + } + + protected boolean lessThan(Object a, Object b) { + boolean c = super.lessThan(a, b); + // invert lessThan to make a max top queue + return ! c; + } + } + public TopFieldDocs search (Weight weight, Filter filter, int n, Sort sort) throws IOException { - FieldDocSortedHitQueue hq = null; + SubsearcherFieldDocSortedHitQueue shq = null; int totalHits = 0; - float maxScore=Float.NEGATIVE_INFINITY; - for (int i = 0; i < searchables.length; i++) { // search each searcher - TopFieldDocs docs = searchables[i].search (weight, filter, n, sort); - - if (hq == null) hq = new FieldDocSortedHitQueue (docs.fields, n); + TopFieldDocs docs = searchables[i].search(weight, filter, n, sort); totalHits += docs.totalHits; // update totalHits - maxScore = Math.max(maxScore, docs.getMaxScore()); - ScoreDoc[] scoreDocs = docs.scoreDocs; - for (int j = 0; j < scoreDocs.length; j++) { // merge scoreDocs into hq - ScoreDoc scoreDoc = scoreDocs[j]; - scoreDoc.doc += starts[i]; // convert doc - if (!hq.insert (scoreDoc)) - break; // no more scores > minScore + if (docs.totalHits > 0) { + if (shq == null) shq = new SubsearcherFieldDocSortedHitQueue (docs.fields, n); + final SubsearcherTopDocs subsearcherTopDocs = new SubsearcherTopDocs(docs, i); + subsearcherTopDocs.convertTopDoc(starts); + shq.put(subsearcherTopDocs); } } - ScoreDoc[] scoreDocs = new ScoreDoc[hq.size()]; - for (int i = hq.size() - 1; i >= 0; i--) // put docs in array - scoreDocs[i] = (ScoreDoc) hq.pop(); + // merge top nDocs sorted results into scoreDocs + ScoreDoc[] scoreDocs = new ScoreDoc[Math.min(totalHits, n)]; - return new TopFieldDocs (totalHits, scoreDocs, hq.getFields(), maxScore); + for (int i = 0; i < scoreDocs.length; i++) { + // using the top(), top().change(), adjustTop() optimized form + final SubsearcherTopDocs topSubsearcherHits = (SubsearcherTopDocs) shq.top(); + final ScoreDoc topDoc = topSubsearcherHits.topDoc(); + scoreDocs[i] = topDoc; + + topSubsearcherHits.hitIdx++; + + if (topSubsearcherHits.hasNext()) { + topSubsearcherHits.convertTopDoc(starts); + shq.adjustTop(); + } else { + shq.pop(); + } + } + + float maxScore = (totalHits==0) ? Float.NEGATIVE_INFINITY : scoreDocs[0].score; + + return new TopFieldDocs(totalHits, scoreDocs, shq.getFields(), maxScore); }