You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-commits@lucene.apache.org by mi...@apache.org on 2009/04/13 20:33:58 UTC
svn commit: r764551 [1/3] - in /lucene/java/trunk: ./
contrib/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/
contrib/miscellaneous/src/test/org/apache/lucene/index/
contrib/miscellaneous/src/test/org/apache/lucene/misc/ contrib/spatial/sr...
Author: mikemccand
Date: Mon Apr 13 18:33:56 2009
New Revision: 764551
URL: http://svn.apache.org/viewvc?rev=764551&view=rev
Log:
LUCENE-1575: switch to new Collector API
Added:
lucene/java/trunk/src/java/org/apache/lucene/search/Collector.java
lucene/java/trunk/src/java/org/apache/lucene/search/HitCollectorWrapper.java
lucene/java/trunk/src/java/org/apache/lucene/search/PositiveScoresOnlyCollector.java
lucene/java/trunk/src/java/org/apache/lucene/search/ScoreCachingWrappingScorer.java
lucene/java/trunk/src/java/org/apache/lucene/search/TimeLimitingCollector.java
lucene/java/trunk/src/java/org/apache/lucene/search/TopDocsCollector.java
lucene/java/trunk/src/test/org/apache/lucene/search/JustCompileSearch.java
lucene/java/trunk/src/test/org/apache/lucene/search/TestPositiveScoresOnlyCollector.java
lucene/java/trunk/src/test/org/apache/lucene/search/TestScoreCachingWrappingScorer.java
lucene/java/trunk/src/test/org/apache/lucene/search/TestTimeLimitingCollector.java
lucene/java/trunk/src/test/org/apache/lucene/search/TestTopDocsCollector.java
lucene/java/trunk/src/test/org/apache/lucene/search/function/JustCompileSearchSpans.java
lucene/java/trunk/src/test/org/apache/lucene/search/spans/JustCompileSearchSpans.java
Removed:
lucene/java/trunk/src/java/org/apache/lucene/search/MultiReaderHitCollector.java
Modified:
lucene/java/trunk/CHANGES.txt
lucene/java/trunk/contrib/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/ReadTask.java
lucene/java/trunk/contrib/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/SearchWithSortTask.java
lucene/java/trunk/contrib/miscellaneous/src/test/org/apache/lucene/index/TestFieldNormModifier.java
lucene/java/trunk/contrib/miscellaneous/src/test/org/apache/lucene/misc/TestLengthNormModifier.java
lucene/java/trunk/contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceFieldComparatorSource.java
lucene/java/trunk/src/java/org/apache/lucene/search/BooleanScorer.java
lucene/java/trunk/src/java/org/apache/lucene/search/BooleanScorer2.java
lucene/java/trunk/src/java/org/apache/lucene/search/DisjunctionSumScorer.java
lucene/java/trunk/src/java/org/apache/lucene/search/FieldComparator.java
lucene/java/trunk/src/java/org/apache/lucene/search/FieldComparatorSource.java
lucene/java/trunk/src/java/org/apache/lucene/search/FieldValueHitQueue.java
lucene/java/trunk/src/java/org/apache/lucene/search/HitCollector.java
lucene/java/trunk/src/java/org/apache/lucene/search/IndexSearcher.java
lucene/java/trunk/src/java/org/apache/lucene/search/MultiSearcher.java
lucene/java/trunk/src/java/org/apache/lucene/search/ParallelMultiSearcher.java
lucene/java/trunk/src/java/org/apache/lucene/search/QueryWrapperFilter.java
lucene/java/trunk/src/java/org/apache/lucene/search/RemoteSearchable.java
lucene/java/trunk/src/java/org/apache/lucene/search/Scorer.java
lucene/java/trunk/src/java/org/apache/lucene/search/Searchable.java
lucene/java/trunk/src/java/org/apache/lucene/search/Searcher.java
lucene/java/trunk/src/java/org/apache/lucene/search/SortField.java
lucene/java/trunk/src/java/org/apache/lucene/search/TermScorer.java
lucene/java/trunk/src/java/org/apache/lucene/search/TimeLimitedCollector.java
lucene/java/trunk/src/java/org/apache/lucene/search/TopDocs.java
lucene/java/trunk/src/java/org/apache/lucene/search/TopFieldCollector.java
lucene/java/trunk/src/java/org/apache/lucene/search/TopFieldDocCollector.java
lucene/java/trunk/src/java/org/apache/lucene/search/TopScoreDocCollector.java
lucene/java/trunk/src/test/org/apache/lucene/index/TestIndexReader.java
lucene/java/trunk/src/test/org/apache/lucene/index/TestOmitTf.java
lucene/java/trunk/src/test/org/apache/lucene/search/CheckHits.java
lucene/java/trunk/src/test/org/apache/lucene/search/QueryUtils.java
lucene/java/trunk/src/test/org/apache/lucene/search/TestDocBoost.java
lucene/java/trunk/src/test/org/apache/lucene/search/TestMultiTermConstantScore.java
lucene/java/trunk/src/test/org/apache/lucene/search/TestScorerPerf.java
lucene/java/trunk/src/test/org/apache/lucene/search/TestSetNorm.java
lucene/java/trunk/src/test/org/apache/lucene/search/TestSimilarity.java
lucene/java/trunk/src/test/org/apache/lucene/search/TestSort.java
lucene/java/trunk/src/test/org/apache/lucene/search/TestTermScorer.java
lucene/java/trunk/src/test/org/apache/lucene/search/TestTimeLimitedCollector.java
Modified: lucene/java/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/java/trunk/CHANGES.txt?rev=764551&r1=764550&r2=764551&view=diff
==============================================================================
--- lucene/java/trunk/CHANGES.txt (original)
+++ lucene/java/trunk/CHANGES.txt Mon Apr 13 18:33:56 2009
@@ -3,6 +3,32 @@
======================= Trunk (not yet released) =======================
+Changes in backwards compatibility policy
+
+ 1. LUCENE-1575: Searchable.search(Weight, Filter, int, Sort)
+ currently tracks document scores (including maxScore), and sets
+ the score in each returned FieldDoc. However, in 3.0 it will stop
+ tracking document scores. If document scores tracking is still
+ needed, you can use Searchable.search(Weight, Filter, Collector)
+ and pass in a TopFieldCollector instance, using the following code
+ sample:
+
+ <code>
+ TopFieldCollector tfc = TopFieldCollector.create(sort, numHits, fillFields,
+ true /* trackDocScores */,
+ true /* trackMaxScore */);
+ searcher.search(weight, filter, tfc);
+ TopDocs results = tfc.topDocs();
+ </code>
+
+ Also, the method search(Weight, Filter, Collector) was added to
+ the Searchable interface and the Searcher abstract class, to
+ replace the deprecated HitCollector versions. If you either
+ implement Searchable or extend Searcher, you should change you
+ code to implement this method. If you already extend
+ IndexSearcher, no further changes are needed to use Collector.
+ (Shai Erera via Mike McCandless)
+
Changes in runtime behavior
1. LUCENE-1424: QueryParser now by default uses constant score query
@@ -10,6 +36,19 @@
already does so for RangeQuery, as well). Call
setConstantScoreRewrite(false) to revert to BooleanQuery rewriting
method. (Mark Miller via Mike McCandless)
+
+ 2. LUCENE-1575: As of 2.9, the core collectors as well as
+ IndexSearcher's search methods that return top N results, no
+ longer filter out zero scoring documents. If you rely on this
+ functionaliy you can use PositiveScoresOnlyCollector like this:
+
+ <code>
+ TopDocsCollector tdc = new TopScoreDocCollector(10);
+ Collector c = new PositiveScoresOnlyCollector(tdc);
+ searcher.search(query, c);
+ TopDocs hits = tdc.topDocs();
+ ...
+ </code>
API Changes
@@ -69,6 +108,14 @@
12. LUCENE-1500: Added new InvalidTokenOffsetsException to Highlighter methods
to denote issues when offsets in TokenStream tokens exceed the length of the
provided text. (Mark Harwood)
+
+13. LUCENE-1575: HitCollector is now deprecated in favor of a new
+ Collector abstract class. For easy migration, people can use
+ HitCollectorWrapper which translates (wraps) HitCollector into
+ Collector. Note that this class is also deprecated and will be
+ removed when HitCollector is removed. Also TimeLimitedCollector
+ is deprecated in favor of the new TimeLimitingCollector which
+ extends Collector. (Shai Erera via Mike McCandless)
Bug fixes
@@ -258,6 +305,12 @@
those segments that did not change, and also speeds up searches
that sort by relevance or by field values. (Mark Miller, Mike
McCandless)
+
+ 7. LUCENE-1575: The new Collector class decouples collect() from
+ score computation. Collector.setScorer is called to establish the
+ current Scorer in-use per segment. Collectors that require the
+ score should then call Scorer.score() per hit inside
+ collect(). (Shai Erera via Mike McCandless)
Documentation
Modified: lucene/java/trunk/contrib/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/ReadTask.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/contrib/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/ReadTask.java?rev=764551&r1=764550&r2=764551&view=diff
==============================================================================
--- lucene/java/trunk/contrib/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/ReadTask.java (original)
+++ lucene/java/trunk/contrib/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/ReadTask.java Mon Apr 13 18:33:56 2009
@@ -32,6 +32,7 @@
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.TopDocs;
+import org.apache.lucene.search.TopFieldCollector;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
@@ -62,7 +63,6 @@
public ReadTask(PerfRunData runData) {
super(runData);
}
-
public int doLogic() throws Exception {
int res = 0;
boolean closeReader = false;
@@ -102,7 +102,10 @@
final int numHits = numHits();
if (numHits > 0) {
if (sort != null) {
- hits = searcher.search(q, null, numHits, sort);
+ TopFieldCollector collector = TopFieldCollector.create(sort, numHits,
+ true, withScore(), withMaxScore());
+ searcher.search(q, collector);
+ hits = collector.topDocs();
} else {
hits = searcher.search(q, numHits);
}
@@ -180,6 +183,18 @@
*/
public abstract boolean withTraverse();
+ /** Whether scores should be computed (only useful with
+ * field sort) */
+ public boolean withScore() {
+ return true;
+ }
+
+ /** Whether maxScores should be computed (only useful with
+ * field sort) */
+ public boolean withMaxScore() {
+ return true;
+ }
+
/**
* Specify the number of hits to traverse. Tasks should override this if they want to restrict the number
* of hits that are traversed when {@link #withTraverse()} is true. Must be greater than 0.
Modified: lucene/java/trunk/contrib/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/SearchWithSortTask.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/contrib/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/SearchWithSortTask.java?rev=764551&r1=764550&r2=764551&view=diff
==============================================================================
--- lucene/java/trunk/contrib/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/SearchWithSortTask.java (original)
+++ lucene/java/trunk/contrib/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/SearchWithSortTask.java Mon Apr 13 18:33:56 2009
@@ -27,6 +27,8 @@
*/
public class SearchWithSortTask extends ReadTask {
+ private boolean doScore = true;
+ private boolean doMaxScore = true;
private Sort sort;
public SearchWithSortTask(PerfRunData runData) {
@@ -34,7 +36,12 @@
}
/**
- * SortFields: field:type,field:type
+ * SortFields: field:type,field:type[,noscore][,nomaxscore]
+ *
+ * If noscore is present, then we turn off score tracking
+ * in {@link org.apache.lucene.search.TopFieldCollector}.
+ * If nomaxscore is present, then we turn off maxScore tracking
+ * in {@link org.apache.lucene.search.TopFieldCollector}.
*
* name,byline:int,subject:auto
*
@@ -43,11 +50,18 @@
super.setParams(sortField);
String[] fields = sortField.split(",");
SortField[] sortFields = new SortField[fields.length];
+ int upto = 0;
for (int i = 0; i < fields.length; i++) {
String field = fields[i];
SortField sortField0;
if (field.equals("doc")) {
sortField0 = SortField.FIELD_DOC;
+ } else if (field.equals("noscore")) {
+ doScore = false;
+ continue;
+ } else if (field.equals("nomaxscore")) {
+ doMaxScore = false;
+ continue;
} else {
int index = field.lastIndexOf(":");
String fieldName;
@@ -62,7 +76,13 @@
int type = getType(typeString);
sortField0 = new SortField(fieldName, type);
}
- sortFields[i] = sortField0;
+ sortFields[upto++] = sortField0;
+ }
+
+ if (upto < sortFields.length) {
+ SortField[] newSortFields = new SortField[upto];
+ System.arraycopy(sortFields, 0, newSortFields, 0, upto);
+ sortFields = newSortFields;
}
this.sort = new Sort(sortFields);
}
@@ -107,6 +127,14 @@
return false;
}
+ public boolean withScore() {
+ return doScore;
+ }
+
+ public boolean withMaxScore() {
+ return doMaxScore;
+ }
+
public Sort getSort() {
if (sort == null) {
throw new IllegalStateException("No sort field was set");
Modified: lucene/java/trunk/contrib/miscellaneous/src/test/org/apache/lucene/index/TestFieldNormModifier.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/contrib/miscellaneous/src/test/org/apache/lucene/index/TestFieldNormModifier.java?rev=764551&r1=764550&r2=764551&view=diff
==============================================================================
--- lucene/java/trunk/contrib/miscellaneous/src/test/org/apache/lucene/index/TestFieldNormModifier.java (original)
+++ lucene/java/trunk/contrib/miscellaneous/src/test/org/apache/lucene/index/TestFieldNormModifier.java Mon Apr 13 18:33:56 2009
@@ -22,16 +22,18 @@
import junit.framework.TestCase;
+import org.apache.lucene.analysis.SimpleAnalyzer;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.index.IndexWriter.MaxFieldLength;
+import org.apache.lucene.search.Collector;
+import org.apache.lucene.search.DefaultSimilarity;
import org.apache.lucene.search.IndexSearcher;
-import org.apache.lucene.search.MultiReaderHitCollector;
+import org.apache.lucene.search.Scorer;
import org.apache.lucene.search.Similarity;
-import org.apache.lucene.search.DefaultSimilarity;
import org.apache.lucene.search.TermQuery;
-import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.store.Directory;
-import org.apache.lucene.analysis.SimpleAnalyzer;
-import org.apache.lucene.document.Document;
-import org.apache.lucene.document.Field;
+import org.apache.lucene.store.RAMDirectory;
/**
* Tests changing of field norms with a custom similarity and with fake norms.
@@ -52,12 +54,12 @@
/** inverts the normal notion of lengthNorm */
public static Similarity s = new DefaultSimilarity() {
public float lengthNorm(String fieldName, int numTokens) {
- return (float)numTokens;
+ return numTokens;
}
};
public void setUp() throws Exception {
- IndexWriter writer = new IndexWriter(store, new SimpleAnalyzer(), true);
+ IndexWriter writer = new IndexWriter(store, new SimpleAnalyzer(), true, MaxFieldLength.UNLIMITED);
for (int i = 0; i < NUM_DOCS; i++) {
Document d = new Document();
@@ -123,14 +125,19 @@
float lastScore = 0.0f;
// default similarity should put docs with shorter length first
- searcher.search(new TermQuery(new Term("field", "word")), new MultiReaderHitCollector() {
- private int docBase = -1;
- public final void collect(int doc, float score) {
- scores[doc + docBase] = score;
+ searcher.search(new TermQuery(new Term("field", "word")), new Collector() {
+ private int docBase = 0;
+ private Scorer scorer;
+
+ public final void collect(int doc) throws IOException {
+ scores[doc + docBase] = scorer.score();
}
public void setNextReader(IndexReader reader, int docBase) {
this.docBase = docBase;
}
+ public void setScorer(Scorer scorer) throws IOException {
+ this.scorer = scorer;
+ }
});
searcher.close();
@@ -147,14 +154,18 @@
// new norm (with default similarity) should put longer docs first
searcher = new IndexSearcher(store);
- searcher.search(new TermQuery(new Term("field", "word")), new MultiReaderHitCollector() {
- private int docBase = -1;
- public final void collect(int doc, float score) {
- scores[doc + docBase] = score;
+ searcher.search(new TermQuery(new Term("field", "word")), new Collector() {
+ private int docBase = 0;
+ private Scorer scorer;
+ public final void collect(int doc) throws IOException {
+ scores[doc + docBase] = scorer.score();
}
public void setNextReader(IndexReader reader, int docBase) {
this.docBase = docBase;
}
+ public void setScorer(Scorer scorer) throws IOException {
+ this.scorer = scorer;
+ }
});
searcher.close();
@@ -188,15 +199,18 @@
float lastScore = 0.0f;
// default similarity should return the same score for all documents for this query
- searcher.search(new TermQuery(new Term("untokfield", "20061212")), new MultiReaderHitCollector() {
- private int docBase = -1;
- private int lastMax;
- public final void collect(int doc, float score) {
- scores[doc + docBase] = score;
+ searcher.search(new TermQuery(new Term("untokfield", "20061212")), new Collector() {
+ private int docBase = 0;
+ private Scorer scorer;
+ public final void collect(int doc) throws IOException {
+ scores[doc + docBase] = scorer.score();
}
public void setNextReader(IndexReader reader, int docBase) {
this.docBase = docBase;
}
+ public void setScorer(Scorer scorer) throws IOException {
+ this.scorer = scorer;
+ }
});
searcher.close();
Modified: lucene/java/trunk/contrib/miscellaneous/src/test/org/apache/lucene/misc/TestLengthNormModifier.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/contrib/miscellaneous/src/test/org/apache/lucene/misc/TestLengthNormModifier.java?rev=764551&r1=764550&r2=764551&view=diff
==============================================================================
--- lucene/java/trunk/contrib/miscellaneous/src/test/org/apache/lucene/misc/TestLengthNormModifier.java (original)
+++ lucene/java/trunk/contrib/miscellaneous/src/test/org/apache/lucene/misc/TestLengthNormModifier.java Mon Apr 13 18:33:56 2009
@@ -17,21 +17,26 @@
* limitations under the License.
*/
+import java.io.IOException;
+
import junit.framework.TestCase;
-import org.apache.lucene.index.Term;
-import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.analysis.SimpleAnalyzer;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.index.FieldNormModifier;
import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.index.IndexWriter.MaxFieldLength;
+import org.apache.lucene.search.Collector;
+import org.apache.lucene.search.DefaultSimilarity;
import org.apache.lucene.search.IndexSearcher;
-import org.apache.lucene.search.MultiReaderHitCollector;
+import org.apache.lucene.search.Scorer;
import org.apache.lucene.search.Similarity;
-import org.apache.lucene.search.DefaultSimilarity;
import org.apache.lucene.search.TermQuery;
-import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.store.Directory;
-import org.apache.lucene.analysis.SimpleAnalyzer;
-import org.apache.lucene.document.Document;
-import org.apache.lucene.document.Field;
+import org.apache.lucene.store.RAMDirectory;
/**
* Tests changing the norms after changing the simularity
@@ -52,13 +57,12 @@
/** inverts the normal notion of lengthNorm */
public static Similarity s = new DefaultSimilarity() {
public float lengthNorm(String fieldName, int numTokens) {
- return (float)numTokens;
+ return numTokens;
}
};
public void setUp() throws Exception {
- IndexWriter writer = new
- IndexWriter(store, new SimpleAnalyzer(), true);
+ IndexWriter writer = new IndexWriter(store, new SimpleAnalyzer(), true, MaxFieldLength.UNLIMITED);
for (int i = 0; i < NUM_DOCS; i++) {
Document d = new Document();
@@ -79,9 +83,9 @@
}
public void testMissingField() {
- LengthNormModifier lnm = new LengthNormModifier(store, s);
+ FieldNormModifier fnm = new FieldNormModifier(store, s);
try {
- lnm.reSetNorms("nobodyherebutuschickens");
+ fnm.reSetNorms("nobodyherebutuschickens");
} catch (Exception e) {
assertNull("caught something", e);
}
@@ -100,9 +104,9 @@
r.close();
- LengthNormModifier lnm = new LengthNormModifier(store, s);
+ FieldNormModifier fnm = new FieldNormModifier(store, s);
try {
- lnm.reSetNorms("nonorm");
+ fnm.reSetNorms("nonorm");
} catch (Exception e) {
assertNull("caught something", e);
}
@@ -129,14 +133,18 @@
// default similarity should put docs with shorter length first
searcher = new IndexSearcher(store);
- searcher.search(new TermQuery(new Term("field", "word")), new MultiReaderHitCollector() {
- private int docBase = -1;
- public final void collect(int doc, float score) {
- scores[doc + docBase] = score;
+ searcher.search(new TermQuery(new Term("field", "word")), new Collector() {
+ private int docBase = 0;
+ private Scorer scorer;
+ public final void collect(int doc) throws IOException {
+ scores[doc + docBase] = scorer.score();
}
public void setNextReader(IndexReader reader, int docBase) {
this.docBase = docBase;
}
+ public void setScorer(Scorer scorer) throws IOException {
+ this.scorer = scorer;
+ }
});
searcher.close();
@@ -151,22 +159,26 @@
// override the norms to be inverted
Similarity s = new DefaultSimilarity() {
public float lengthNorm(String fieldName, int numTokens) {
- return (float)numTokens;
+ return numTokens;
}
};
- LengthNormModifier lnm = new LengthNormModifier(store, s);
- lnm.reSetNorms("field");
+ FieldNormModifier fnm = new FieldNormModifier(store, s);
+ fnm.reSetNorms("field");
// new norm (with default similarity) should put longer docs first
searcher = new IndexSearcher(store);
- searcher.search(new TermQuery(new Term("field", "word")), new MultiReaderHitCollector() {
- private int docBase = -1;
- public final void collect(int doc, float score) {
- scores[doc + docBase] = score;
+ searcher.search(new TermQuery(new Term("field", "word")), new Collector() {
+ private int docBase = 0;
+ private Scorer scorer;
+ public final void collect(int doc) throws IOException {
+ scores[doc + docBase] = scorer.score();
}
public void setNextReader(IndexReader reader, int docBase) {
this.docBase = docBase;
}
+ public void setScorer(Scorer scorer) throws IOException {
+ this.scorer = scorer;
+ }
});
searcher.close();
Modified: lucene/java/trunk/contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceFieldComparatorSource.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceFieldComparatorSource.java?rev=764551&r1=764550&r2=764551&view=diff
==============================================================================
--- lucene/java/trunk/contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceFieldComparatorSource.java (original)
+++ lucene/java/trunk/contrib/spatial/src/java/org/apache/lucene/spatial/tier/DistanceFieldComparatorSource.java Mon Apr 13 18:33:56 2009
@@ -21,7 +21,6 @@
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.search.Filter;
-import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.FieldComparator;
import org.apache.lucene.search.FieldComparatorSource;
import org.apache.lucene.search.SortField;
@@ -49,8 +48,7 @@
}
@Override
- public FieldComparator newComparator(String fieldname,
- IndexReader[] subReaders, int numHits, int sortPos, boolean reversed)
+ public FieldComparator newComparator(String fieldname, int numHits, int sortPos, boolean reversed)
throws IOException {
dsdlc = new DistanceScoreDocLookupComparator(distanceFilter, numHits);
return dsdlc;
@@ -87,7 +85,7 @@
}
@Override
- public int compareBottom(int doc, float score) {
+ public int compareBottom(int doc) {
final double v2 = distanceFilter.getDistance(doc);
if (bottom > v2) {
return 1;
@@ -98,7 +96,7 @@
}
@Override
- public void copy(int slot, int doc, float score) {
+ public void copy(int slot, int doc) {
values[slot] = distanceFilter.getDistance(doc);
}
Modified: lucene/java/trunk/src/java/org/apache/lucene/search/BooleanScorer.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/BooleanScorer.java?rev=764551&r1=764550&r2=764551&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/BooleanScorer.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/BooleanScorer.java Mon Apr 13 18:33:56 2009
@@ -80,11 +80,11 @@
public boolean done;
public boolean required = false;
public boolean prohibited = false;
- public MultiReaderHitCollector collector;
+ public Collector collector;
public SubScorer next;
public SubScorer(Scorer scorer, boolean required, boolean prohibited,
- MultiReaderHitCollector collector, SubScorer next)
+ Collector collector, SubScorer next)
throws IOException {
this.scorer = scorer;
this.done = !scorer.next();
@@ -128,18 +128,32 @@
private int end;
private Bucket current;
+ /** @deprecated use {@link #score(Collector)} instead. */
public void score(HitCollector hc) throws IOException {
next();
score(hc, Integer.MAX_VALUE);
}
+
+ public void score(Collector collector) throws IOException {
+ next();
+ score(collector, Integer.MAX_VALUE);
+ }
+ /** @deprecated use {@link #score(Collector, int)} instead. */
protected boolean score(HitCollector hc, int max) throws IOException {
+ return score(new HitCollectorWrapper(hc), max);
+ }
+
+ protected boolean score(Collector collector, int max) throws IOException {
if (coordFactors == null)
computeCoordFactors();
boolean more;
Bucket tmp;
+ BucketScorer bs = new BucketScorer();
+ // The internal loop will set the score and doc before calling collect.
+ collector.setScorer(bs);
do {
bucketTable.first = null;
@@ -158,7 +172,9 @@
}
if (current.coord >= minNrShouldMatch) {
- hc.collect(current.doc, current.score * coordFactors[current.coord]);
+ bs.score = current.score * coordFactors[current.coord];
+ bs.doc = current.doc;
+ collector.collect(current.doc);
}
}
@@ -210,8 +226,9 @@
end += BucketTable.SIZE;
for (SubScorer sub = scorers; sub != null; sub = sub.next) {
Scorer scorer = sub.scorer;
+ sub.collector.setScorer(scorer);
while (!sub.done && scorer.doc() < end) {
- sub.collector.collect(scorer.doc(), scorer.score());
+ sub.collector.collect(scorer.doc());
sub.done = !scorer.next();
}
if (!sub.done) {
@@ -237,6 +254,42 @@
Bucket next; // next valid bucket
}
+ // An internal class which is used in score(Collector, int) for setting the
+ // current score. This is required since Collector exposes a setScorer method
+ // and implementations that need the score will call scorer.score().
+ // Therefore the only methods that are implemented are score() and doc().
+ private static final class BucketScorer extends Scorer {
+
+ float score;
+ int doc;
+
+ public BucketScorer() {
+ super(null);
+ }
+
+
+ public Explanation explain(int doc) throws IOException {
+ return null;
+ }
+
+ public float score() throws IOException {
+ return score;
+ }
+
+ public int doc() {
+ return doc;
+ }
+
+ public boolean next() throws IOException {
+ return false;
+ }
+
+ public boolean skipTo(int target) throws IOException {
+ return false;
+ }
+
+ }
+
/** A simple hash table of document scores within a range. */
static final class BucketTable {
public static final int SIZE = 1 << 11;
@@ -249,19 +302,25 @@
public final int size() { return SIZE; }
- public MultiReaderHitCollector newCollector(int mask) {
- return new Collector(mask, this);
+ public Collector newCollector(int mask) {
+ return new BolleanScorerCollector(mask, this);
}
}
- static final class Collector extends MultiReaderHitCollector {
+ private static final class BolleanScorerCollector extends Collector {
private BucketTable bucketTable;
private int mask;
- public Collector(int mask, BucketTable bucketTable) {
+ private Scorer scorer;
+
+ public BolleanScorerCollector(int mask, BucketTable bucketTable) {
this.mask = mask;
this.bucketTable = bucketTable;
}
- public final void collect(final int doc, final float score) {
+ public void setScorer(Scorer scorer) throws IOException {
+ this.scorer = scorer;
+ }
+
+ public final void collect(final int doc) throws IOException {
final BucketTable table = bucketTable;
final int i = doc & BucketTable.MASK;
Bucket bucket = table.buckets[i];
@@ -270,14 +329,14 @@
if (bucket.doc != doc) { // invalid bucket
bucket.doc = doc; // set doc
- bucket.score = score; // initialize score
+ bucket.score = scorer.score(); // initialize score
bucket.bits = mask; // initialize mask
bucket.coord = 1; // initialize coord
bucket.next = table.first; // push onto valid list
table.first = bucket;
} else { // valid bucket
- bucket.score += score; // increment score
+ bucket.score += scorer.score(); // increment score
bucket.bits |= mask; // add bits in mask
bucket.coord++; // increment coord
}
Modified: lucene/java/trunk/src/java/org/apache/lucene/search/BooleanScorer2.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/BooleanScorer2.java?rev=764551&r1=764550&r2=764551&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/BooleanScorer2.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/BooleanScorer2.java Mon Apr 13 18:33:56 2009
@@ -300,8 +300,17 @@
* @param hc The collector to which all matching documents are passed through
* {@link HitCollector#collect(int, float)}.
* <br>When this method is used the {@link #explain(int)} method should not be used.
+ * @deprecated use {@link #score(Collector)} instead.
*/
public void score(HitCollector hc) throws IOException {
+ score(new HitCollectorWrapper(hc));
+ }
+
+ /** Scores and collects all matching documents.
+ * @param collector The collector to which all matching documents are passed through.
+ * <br>When this method is used the {@link #explain(int)} method should not be used.
+ */
+ public void score(Collector collector) throws IOException {
if (allowDocsOutOfOrder && requiredScorers.size() == 0
&& prohibitedScorers.size() < 32) {
// fall back to BooleanScorer, scores documents somewhat out of order
@@ -314,13 +323,14 @@
while (si.hasNext()) {
bs.add((Scorer) si.next(), false /* required */, true /* prohibited */);
}
- bs.score(hc);
+ bs.score(collector);
} else {
if (countingSumScorer == null) {
initCountingSumScorer();
}
+ collector.setScorer(this);
while (countingSumScorer.next()) {
- hc.collect(countingSumScorer.doc(), score());
+ collector.collect(countingSumScorer.doc());
}
}
}
@@ -332,12 +342,25 @@
* {@link HitCollector#collect(int, float)}.
* @param max Do not score documents past this.
* @return true if more matching documents may remain.
+ * @deprecated use {@link #score(Collector, int)} instead.
*/
protected boolean score(HitCollector hc, int max) throws IOException {
+ return score(new HitCollectorWrapper(hc), max);
+ }
+
+ /** Expert: Collects matching documents in a range.
+ * <br>Note that {@link #next()} must be called once before this method is
+ * called for the first time.
+ * @param collector The collector to which all matching documents are passed through.
+ * @param max Do not score documents past this.
+ * @return true if more matching documents may remain.
+ */
+ protected boolean score(Collector collector, int max) throws IOException {
// null pointer exception when next() was not called before:
int docNr = countingSumScorer.doc();
+ collector.setScorer(this);
while (docNr < max) {
- hc.collect(docNr, score());
+ collector.collect(docNr);
if (! countingSumScorer.next()) {
return false;
}
Added: lucene/java/trunk/src/java/org/apache/lucene/search/Collector.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/Collector.java?rev=764551&view=auto
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/Collector.java (added)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/Collector.java Mon Apr 13 18:33:56 2009
@@ -0,0 +1,160 @@
+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 java.io.IOException;
+
+import org.apache.lucene.index.IndexReader;
+
+/**
+ * <p>Expert: Collectors are primarily meant to be used to
+ * gather raw results from a search, and implement sorting
+ * or custom result filtering, collation, etc. </p>
+ *
+ * <p>As of 2.9, this class replaces the deprecated
+ * HitCollector, and offers an API for efficient collection
+ * of hits across sequential {@link IndexReader}s. {@link
+ * IndexSearcher} advances the collector through each of the
+ * sub readers, in an arbitrary order. This results in a
+ * higher performance means of collection.</p>
+ *
+ * <p>Lucene's core collectors are derived from Collector.
+ * Likely your application can use one of these classes, or
+ * subclass {@link TopDocsCollector}, instead of
+ * implementing Collector directly:
+ *
+ * <ul>
+ *
+ * <li>{@link TopDocsCollector} is an abstract base class
+ * that assumes you will retrieve the top N docs,
+ * according to some criteria, after collection is
+ * done. </li>
+ *
+ * <li>{@link TopScoreDocCollector} is a concrete subclass
+ * {@link TopDocsCollector} and sorts according to score +
+ * docID. This is used internally by the {@link
+ * IndexSearcher} search methods that do not take an
+ * explicit {@link Sort}. It is likely the most frequently
+ * used collector.</li>
+ *
+ * <li>{@link TopFieldCollector} subclasses {@link
+ * TopDocsCollector} and sorts according to a specified
+ * {@link Sort} object (sort by field). This is used
+ * internally by the {@link IndexSearcher} search methods
+ * that take an explicit {@link Sort}.
+ *
+ * <li>{@link TimeLimitingCollector}, which wraps any other
+ * Collector and aborts the search if it's taken too much
+ * time, will subclass Collector in 3.0 (presently it
+ * subclasses the deprecated HitCollector).</li>
+ *
+ * <li>{@link PositiveScoresOnlyCollector} wraps any other
+ * Collector and prevents collection of hits whose score
+ * is <= 0.0</li>
+ *
+ * </ul>
+ *
+ * <p>Collector decouples the score from the collected doc:
+ * the score computation is skipped entirely if it's not
+ * needed. Collectors that do need the score should
+ * implement the {@link #setScorer} method, to hold onto the
+ * passed {@link Scorer} instance, and call {@link
+ * Scorer#score()} within the collect method to compute the
+ * current hit's score. If your collector may request the
+ * score for a single hit multiple times, you should use
+ * {@link ScoreCachingWrappingScorer}. </p>
+ *
+ * <p><b>NOTE:</b> The doc that is passed to the collect
+ * method is relative to the current reader. If your
+ * collector needs to resolve this to the docID space of the
+ * Multi*Reader, you must re-base it by recording the
+ * docBase from the most recent setNextReader call. Here's
+ * a simple example showing how to collect docIDs into a
+ * BitSet:</p>
+ *
+ * <pre>
+ * Searcher searcher = new IndexSearcher(indexReader);
+ * final BitSet bits = new BitSet(indexReader.maxDoc());
+ * searcher.search(query, new Collector() {
+ * private int docBase;
+ *
+ * // ignore scorer
+ * public void setScorer(Scorer scorer) {
+ * }
+ *
+ * public void collect(int doc) {
+ * bits.set(doc + docBase);
+ * }
+ *
+ * public void setNextReader(IndexReader reader, int docBase) {
+ * this.docBase = docBase;
+ * }
+ * });
+ * </pre>
+ *
+ * <p>Not all collectors will need to rebase the docID. For
+ * example, a collector that simply counts the total number
+ * of hits would skip it.</p>
+ *
+ * <p><b>NOTE:</b> Prior to 2.9, Lucene silently filtered
+ * out hits with score <= 0. As of 2.9, the core Collectors
+ * no longer do that. It's very unusual to have such hits
+ * (a negative query boost, or function query returning
+ * negative custom scores, could cause it to happen). If
+ * you need that behavior, use {@link
+ * PositiveScoresOnlyCollector}.</p>
+ *
+ * <p><b>NOTE:</b> This API is experimental and might change
+ * in incompatible ways in the next release.</p>
+ */
+public abstract class Collector {
+
+ /**
+ * Called before successive calls to {@link #collect(int)}. Implementations
+ * that need the score of the current document (passed-in to
+ * {@link #collect(int)}), should save the passed-in Scorer and call
+ * scorer.score() when needed.
+ */
+ public abstract void setScorer(Scorer scorer) throws IOException;
+
+ /**
+ * Called once for every document matching a query, with the unbased document
+ * number.
+ *
+ * <p>
+ * Note: This is called in an inner search loop. For good search performance,
+ * implementations of this method should not call {@link Searcher#doc(int)} or
+ * {@link org.apache.lucene.index.IndexReader#document(int)} on every hit.
+ * Doing so can slow searches by an order of magnitude or more.
+ */
+ public abstract void collect(int doc) throws IOException;
+
+ /**
+ * Called before collecting from each IndexReader. All doc ids in
+ * {@link #collect(int)} will correspond to reader.
+ *
+ * Add docBase to the current IndexReaders internal document id to re-base ids
+ * in {@link #collect(int)}.
+ *
+ * @param reader
+ * next IndexReader
+ * @param docBase
+ */
+ public abstract void setNextReader(IndexReader reader, int docBase) throws IOException;
+
+}
Modified: lucene/java/trunk/src/java/org/apache/lucene/search/DisjunctionSumScorer.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/DisjunctionSumScorer.java?rev=764551&r1=764550&r2=764551&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/DisjunctionSumScorer.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/DisjunctionSumScorer.java Mon Apr 13 18:33:56 2009
@@ -112,10 +112,20 @@
* @param hc The collector to which all matching documents are passed through
* {@link HitCollector#collect(int, float)}.
* <br>When this method is used the {@link #explain(int)} method should not be used.
+ * @deprecated use {@link #score(Collector)} instead.
*/
public void score(HitCollector hc) throws IOException {
+ score(new HitCollectorWrapper(hc));
+ }
+
+ /** Scores and collects all matching documents.
+ * @param collector The collector to which all matching documents are passed through.
+ * <br>When this method is used the {@link #explain(int)} method should not be used.
+ */
+ public void score(Collector collector) throws IOException {
+ collector.setScorer(this);
while (next()) {
- hc.collect(currentDoc, currentScore);
+ collector.collect(currentDoc);
}
}
@@ -126,10 +136,23 @@
* {@link HitCollector#collect(int, float)}.
* @param max Do not score documents past this.
* @return true if more matching documents may remain.
+ * @deprecated use {@link #score(Collector, int)} instead.
*/
protected boolean score(HitCollector hc, int max) throws IOException {
+ return score(new HitCollectorWrapper(hc), max);
+ }
+
+ /** Expert: Collects matching documents in a range. Hook for optimization.
+ * Note that {@link #next()} must be called once before this method is called
+ * for the first time.
+ * @param collector The collector to which all matching documents are passed through.
+ * @param max Do not score documents past this.
+ * @return true if more matching documents may remain.
+ */
+ protected boolean score(Collector collector, int max) throws IOException {
+ collector.setScorer(this);
while (currentDoc < max) {
- hc.collect(currentDoc, currentScore);
+ collector.collect(currentDoc);
if (!next()) {
return false;
}
Modified: lucene/java/trunk/src/java/org/apache/lucene/search/FieldComparator.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/FieldComparator.java?rev=764551&r1=764550&r2=764551&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/FieldComparator.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/FieldComparator.java Mon Apr 13 18:33:56 2009
@@ -62,11 +62,11 @@
return values[slot1] - values[slot2];
}
- public int compareBottom(int doc, float score) {
+ public int compareBottom(int doc) {
return bottom - currentReaderValues[doc];
}
- public void copy(int slot, int doc, float score) {
+ public void copy(int slot, int doc) {
values[slot] = currentReaderValues[doc];
}
@@ -87,7 +87,7 @@
public Comparable value(int slot) {
return new Byte(values[slot]);
}
- };
+ }
/** Sorts by ascending docID */
public static final class DocComparator extends FieldComparator {
@@ -104,12 +104,12 @@
return docIDs[slot1] - docIDs[slot2];
}
- public int compareBottom(int doc, float score) {
+ public int compareBottom(int doc) {
// No overflow risk because docIDs are non-negative
return bottom - (docBase + doc);
}
- public void copy(int slot, int doc, float score) {
+ public void copy(int slot, int doc) {
docIDs[slot] = docBase + doc;
}
@@ -131,7 +131,7 @@
public Comparable value(int slot) {
return new Integer(docIDs[slot]);
}
- };
+ }
/** Parses field's values as double (using {@link
* ExtendedFieldCache#getDoubles} and sorts by ascending value */
@@ -160,7 +160,7 @@
}
}
- public int compareBottom(int doc, float score) {
+ public int compareBottom(int doc) {
final double v2 = currentReaderValues[doc];
if (bottom > v2) {
return 1;
@@ -171,7 +171,7 @@
}
}
- public void copy(int slot, int doc, float score) {
+ public void copy(int slot, int doc) {
values[slot] = currentReaderValues[doc];
}
@@ -192,7 +192,7 @@
public Comparable value(int slot) {
return new Double(values[slot]);
}
- };
+ }
/** Parses field's values as float (using {@link
* FieldCache#getFloats} and sorts by ascending value */
@@ -223,7 +223,7 @@
}
}
- public int compareBottom(int doc, float score) {
+ public int compareBottom(int doc) {
// TODO: are there sneaky non-branch ways to compute
// sign of float?
final float v2 = currentReaderValues[doc];
@@ -236,7 +236,7 @@
}
}
- public void copy(int slot, int doc, float score) {
+ public void copy(int slot, int doc) {
values[slot] = currentReaderValues[doc];
}
@@ -256,7 +256,7 @@
public Comparable value(int slot) {
return new Float(values[slot]);
}
- };
+ }
/** Parses field's values as int (using {@link
* FieldCache#getInts} and sorts by ascending value */
@@ -289,7 +289,7 @@
}
}
- public int compareBottom(int doc, float score) {
+ public int compareBottom(int doc) {
// TODO: there are sneaky non-branch ways to compute
// -1/+1/0 sign
// Cannot return bottom - values[slot2] because that
@@ -304,7 +304,7 @@
}
}
- public void copy(int slot, int doc, float score) {
+ public void copy(int slot, int doc) {
values[slot] = currentReaderValues[doc];
}
@@ -324,7 +324,7 @@
public Comparable value(int slot) {
return new Integer(values[slot]);
}
- };
+ }
/** Parses field's values as long (using {@link
* ExtendedFieldCache#getLongs} and sorts by ascending value */
@@ -355,7 +355,7 @@
}
}
- public int compareBottom(int doc, float score) {
+ public int compareBottom(int doc) {
// TODO: there are sneaky non-branch ways to compute
// -1/+1/0 sign
final long v2 = currentReaderValues[doc];
@@ -368,7 +368,7 @@
}
}
- public void copy(int slot, int doc, float score) {
+ public void copy(int slot, int doc) {
values[slot] = currentReaderValues[doc];
}
@@ -389,7 +389,7 @@
public Comparable value(int slot) {
return new Long(values[slot]);
}
- };
+ }
/** Sorts by descending relevance. NOTE: if you are
* sorting only by descending relevance and then
@@ -400,7 +400,8 @@
public static final class RelevanceComparator extends FieldComparator {
private final float[] scores;
private float bottom;
-
+ private Scorer scorer;
+
RelevanceComparator(int numHits) {
scores = new float[numHits];
}
@@ -408,27 +409,16 @@
public int compare(int slot1, int slot2) {
final float score1 = scores[slot1];
final float score2 = scores[slot2];
- if (score1 > score2) {
- return -1;
- } else if (score1 < score2) {
- return 1;
- } else {
- return 0;
- }
+ return score1 > score2 ? -1 : (score1 < score2 ? 1 : 0);
}
- public int compareBottom(int doc, float score) {
- if (bottom > score) {
- return -1;
- } else if (bottom < score) {
- return 1;
- } else {
- return 0;
- }
+ public int compareBottom(int doc) throws IOException {
+ float score = scorer.score();
+ return bottom > score ? -1 : (bottom < score ? 1 : 0);
}
- public void copy(int slot, int doc, float score) {
- scores[slot] = score;
+ public void copy(int slot, int doc) throws IOException {
+ scores[slot] = scorer.score();
}
public void setNextReader(IndexReader reader, int docBase, int numSlotsFull) {
@@ -438,6 +428,12 @@
this.bottom = scores[bottom];
}
+ public void setScorer(Scorer scorer) {
+ // wrap with a ScoreCachingWrappingScorer so that successive calls to
+ // score() will not incur score computation over and over again.
+ this.scorer = new ScoreCachingWrappingScorer(scorer);
+ }
+
public int sortType() {
return SortField.SCORE;
}
@@ -445,7 +441,7 @@
public Comparable value(int slot) {
return new Float(scores[slot]);
}
- };
+ }
/** Parses field's values as short (using {@link
* FieldCache#getShorts} and sorts by ascending value */
@@ -466,11 +462,11 @@
return values[slot1] - values[slot2];
}
- public int compareBottom(int doc, float score) {
+ public int compareBottom(int doc) {
return bottom - currentReaderValues[doc];
}
- public void copy(int slot, int doc, float score) {
+ public void copy(int slot, int doc) {
values[slot] = currentReaderValues[doc];
}
@@ -491,7 +487,7 @@
public Comparable value(int slot) {
return new Short(values[slot]);
}
- };
+ }
/** Sorts by a field's value using the Collator for a
* given Locale.*/
@@ -523,7 +519,7 @@
return collator.compare(val1, val2);
}
- public int compareBottom(int doc, float score) {
+ public int compareBottom(int doc) {
final String val2 = currentReaderValues[doc];
if (bottom == null) {
if (val2 == null) {
@@ -536,7 +532,7 @@
return collator.compare(bottom, val2);
}
- public void copy(int slot, int doc, float score) {
+ public void copy(int slot, int doc) {
values[slot] = currentReaderValues[doc];
}
@@ -556,7 +552,7 @@
public Comparable value(int slot) {
return values[slot];
}
- };
+ }
// NOTE: there were a number of other interesting String
// comparators explored, but this one seemed to perform
@@ -608,7 +604,7 @@
return val1.compareTo(val2);
}
- public int compareBottom(int doc, float score) {
+ public int compareBottom(int doc) {
assert bottomSlot != -1;
int order = this.order[doc];
final int cmp = bottomOrd - order;
@@ -659,7 +655,7 @@
ords[slot] = index;
}
- public void copy(int slot, int doc, float score) {
+ public void copy(int slot, int doc) {
final int ord = order[doc];
ords[slot] = ord;
assert ord >= 0;
@@ -709,7 +705,7 @@
public String getField() {
return field;
}
- };
+ }
/** Sorts by field's natural String sort order. All
* comparisons are done using String.compareTo, which is
@@ -742,7 +738,7 @@
return val1.compareTo(val2);
}
- public int compareBottom(int doc, float score) {
+ public int compareBottom(int doc) {
final String val2 = currentReaderValues[doc];
if (bottom == null) {
if (val2 == null) {
@@ -755,7 +751,7 @@
return bottom.compareTo(val2);
}
- public void copy(int slot, int doc, float score) {
+ public void copy(int slot, int doc) {
values[slot] = currentReaderValues[doc];
}
@@ -775,11 +771,11 @@
public Comparable value(int slot) {
return values[slot];
}
- };
+ }
final protected static int binarySearch(String[] a, String key) {
return binarySearch(a, key, 0, a.length-1);
- };
+ }
final protected static int binarySearch(String[] a, String key, int low, int high) {
@@ -801,7 +797,7 @@
return mid;
}
return -(low + 1);
- };
+ }
/**
* Compare hit at slot1 with hit at slot2. Return
@@ -827,22 +823,20 @@
* only invoked after setBottom has been called.
*
* @param doc that was hit
- * @param score of the hit
* @return any N < 0 if the doc's value is sorted after
* the bottom entry (not competitive), any N > 0 if the
* doc's value is sorted before the bottom entry and 0 if
* they are equal.
*/
- public abstract int compareBottom(int doc, float score);
+ public abstract int compareBottom(int doc) throws IOException;
/**
* Copy hit (doc,score) to hit slot.
*
* @param slot which slot to copy the hit to
* @param doc docID relative to current reader
- * @param score hit score
*/
- public abstract void copy(int slot, int doc, float score);
+ public abstract void copy(int slot, int doc) throws IOException;
/**
* Set a new Reader. All doc correspond to the current Reader.
@@ -854,6 +848,12 @@
*/
public abstract void setNextReader(IndexReader reader, int docBase, int numSlotsFull) throws IOException;
+ /** Sets the Scorer to use in case a document's score is needed. */
+ public void setScorer(Scorer scorer) {
+ // Empty implementation since most comparators don't need the score. This
+ // can be overridden by those that need it.
+ }
+
/**
* @return SortField.TYPE
*/
Modified: lucene/java/trunk/src/java/org/apache/lucene/search/FieldComparatorSource.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/FieldComparatorSource.java?rev=764551&r1=764550&r2=764551&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/FieldComparatorSource.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/FieldComparatorSource.java Mon Apr 13 18:33:56 2009
@@ -18,7 +18,6 @@
*/
import java.io.IOException;
-import org.apache.lucene.index.IndexReader;
/**
* Provides a {@link FieldComparator} for custom field sorting.
@@ -38,6 +37,6 @@
* @throws IOException
* If an error occurs reading the index.
*/
- public abstract FieldComparator newComparator(String fieldname, IndexReader[] subReaders, int numHits, int sortPos, boolean reversed)
+ public abstract FieldComparator newComparator(String fieldname, int numHits, int sortPos, boolean reversed)
throws IOException;
}
Modified: lucene/java/trunk/src/java/org/apache/lucene/search/FieldValueHitQueue.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/FieldValueHitQueue.java?rev=764551&r1=764550&r2=764551&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/FieldValueHitQueue.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/FieldValueHitQueue.java Mon Apr 13 18:33:56 2009
@@ -17,13 +17,13 @@
* limitations under the License.
*/
+import java.io.IOException;
+
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.TermEnum;
import org.apache.lucene.util.PriorityQueue;
-import java.io.IOException;;
-
/**
* Expert: A hit queue for sorting by hits by terms in more than one field.
* Uses <code>FieldCache.DEFAULT</code> for maintaining
@@ -32,12 +32,12 @@
* <b>NOTE:</b> This API is experimental and might change in
* incompatible ways in the next release.
*
- * @since lucene 2.9
+ * @since 2.9
* @version $Id:
* @see Searcher#search(Query,Filter,int,Sort)
* @see FieldCache
*/
-public class FieldValueHitQueue extends PriorityQueue {
+public abstract class FieldValueHitQueue extends PriorityQueue {
final static class Entry {
int slot;
@@ -56,136 +56,185 @@
}
/**
- * Creates a hit queue sorted by the given list of fields.
- * @param fields SortField array we are sorting by in
- * priority order (highest priority first); cannot be <code>null</code> or empty
- * @param size The number of hits to retain. Must be
- * greater than zero.
- * @param subReaders Array of IndexReaders we will search,
- * in order that they will be searched
- * @throws IOException
+ * An implementation of {@link FieldValueHitQueue} which is optimized in case
+ * there is just one comparator.
*/
- public FieldValueHitQueue(SortField[] fields, int size, IndexReader[] subReaders) throws IOException {
- numComparators = fields.length;
- comparators = new FieldComparator[numComparators];
- reverseMul = new int[numComparators];
-
- if (fields.length == 0) {
- throw new IllegalArgumentException("Sort must contain at least one field");
- }
+ private static final class OneComparatorFieldValueHitQueue extends FieldValueHitQueue {
- this.fields = fields;
- for (int i=0; i<numComparators; ++i) {
- SortField field = fields[i];
+ private final FieldComparator comparator;
+ private final int oneReverseMul;
+
+ public OneComparatorFieldValueHitQueue(SortField[] fields, int size)
+ throws IOException {
+ super(fields);
+ if (fields.length == 0) {
+ throw new IllegalArgumentException("Sort must contain at least one field");
+ }
+ SortField field = fields[0];
// AUTO is resolved before we are called
assert field.getType() != SortField.AUTO;
+ comparator = field.getComparator(size, 0, field.reverse);
+ oneReverseMul = field.reverse ? -1 : 1;
- reverseMul[i] = field.reverse ? -1 : 1;
- comparators[i] = field.getComparator(subReaders, size, i, field.reverse);
+ comparators[0] = comparator;
+ reverseMul[0] = oneReverseMul;
+
+ initialize(size);
}
- if (numComparators == 1) {
- comparator1 = comparators[0];
- reverseMul1 = reverseMul[0];
- } else {
- comparator1 = null;
- reverseMul1 = 0;
+ /**
+ * Returns whether <code>a</code> is less relevant than <code>b</code>.
+ * @param a ScoreDoc
+ * @param b ScoreDoc
+ * @return <code>true</code> if document <code>a</code> should be sorted after document <code>b</code>.
+ */
+ protected boolean lessThan(final Object a, final Object b) {
+ final Entry hitA = (Entry) a;
+ final Entry hitB = (Entry) b;
+
+ assert hitA != hitB;
+ assert hitA.slot != hitB.slot;
+
+ final int c = oneReverseMul * comparator.compare(hitA.slot, hitB.slot);
+ if (c != 0) {
+ return c > 0;
+ }
+
+ // avoid random sort order that could lead to duplicates (bug #31241):
+ return hitA.docID > hitB.docID;
}
- initialize(size);
}
- /** Stores a comparator corresponding to each field being sorted by */
- private final FieldComparator[] comparators;
- private final FieldComparator comparator1;
- private final int numComparators;
- private final int[] reverseMul;
- private final int reverseMul1;
+ /**
+ * An implementation of {@link FieldValueHitQueue} which is optimized in case
+ * there is more than one comparator.
+ */
+ private static final class MultiComparatorsFieldValueHitQueue extends FieldValueHitQueue {
- FieldComparator[] getComparators() {
- return comparators;
- }
+ public MultiComparatorsFieldValueHitQueue(SortField[] fields, int size)
+ throws IOException {
+ super(fields);
- int[] getReverseMul() {
- return reverseMul;
- }
+ int numComparators = comparators.length;
+ for (int i = 0; i < numComparators; ++i) {
+ SortField field = fields[i];
- /** Stores the sort criteria being used. */
- private final SortField[] fields;
+ // AUTO is resolved before we are called
+ assert field.getType() != SortField.AUTO;
- /**
- * Returns whether <code>a</code> is less relevant than <code>b</code>.
- * @param a ScoreDoc
- * @param b ScoreDoc
- * @return <code>true</code> if document <code>a</code> should be sorted after document <code>b</code>.
- */
- protected boolean lessThan (final Object a, final Object b) {
- final Entry hitA = (Entry) a;
- final Entry hitB = (Entry) b;
-
- assert hitA != hitB;
- assert hitA.slot != hitB.slot;
-
- if (numComparators == 1) {
- // Common case
- final int c = reverseMul1 * comparator1.compare(hitA.slot, hitB.slot);
- if (c != 0) {
- return c > 0;
+ reverseMul[i] = field.reverse ? -1 : 1;
+ comparators[i] = field.getComparator(size, i, field.reverse);
}
- } else {
- // run comparators
- for (int i=0; i<numComparators; ++i) {
+
+ initialize(size);
+ }
+
+ protected boolean lessThan(Object a, Object b) {
+ final Entry hitA = (Entry) a;
+ final Entry hitB = (Entry) b;
+
+ assert hitA != hitB;
+ assert hitA.slot != hitB.slot;
+
+ int numComparators = comparators.length;
+ for (int i = 0; i < numComparators; ++i) {
final int c = reverseMul[i] * comparators[i].compare(hitA.slot, hitB.slot);
if (c != 0) {
// Short circuit
return c > 0;
}
}
+
+ // avoid random sort order that could lead to duplicates (bug #31241):
+ return hitA.docID > hitB.docID;
}
+
+ }
+
+ // prevent instantiation and extension.
+ private FieldValueHitQueue(SortField[] fields) {
+ // When we get here, fields.length is guaranteed to be > 0, therefore no
+ // need to check it again.
+
+ // All these are required by this class's API - need to return arrays.
+ // Therefore even in the case of a single comparator, create an array
+ // anyway.
+ this.fields = fields;
+ int numComparators = fields.length;
+ comparators = new FieldComparator[numComparators];
+ reverseMul = new int[numComparators];
+ }
- // avoid random sort order that could lead to duplicates (bug #31241):
- return hitA.docID > hitB.docID;
+ /**
+ * Creates a hit queue sorted by the given list of fields.
+ *
+ * @param fields
+ * SortField array we are sorting by in priority order (highest
+ * priority first); cannot be <code>null</code> or empty
+ * @param size
+ * The number of hits to retain. Must be greater than zero.
+ * @throws IOException
+ */
+ public static FieldValueHitQueue create(SortField[] fields, int size) throws IOException {
+
+ if (fields.length == 0) {
+ throw new IllegalArgumentException("Sort must contain at least one field");
+ }
+
+ if (fields.length == 1) {
+ return new OneComparatorFieldValueHitQueue(fields, size);
+ } else {
+ return new MultiComparatorsFieldValueHitQueue(fields, size);
+ }
}
+
+ FieldComparator[] getComparators() { return comparators; }
+ int[] getReverseMul() { return reverseMul; }
+
+ /** Stores the sort criteria being used. */
+ protected final SortField[] fields;
+ protected final FieldComparator[] comparators;
+ protected final int[] reverseMul;
+
+ protected abstract boolean lessThan (final Object a, final Object b);
/**
- * Given a FieldDoc object, stores the values used
- * to sort the given document. These values are not the raw
- * values out of the index, but the internal representation
- * of them. This is so the given search hit can be collated
- * by a MultiSearcher with other search hits.
- * @param doc The FieldDoc to store sort values into.
- * @return The same FieldDoc passed in.
+ * Given a FieldDoc object, stores the values used to sort the given document.
+ * These values are not the raw values out of the index, but the internal
+ * representation of them. This is so the given search hit can be collated by
+ * a MultiSearcher with other search hits.
+ *
+ * @param doc
+ * The FieldDoc to store sort values into.
+ * @return The same FieldDoc passed in.
* @see Searchable#search(Weight,Filter,int,Sort)
*/
- FieldDoc fillFields (final Entry entry) {
+ FieldDoc fillFields(final Entry entry) {
final int n = comparators.length;
final Comparable[] fields = new Comparable[n];
- for (int i=0; i<n; ++i)
+ for (int i = 0; i < n; ++i) {
fields[i] = comparators[i].value(entry.slot);
+ }
//if (maxscore > 1.0f) doc.score /= maxscore; // normalize scores
- return new FieldDoc(entry.docID,
- entry.score,
- fields);
+ return new FieldDoc(entry.docID, entry.score, fields);
}
-
/** Returns the SortFields being used by this hit queue. */
SortField[] getFields() {
return fields;
}
- /**
- * Attempts to detect the given field type for an IndexReader.
- */
+ /** Attempts to detect the given field type for an IndexReader. */
static int detectFieldType(IndexReader reader, String fieldKey) throws IOException {
- String field = ((String)fieldKey).intern();
- TermEnum enumerator = reader.terms (new Term (field));
+ String field = fieldKey.intern();
+ TermEnum enumerator = reader.terms(new Term(field));
try {
Term term = enumerator.term();
if (term == null) {
- throw new RuntimeException ("no terms in field " + field + " - cannot determine sort type");
+ throw new RuntimeException("no terms in field " + field + " - cannot determine sort type");
}
int ret = 0;
if (term.field() == field) {
@@ -219,7 +268,7 @@
}
}
} else {
- throw new RuntimeException ("field \"" + field + "\" does not appear to be indexed");
+ throw new RuntimeException("field \"" + field + "\" does not appear to be indexed");
}
return ret;
} finally {
Modified: lucene/java/trunk/src/java/org/apache/lucene/search/HitCollector.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/HitCollector.java?rev=764551&r1=764550&r2=764551&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/HitCollector.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/HitCollector.java Mon Apr 13 18:33:56 2009
@@ -17,13 +17,15 @@
* limitations under the License.
*/
-/** Lower-level search API.
- * <br>HitCollectors are primarily meant to be used to implement queries,
- * sorting and filtering. See {@link
- * MultiReaderHitCollector} for a lower level and
- * higher performance (on a multi-segment index) API.
+/**
+ * Lower-level search API. <br>
+ * HitCollectors are primarily meant to be used to implement queries, sorting
+ * and filtering. See {@link Collector} for a lower level and higher performance
+ * (on a multi-segment index) API.
+ *
* @see Searcher#search(Query,HitCollector)
* @version $Id$
+ * @deprecated Please use {@link Collector} instead.
*/
public abstract class HitCollector {
/** Called once for every document matching a query, with the document
Added: lucene/java/trunk/src/java/org/apache/lucene/search/HitCollectorWrapper.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/HitCollectorWrapper.java?rev=764551&view=auto
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/HitCollectorWrapper.java (added)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/HitCollectorWrapper.java Mon Apr 13 18:33:56 2009
@@ -0,0 +1,50 @@
+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 java.io.IOException;
+
+import org.apache.lucene.index.IndexReader;
+
+/**
+ * Wrapper for ({@link HitCollector}) implementations, which
+ * simply re-bases the incoming docID before calling {@link
+ * HitCollector#collect}.
+ * @deprecated this class will be removed when {@link HitCollector} is removed.
+ */
+class HitCollectorWrapper extends Collector {
+ private HitCollector collector;
+ private int base = 0;
+ private Scorer scorer = null;
+
+ public HitCollectorWrapper(HitCollector collector) {
+ this.collector = collector;
+ }
+
+ public void setNextReader(IndexReader reader, int docBase) {
+ base = docBase;
+ }
+
+ public void collect(int doc) throws IOException {
+ collector.collect(doc + base, scorer.score());
+ }
+
+ public void setScorer(Scorer scorer) throws IOException {
+ this.scorer = scorer;
+ }
+}
Modified: lucene/java/trunk/src/java/org/apache/lucene/search/IndexSearcher.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/IndexSearcher.java?rev=764551&r1=764550&r2=764551&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/IndexSearcher.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/IndexSearcher.java Mon Apr 13 18:33:56 2009
@@ -188,12 +188,16 @@
throws IOException {
return search(weight, filter, nDocs, sort, true);
}
-
- /**
- * Just like {@link #search(Weight, Filter, int, Sort)},
- * but you choose whether or not the fields in the
- * returned {@link FieldDoc} instances should be set by
- * specifying fillFields.
+
+ /**
+ * Just like {@link #search(Weight, Filter, int, Sort)}, but you choose
+ * whether or not the fields in the returned {@link FieldDoc} instances should
+ * be set by specifying fillFields.<br>
+ * <b>NOTE:</b> currently, this method tracks document scores and sets them in
+ * the returned {@link FieldDoc}, however in 3.0 it will move to not track
+ * document scores. If document scores tracking is still needed, you can use
+ * {@link #search(Weight, Filter, Collector)} and pass in a
+ * {@link TopFieldCollector} instance.
*/
public TopFieldDocs search(Weight weight, Filter filter, final int nDocs,
Sort sort, boolean fillFields)
@@ -222,29 +226,32 @@
if (legacy) {
// Search the single top-level reader
- TopScoreDocCollector collector = new TopFieldDocCollector(reader, sort, nDocs);
- collector.setNextReader(reader, 0);
- doSearch(reader, weight, filter, collector);
- return (TopFieldDocs) collector.topDocs();
- } else {
- // Search each sub-reader
- TopFieldCollector collector = new TopFieldCollector(sort, nDocs, sortedSubReaders, fillFields);
- search(weight, filter, collector);
+ TopDocCollector collector = new TopFieldDocCollector(reader, sort, nDocs);
+ HitCollectorWrapper hcw = new HitCollectorWrapper(collector);
+ hcw.setNextReader(reader, 0);
+ doSearch(reader, weight, filter, hcw);
return (TopFieldDocs) collector.topDocs();
}
+ // Search each sub-reader
+ // TODO: by default we should create a TopFieldCollector which does not
+ // track document scores and maxScore. Currently the default is set to true,
+ // however it will change in 3.0.
+ TopFieldCollector collector = TopFieldCollector.create(sort, nDocs, fillFields, true, true);
+ search(weight, filter, collector);
+ return (TopFieldDocs) collector.topDocs();
}
// inherit javadoc
+ /** @deprecated use {@link #search(Weight, Filter, Collector)} instead. */
public void search(Weight weight, Filter filter, HitCollector results)
throws IOException {
-
- final MultiReaderHitCollector collector;
- if (results instanceof MultiReaderHitCollector) {
- collector = (MultiReaderHitCollector) results;
- } else {
- collector = new MultiReaderCollectorWrapper(results);
- }
-
+ search(weight, filter, new HitCollectorWrapper(results));
+ }
+
+ // inherit javadoc
+ public void search(Weight weight, Filter filter, Collector collector)
+ throws IOException {
+
for (int i = 0; i < sortedSubReaders.length; i++) { // search each subreader
collector.setNextReader(sortedSubReaders[i], sortedStarts[i]);
doSearch(sortedSubReaders[i], weight, filter, collector);
@@ -252,14 +259,14 @@
}
private void doSearch(IndexReader reader, Weight weight, Filter filter,
- final HitCollector results) throws IOException {
+ final Collector collector) throws IOException {
Scorer scorer = weight.scorer(reader);
if (scorer == null)
return;
if (filter == null) {
- scorer.score(results);
+ scorer.score(collector);
return;
}
@@ -267,6 +274,7 @@
boolean more = filterDocIdIterator.next() && scorer.skipTo(filterDocIdIterator.doc());
+ collector.setScorer(scorer);
while (more) {
int filterDocId = filterDocIdIterator.doc();
if (filterDocId > scorer.doc() && !scorer.skipTo(filterDocId)) {
@@ -274,7 +282,7 @@
} else {
int scorerDocId = scorer.doc();
if (scorerDocId == filterDocId) { // permitted by filter
- results.collect(scorerDocId, scorer.score());
+ collector.collect(scorerDocId);
more = filterDocIdIterator.next();
} else {
more = filterDocIdIterator.skipTo(scorerDocId);
@@ -295,26 +303,4 @@
public Explanation explain(Weight weight, int doc) throws IOException {
return weight.explain(reader, doc);
}
-
- /**
- * Wrapper for non expert ({@link HitCollector})
- * implementations, which simply re-bases the incoming
- * docID before calling {@link HitCollector#collect}.
- */
- static class MultiReaderCollectorWrapper extends MultiReaderHitCollector {
- private HitCollector collector;
- private int base = -1;
-
- public MultiReaderCollectorWrapper(HitCollector collector) {
- this.collector = collector;
- }
-
- public void collect(int doc, float score) {
- collector.collect(doc + base, score);
- }
-
- public void setNextReader(IndexReader reader, int docBase) {
- base = docBase;
- }
- }
}
Modified: lucene/java/trunk/src/java/org/apache/lucene/search/MultiSearcher.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/MultiSearcher.java?rev=764551&r1=764550&r2=764551&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/MultiSearcher.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/MultiSearcher.java Mon Apr 13 18:33:56 2009
@@ -97,9 +97,14 @@
throw new UnsupportedOperationException();
}
+ /** @deprecated use {@link #search(Weight, Filter, Collector)} instead. */
public void search(Weight weight, Filter filter, HitCollector results) {
throw new UnsupportedOperationException();
}
+
+ public void search(Weight weight, Filter filter, Collector collector) {
+ throw new UnsupportedOperationException();
+ }
public TopDocs search(Weight weight,Filter filter,int n) {
throw new UnsupportedOperationException();
@@ -251,40 +256,31 @@
return new TopFieldDocs (totalHits, scoreDocs, hq.getFields(), maxScore);
}
-
// inherit javadoc
+ /** @deprecated use {@link #search(Weight, Filter, Collector)} instead. */
public void search(Weight weight, Filter filter, final HitCollector results)
throws IOException {
+ search(weight, filter, new HitCollectorWrapper(results));
+ }
+
+ // inherit javadoc
+ public void search(Weight weight, Filter filter, final Collector collector)
+ throws IOException {
for (int i = 0; i < searchables.length; i++) {
-
+
final int start = starts[i];
-
- final MultiReaderHitCollector hc;
- if (results instanceof MultiReaderHitCollector) {
- // results can shift
- final MultiReaderHitCollector resultsMulti = (MultiReaderHitCollector) results;
- hc = new MultiReaderHitCollector() {
- public void collect(int doc, float score) {
- resultsMulti.collect(doc, score);
- }
-
- public void setNextReader(IndexReader reader, int docBase) throws IOException {
- resultsMulti.setNextReader(reader, start+docBase);
- }
- };
- } else {
- // We must shift the docIDs
- hc = new MultiReaderHitCollector() {
- private int docBase;
- public void collect(int doc, float score) {
- results.collect(doc + docBase + start, score);
- }
-
- public void setNextReader(IndexReader reader, int docBase) {
- this.docBase = docBase;
- }
- };
- }
+
+ final Collector hc = new Collector() {
+ public void setScorer(Scorer scorer) throws IOException {
+ collector.setScorer(scorer);
+ }
+ public void collect(int doc) throws IOException {
+ collector.collect(doc);
+ }
+ public void setNextReader(IndexReader reader, int docBase) throws IOException {
+ collector.setNextReader(reader, start + docBase);
+ }
+ };
searchables[i].search(weight, filter, hc);
}
Modified: lucene/java/trunk/src/java/org/apache/lucene/search/ParallelMultiSearcher.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/ParallelMultiSearcher.java?rev=764551&r1=764550&r2=764551&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/ParallelMultiSearcher.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/ParallelMultiSearcher.java Mon Apr 13 18:33:56 2009
@@ -170,44 +170,51 @@
* @param results to receive hits
*
* @todo parallelize this one too
+ * @deprecated use {@link #search(Weight, Filter, Collector)} instead.
*/
public void search(Weight weight, Filter filter, final HitCollector results)
throws IOException {
- for (int i = 0; i < searchables.length; i++) {
-
- final int start = starts[i];
-
- final MultiReaderHitCollector hc;
- if (results instanceof MultiReaderHitCollector) {
- // results can shift
- final MultiReaderHitCollector resultsMulti = (MultiReaderHitCollector) results;
- hc = new MultiReaderHitCollector() {
- public void collect(int doc, float score) {
- resultsMulti.collect(doc, score);
- }
-
- public void setNextReader(IndexReader reader, int docBase) throws IOException {
- resultsMulti.setNextReader(reader, start+docBase);
- }
- };
- } else {
- // We must shift the docIDs
- hc = new MultiReaderHitCollector() {
- private int docBase;
- public void collect(int doc, float score) {
- results.collect(doc + docBase + start, score);
- }
-
- public void setNextReader(IndexReader reader, int docBase) {
- this.docBase = docBase;
- }
- };
- }
-
- searchables[i].search(weight, filter, hc);
- }
+ search(weight, filter, new HitCollectorWrapper(results));
}
+ /** Lower-level search API.
+ *
+ * <p>{@link Collector#collect(int)} is called for every matching document.
+ *
+ * <p>Applications should only use this if they need <i>all</i> of the
+ * matching documents. The high-level search API ({@link
+ * Searcher#search(Query)}) is usually more efficient, as it skips
+ * non-high-scoring hits.
+ *
+ * @param weight to match documents
+ * @param filter if non-null, a bitset used to eliminate some documents
+ * @param collector to receive hits
+ *
+ * @todo parallelize this one too
+ */
+ public void search(Weight weight, Filter filter, final Collector collector)
+ throws IOException {
+ for (int i = 0; i < searchables.length; i++) {
+
+ final int start = starts[i];
+
+ final Collector hc = new Collector() {
+ public void setScorer(Scorer scorer) throws IOException {
+ collector.setScorer(scorer);
+ }
+ public void collect(int doc) throws IOException {
+ collector.collect(doc);
+ }
+
+ public void setNextReader(IndexReader reader, int docBase) throws IOException {
+ collector.setNextReader(reader, start + docBase);
+ }
+ };
+
+ searchables[i].search(weight, filter, hc);
+ }
+ }
+
/*
* TODO: this one could be parallelized too
* @see org.apache.lucene.search.Searchable#rewrite(org.apache.lucene.search.Query)
Added: lucene/java/trunk/src/java/org/apache/lucene/search/PositiveScoresOnlyCollector.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/PositiveScoresOnlyCollector.java?rev=764551&view=auto
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/PositiveScoresOnlyCollector.java (added)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/PositiveScoresOnlyCollector.java Mon Apr 13 18:33:56 2009
@@ -0,0 +1,56 @@
+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 java.io.IOException;
+
+import org.apache.lucene.index.IndexReader;
+
+/**
+ * A {@link Collector} implementation which wraps another
+ * {@link Collector} and makes sure only documents with
+ * scores > 0 are collected.
+ */
+
+public class PositiveScoresOnlyCollector extends Collector {
+
+ final private Collector c;
+ private Scorer scorer;
+
+ public PositiveScoresOnlyCollector(Collector c) {
+ this.c = c;
+ }
+
+ public void collect(int doc) throws IOException {
+ if (scorer.score() > 0) {
+ c.collect(doc);
+ }
+ }
+
+ public void setNextReader(IndexReader reader, int docBase) throws IOException {
+ c.setNextReader(reader, docBase);
+ }
+
+ public void setScorer(Scorer scorer) throws IOException {
+ // Set a ScoreCachingWrappingScorer in case the wrapped Collector will call
+ // score() also.
+ this.scorer = new ScoreCachingWrappingScorer(scorer);
+ c.setScorer(this.scorer);
+ }
+
+}
Modified: lucene/java/trunk/src/java/org/apache/lucene/search/QueryWrapperFilter.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/QueryWrapperFilter.java?rev=764551&r1=764550&r2=764551&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/QueryWrapperFilter.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/QueryWrapperFilter.java Mon Apr 13 18:33:56 2009
@@ -50,9 +50,12 @@
public BitSet bits(IndexReader reader) throws IOException {
final BitSet bits = new BitSet(reader.maxDoc());
- new IndexSearcher(reader).search(query, new MultiReaderHitCollector() {
- private int base = -1;
- public final void collect(int doc, float score) {
+ new IndexSearcher(reader).search(query, new Collector() {
+ private int base = 0;
+ public void setScorer(Scorer scorer) throws IOException {
+ // score is not needed by this collector
+ }
+ public final void collect(int doc) {
bits.set(doc + base); // set bit for hit
}
public void setNextReader(IndexReader reader, int docBase) {
Modified: lucene/java/trunk/src/java/org/apache/lucene/search/RemoteSearchable.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/RemoteSearchable.java?rev=764551&r1=764550&r2=764551&view=diff
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/RemoteSearchable.java (original)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/RemoteSearchable.java Mon Apr 13 18:33:56 2009
@@ -45,12 +45,17 @@
this.local = local;
}
-
+ /** @deprecated use {@link #search(Weight, Filter, Collector)} instead. */
public void search(Weight weight, Filter filter, HitCollector results)
throws IOException {
local.search(weight, filter, results);
}
+ public void search(Weight weight, Filter filter, Collector results)
+ throws IOException {
+ local.search(weight, filter, results);
+ }
+
public void close() throws IOException {
local.close();
}
Added: lucene/java/trunk/src/java/org/apache/lucene/search/ScoreCachingWrappingScorer.java
URL: http://svn.apache.org/viewvc/lucene/java/trunk/src/java/org/apache/lucene/search/ScoreCachingWrappingScorer.java?rev=764551&view=auto
==============================================================================
--- lucene/java/trunk/src/java/org/apache/lucene/search/ScoreCachingWrappingScorer.java (added)
+++ lucene/java/trunk/src/java/org/apache/lucene/search/ScoreCachingWrappingScorer.java Mon Apr 13 18:33:56 2009
@@ -0,0 +1,83 @@
+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 java.io.IOException;
+
+/**
+ * A {@link Scorer} which wraps another scorer and caches the score of the
+ * current document. Successive calls to {@link #score()} will return the same
+ * result and will not invoke the wrapped Scorer's score() method, unless the
+ * current document has changed.<br>
+ * This class might be useful due to the changes done to the {@link Collector}
+ * interface, in which the score is not computed for a document by default, only
+ * if the collector requests it. Some collectors may need to use the score in
+ * several places, however all they have in hand is a {@link Scorer} object, and
+ * might end up computing the score of a document more than once.
+ */
+public class ScoreCachingWrappingScorer extends Scorer {
+
+ private Scorer scorer;
+ private int curDoc = -1;
+ private float curScore;
+
+ /** Creates a new instance by wrapping the given scorer. */
+ public ScoreCachingWrappingScorer(Scorer scorer) {
+ super(scorer.getSimilarity());
+ this.scorer = scorer;
+ }
+
+ protected boolean score(Collector collector, int max) throws IOException {
+ return scorer.score(collector, max);
+ }
+
+ public Similarity getSimilarity() {
+ return scorer.getSimilarity();
+ }
+
+ public Explanation explain(int doc) throws IOException {
+ return scorer.explain(doc);
+ }
+
+ public float score() throws IOException {
+ int doc = scorer.doc();
+ if (doc != curDoc) {
+ curScore = scorer.score();
+ curDoc = doc;
+ }
+
+ return curScore;
+ }
+
+ public int doc() {
+ return scorer.doc();
+ }
+
+ public boolean next() throws IOException {
+ return scorer.next();
+ }
+
+ public void score(Collector collector) throws IOException {
+ scorer.score(collector);
+ }
+
+ public boolean skipTo(int target) throws IOException {
+ return scorer.skipTo(target);
+ }
+
+}