Index: lucene/contrib/queries/src/test/org/apache/lucene/search/TestSlowCollationMethods.java --- lucene/contrib/queries/src/test/org/apache/lucene/search/TestSlowCollationMethods.java Mon Feb 28 08:24:50 2011 -0500 +++ lucene/contrib/queries/src/test/org/apache/lucene/search/TestSlowCollationMethods.java Mon Feb 28 11:41:31 2011 -0500 @@ -62,10 +62,7 @@ reader = iw.getReader(); iw.close(); - // TODO: we should be able to use newSearcher, but custom sorts are broken if IS has an executorservice - // see LUCENE-2941 - //searcher = newSearcher(reader); - searcher = new IndexSearcher(reader); + searcher = newSearcher(reader); } @AfterClass Index: lucene/src/java/org/apache/lucene/search/FieldDocSortedHitQueue.java --- lucene/src/java/org/apache/lucene/search/FieldDocSortedHitQueue.java Mon Feb 28 08:24:50 2011 -0500 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -package org.apache.lucene.search; - -/** - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import org.apache.lucene.util.PriorityQueue; -import org.apache.lucene.util.BytesRef; - -/** - * Expert: Collects sorted results from Searchable's and collates them. - * The elements put into this queue must be of type FieldDoc. - * - *

Created: Feb 11, 2004 2:04:21 PM - * - * @since lucene 1.4 - */ -class FieldDocSortedHitQueue extends PriorityQueue { - - volatile SortField[] fields = null; - - /** - * Creates a hit queue sorted by the given list of fields. - * @param fields Fieldable names, in priority order (highest priority first). - * @param size The number of hits to retain. Must be greater than zero. - */ - FieldDocSortedHitQueue (int size) { - initialize (size); - } - - - /** - * Allows redefinition of sort fields if they are null. - * This is to handle the case using ParallelMultiSearcher where the - * original list contains AUTO and we don't know the actual sort - * type until the values come back. The fields can only be set once. - * This method should be synchronized external like all other PQ methods. - * @param fields - */ - void setFields (SortField[] fields) { - this.fields = fields; - } - - - /** Returns the fields being used to sort. */ - SortField[] getFields() { - return fields; - } - - /** - * Returns whether a is less relevant than b. - * @param a ScoreDoc - * @param b ScoreDoc - * @return true if document a should be sorted after document b. - */ - @SuppressWarnings("unchecked") @Override - protected final boolean lessThan(final FieldDoc docA, final FieldDoc docB) { - final int n = fields.length; - int c = 0; - for (int i=0; i docB.doc; - - return c > 0; - } -} Index: lucene/src/java/org/apache/lucene/search/IndexSearcher.java --- lucene/src/java/org/apache/lucene/search/IndexSearcher.java Mon Feb 28 08:24:50 2011 -0500 +++ lucene/src/java/org/apache/lucene/search/IndexSearcher.java Mon Feb 28 11:41:31 2011 -0500 @@ -442,13 +442,17 @@ // use all leaves here! return search (leafContexts, weight, filter, nDocs, sort, fillFields); } else { - // TODO: make this respect fillFields - final FieldDocSortedHitQueue hq = new FieldDocSortedHitQueue(nDocs); + final TopFieldCollector topCollector = TopFieldCollector.create(sort, nDocs, + fillFields, + fieldSortDoTrackScores, + fieldSortDoMaxScore, + false); + final Lock lock = new ReentrantLock(); final ExecutionHelper runner = new ExecutionHelper(executor); for (int i = 0; i < leafSlices.length; i++) { // search each leaf slice runner.submit( - new SearcherCallableWithSort(lock, this, leafSlices[i], weight, filter, nDocs, hq, sort)); + new SearcherCallableWithSort(lock, this, leafSlices[i], weight, filter, nDocs, topCollector, sort)); } int totalHits = 0; float maxScore = Float.NEGATIVE_INFINITY; @@ -458,11 +462,10 @@ maxScore = Math.max(maxScore, topFieldDocs.getMaxScore()); } } - final ScoreDoc[] scoreDocs = new ScoreDoc[hq.size()]; - for (int i = hq.size() - 1; i >= 0; i--) // put docs in array - scoreDocs[i] = hq.pop(); - return new TopFieldDocs(totalHits, scoreDocs, hq.getFields(), maxScore); + final TopFieldDocs topDocs = (TopFieldDocs) topCollector.topDocs(); + + return new TopFieldDocs(totalHits, topDocs.scoreDocs, topDocs.fields, topDocs.getMaxScore()); } } @@ -721,12 +724,12 @@ private final Weight weight; private final Filter filter; private final int nDocs; - private final FieldDocSortedHitQueue hq; + private final TopFieldCollector hq; private final Sort sort; private final LeafSlice slice; public SearcherCallableWithSort(Lock lock, IndexSearcher searcher, LeafSlice slice, Weight weight, - Filter filter, int nDocs, FieldDocSortedHitQueue hq, Sort sort) { + Filter filter, int nDocs, TopFieldCollector hq, Sort sort) { this.lock = lock; this.searcher = searcher; this.weight = weight; @@ -737,27 +740,58 @@ this.slice = slice; } + private final class FakeScorer extends Scorer { + float score; + int doc; + + public FakeScorer() { + super(null); + } + + @Override + public int advance(int target) { + throw new UnsupportedOperationException(); + } + + @Override + public int docID() { + return doc; + } + + @Override + public float freq() { + throw new UnsupportedOperationException(); + } + + @Override + public int nextDoc() { + throw new UnsupportedOperationException(); + } + + @Override + public float score() { + return score; + } + } + + private final FakeScorer fakeScorer = new FakeScorer(); + public TopFieldDocs call() throws IOException { + assert slice.leaves.length == 1; final TopFieldDocs docs = searcher.search (slice.leaves, weight, filter, nDocs, sort, true); lock.lock(); try { - hq.setFields(docs.fields); + final int base = slice.leaves[0].docBase; + hq.setNextReader(slice.leaves[0]); + hq.setScorer(fakeScorer); + for(ScoreDoc scoreDoc : docs.scoreDocs) { + fakeScorer.doc = scoreDoc.doc - base; + fakeScorer.score = scoreDoc.score; + hq.collect(scoreDoc.doc-base); + } } finally { lock.unlock(); } - - final ScoreDoc[] scoreDocs = docs.scoreDocs; - for (int j = 0; j < scoreDocs.length; j++) { // merge scoreDocs into hq - final FieldDoc fieldDoc = (FieldDoc) scoreDocs[j]; - //it would be so nice if we had a thread-safe insert - lock.lock(); - try { - if (fieldDoc == hq.insertWithOverflow(fieldDoc)) - break; - } finally { - lock.unlock(); - } - } return docs; } } Index: lucene/src/test/org/apache/lucene/search/TestSort.java --- lucene/src/test/org/apache/lucene/search/TestSort.java Mon Feb 28 08:24:50 2011 -0500 +++ lucene/src/test/org/apache/lucene/search/TestSort.java Mon Feb 28 11:41:31 2011 -0500 @@ -495,13 +495,15 @@ bottomValue = slotValues[bottom]; } + private static final FieldCache.IntParser testIntParser = new FieldCache.IntParser() { + public final int parseInt(final BytesRef term) { + return (term.bytes[term.offset]-'A') * 123456; + } + }; + @Override public FieldComparator setNextReader(AtomicReaderContext context) throws IOException { - docValues = FieldCache.DEFAULT.getInts(context.reader, "parser", new FieldCache.IntParser() { - public final int parseInt(final BytesRef term) { - return (term.bytes[term.offset]-'A') * 123456; - } - }); + docValues = FieldCache.DEFAULT.getInts(context.reader, "parser", testIntParser); return this; }