mirror of https://github.com/apache/lucene.git
Latest patches to hit sorting code, including unit tests, two of which currently fail.
git-svn-id: https://svn.apache.org/repos/asf/lucene/java/trunk@150207 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
12eee6df5a
commit
60f1d192c7
|
@ -33,8 +33,10 @@ import java.io.IOException;
|
|||
class FieldDocSortedHitQueue
|
||||
extends PriorityQueue {
|
||||
|
||||
// this cannot contain AUTO fields
|
||||
SortField[] fields;
|
||||
// this cannot contain AUTO fields - any AUTO fields should
|
||||
// have been resolved by the time this class is used.
|
||||
volatile SortField[] fields;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a hit queue sorted by the given list of fields.
|
||||
|
@ -51,15 +53,14 @@ extends PriorityQueue {
|
|||
|
||||
/**
|
||||
* Allows redefinition of sort fields if they are <code>null</code>.
|
||||
* 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. This
|
||||
* method is thread safe.
|
||||
* 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 is thread safe.
|
||||
* @param fields
|
||||
*/
|
||||
synchronized void setFields (SortField[] fields) {
|
||||
if (fields == null) this.fields = fields;
|
||||
if (this.fields == null) this.fields = fields;
|
||||
}
|
||||
|
||||
|
||||
|
@ -92,12 +93,16 @@ extends PriorityQueue {
|
|||
break;
|
||||
case SortField.DOC:
|
||||
case SortField.INT:
|
||||
case SortField.STRING:
|
||||
int i1 = ((Integer)docA.fields[i]).intValue();
|
||||
int i2 = ((Integer)docB.fields[i]).intValue();
|
||||
if (i1 > i2) c = -1;
|
||||
if (i1 < i2) c = 1;
|
||||
break;
|
||||
case SortField.STRING:
|
||||
String s1 = (String) docA.fields[i];
|
||||
String s2 = (String) docB.fields[i];
|
||||
c = s2.compareTo(s1);
|
||||
break;
|
||||
case SortField.FLOAT:
|
||||
float f1 = ((Float)docA.fields[i]).floatValue();
|
||||
float f2 = ((Float)docB.fields[i]).floatValue();
|
||||
|
@ -123,12 +128,16 @@ extends PriorityQueue {
|
|||
break;
|
||||
case SortField.DOC:
|
||||
case SortField.INT:
|
||||
case SortField.STRING:
|
||||
int i1 = ((Integer)docA.fields[i]).intValue();
|
||||
int i2 = ((Integer)docB.fields[i]).intValue();
|
||||
if (i1 < i2) c = -1;
|
||||
if (i1 > i2) c = 1;
|
||||
break;
|
||||
case SortField.STRING:
|
||||
String s1 = (String) docA.fields[i];
|
||||
String s2 = (String) docB.fields[i];
|
||||
c = s1.compareTo(s2);
|
||||
break;
|
||||
case SortField.FLOAT:
|
||||
float f1 = ((Float)docA.fields[i]).floatValue();
|
||||
float f2 = ((Float)docB.fields[i]).floatValue();
|
||||
|
@ -148,4 +157,4 @@ extends PriorityQueue {
|
|||
}
|
||||
return c > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,11 +39,16 @@ import java.util.regex.Pattern;
|
|||
*
|
||||
* <p>A static cache is maintained. This cache contains an integer
|
||||
* or float array of length <code>IndexReader.maxDoc()</code> for each field
|
||||
* name for which a sort is performed. In other words, the size of
|
||||
* the cache in bytes is:
|
||||
* name for which a sort is performed. In other words, the size of the
|
||||
* cache in bytes is:
|
||||
*
|
||||
* <p><code>4 * IndexReader.maxDoc() * (# of different fields actually used to sort)</code>
|
||||
*
|
||||
* <p>For String fields, the cache is larger: in addition to the
|
||||
* above array, the value of every term in the field is kept in memory.
|
||||
* If there are many unique terms in the field, this could
|
||||
* be quite large.
|
||||
*
|
||||
* <p>Note that the size of the cache is not affected by how many
|
||||
* fields are in the index and <i>might</i> be used to sort - only by
|
||||
* the ones actually used to sort a result set.
|
||||
|
@ -172,7 +177,7 @@ extends PriorityQueue {
|
|||
*/
|
||||
protected static ScoreDocComparator determineComparator (IndexReader reader, String field)
|
||||
throws IOException {
|
||||
|
||||
field = field.intern();
|
||||
TermEnum enumerator = reader.terms (new Term (field, ""));
|
||||
try {
|
||||
Term term = enumerator.term();
|
||||
|
|
|
@ -66,12 +66,13 @@ extends FieldSortedHitQueue {
|
|||
/**
|
||||
* Returns a comparator for sorting hits according to a field containing floats.
|
||||
* @param reader Index to use.
|
||||
* @param field Field containg float values.
|
||||
* @param fieldname Field containg float values.
|
||||
* @return Comparator for sorting hits.
|
||||
* @throws IOException If an error occurs reading the index.
|
||||
*/
|
||||
static ScoreDocLookupComparator comparator (final IndexReader reader, final String field)
|
||||
static ScoreDocLookupComparator comparator (final IndexReader reader, final String fieldname)
|
||||
throws IOException {
|
||||
final String field = fieldname.intern();
|
||||
return new ScoreDocLookupComparator () {
|
||||
|
||||
protected final float[] fieldOrder = generateSortIndex();
|
||||
|
@ -140,12 +141,13 @@ extends FieldSortedHitQueue {
|
|||
* Returns a comparator for sorting hits according to a field containing floats using the given enumerator
|
||||
* to collect term values.
|
||||
* @param reader Index to use.
|
||||
* @param field Field containg float values.
|
||||
* @param fieldname Field containg float values.
|
||||
* @return Comparator for sorting hits.
|
||||
* @throws IOException If an error occurs reading the index.
|
||||
*/
|
||||
static ScoreDocLookupComparator comparator (final IndexReader reader, final TermEnum enumerator, final String field)
|
||||
static ScoreDocLookupComparator comparator (final IndexReader reader, final TermEnum enumerator, final String fieldname)
|
||||
throws IOException {
|
||||
final String field = fieldname.intern();
|
||||
return new ScoreDocLookupComparator () {
|
||||
|
||||
protected final float[] fieldOrder = generateSortIndex();
|
||||
|
@ -202,4 +204,4 @@ extends FieldSortedHitQueue {
|
|||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,8 +28,8 @@ import java.io.IOException;
|
|||
* Expert: A sorted hit queue for fields that contain strictly integer values.
|
||||
* Hits are sorted into the queue by the values in the field and then by document number.
|
||||
*
|
||||
* <p>Created: Jan 30, 2004 3:35:09 PM
|
||||
*
|
||||
* <p>Created: Jan 30, 2004 3:35:09 PM
|
||||
*
|
||||
* @author Tim Jones (Nacimiento Software)
|
||||
* @since lucene 1.4
|
||||
* @version $Id$
|
||||
|
@ -67,12 +67,13 @@ extends FieldSortedHitQueue {
|
|||
/**
|
||||
* Returns a comparator for sorting hits according to a field containing integers.
|
||||
* @param reader Index to use.
|
||||
* @param field Field containg integer values.
|
||||
* @param fieldname Field containg integer values.
|
||||
* @return Comparator for sorting hits.
|
||||
* @throws IOException If an error occurs reading the index.
|
||||
*/
|
||||
static ScoreDocLookupComparator comparator (final IndexReader reader, final String field)
|
||||
static ScoreDocLookupComparator comparator (final IndexReader reader, final String fieldname)
|
||||
throws IOException {
|
||||
final String field = fieldname.intern();
|
||||
return new ScoreDocLookupComparator() {
|
||||
|
||||
/** The sort information being used by this instance */
|
||||
|
@ -142,12 +143,13 @@ extends FieldSortedHitQueue {
|
|||
* Returns a comparator for sorting hits according to a field containing integers using the given enumerator
|
||||
* to collect term values.
|
||||
* @param reader Index to use.
|
||||
* @param field Field containg integer values.
|
||||
* @param fieldname Field containg integer values.
|
||||
* @return Comparator for sorting hits.
|
||||
* @throws IOException If an error occurs reading the index.
|
||||
*/
|
||||
static ScoreDocLookupComparator comparator (final IndexReader reader, final TermEnum enumerator, final String field)
|
||||
static ScoreDocLookupComparator comparator (final IndexReader reader, final TermEnum enumerator, final String fieldname)
|
||||
throws IOException {
|
||||
final String field = fieldname.intern();
|
||||
return new ScoreDocLookupComparator() {
|
||||
|
||||
protected final int[] fieldOrder = generateSortIndex();
|
||||
|
@ -204,4 +206,4 @@ extends FieldSortedHitQueue {
|
|||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,8 +26,8 @@ import java.io.IOException;
|
|||
* The type of content in each field could be determined dynamically by
|
||||
* FieldSortedHitQueue.determineComparator().
|
||||
*
|
||||
* <p>Created: Feb 3, 2004 4:46:55 PM
|
||||
*
|
||||
* <p>Created: Feb 3, 2004 4:46:55 PM
|
||||
*
|
||||
* @author Tim Jones (Nacimiento Software)
|
||||
* @since lucene 1.4
|
||||
* @version $Id$
|
||||
|
@ -50,8 +50,9 @@ extends PriorityQueue {
|
|||
comparators = new ScoreDocComparator[n];
|
||||
this.fields = new SortField[n];
|
||||
for (int i=0; i<n; ++i) {
|
||||
comparators[i] = FieldSortedHitQueue.getCachedComparator (reader, fields[i].getField(), fields[i].getType());
|
||||
this.fields[i] = new SortField (fields[i].getField(), comparators[i].sortType(), fields[i].getReverse());
|
||||
String fieldname = fields[i].getField();
|
||||
comparators[i] = FieldSortedHitQueue.getCachedComparator (reader, fieldname, fields[i].getType());
|
||||
this.fields[i] = new SortField (fieldname, comparators[i].sortType(), fields[i].getReverse());
|
||||
}
|
||||
initialize (size);
|
||||
}
|
||||
|
@ -107,4 +108,4 @@ extends PriorityQueue {
|
|||
SortField[] getFields() {
|
||||
return fields;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,12 +18,62 @@ package org.apache.lucene.search;
|
|||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
/**
|
||||
* Encapsulates sort criteria for returned hits. The sort criteria can
|
||||
* be changed between calls to Searcher#search(). This class is thread safe.
|
||||
* Encapsulates sort criteria for returned hits.
|
||||
*
|
||||
* <p>The fields used to determine sort order must be carefully chosen.
|
||||
* Documents must contain a single term in such a field,
|
||||
* and the value of the term should indicate the document's relative position in
|
||||
* a given sort order. The field must be indexed, but should not be tokenized,
|
||||
* and does not need to be stored (unless you happen to want it back with the
|
||||
* rest of your document data). In other words:
|
||||
*
|
||||
* <dl><dd><code>document.add (new Field ("byNumber", Integer.toString(x), false, true, false));</code>
|
||||
* </dd></dl>
|
||||
*
|
||||
* <p><h3>Valid Types of Values</h3>
|
||||
*
|
||||
* <p>There are three possible kinds of term values which may be put into
|
||||
* sorting fields: Integers, Floats, or Strings. Unless
|
||||
* {@link SortField SortField} objects are specified, the type of value
|
||||
* in the field is determined by using a regular expression against the
|
||||
* first term in the field.
|
||||
*
|
||||
* <p>Integer term values should contain only digits and an optional
|
||||
* preceeding negative sign. Values must be base 10 and in the range
|
||||
* <code>Integer.MIN_VALUE</code> and <code>Integer.MAX_VALUE</code> inclusive.
|
||||
* Documents which should appear first in the sort
|
||||
* should have low value integers, later documents high values
|
||||
* (i.e. the documents should be numbered <code>1..n</code> where
|
||||
* <code>1</code> is the first and <code>n</code> the last).
|
||||
*
|
||||
* <p>Float term values should conform to values accepted by
|
||||
* {@link Float Float.valueOf(String)} (except that <code>NaN</code>
|
||||
* and <code>Infinity</code> are not supported).
|
||||
* Documents which should appear first in the sort
|
||||
* should have low values, later documents high values.
|
||||
*
|
||||
* <p>String term values can contain any valid String, but should
|
||||
* not be tokenized. The values are sorted according to their
|
||||
* {@link Comparable natural order}. Note that using this type
|
||||
* of term value has higher memory requirements than the other
|
||||
* two types - see {@link FieldSortedHitQueue FieldSortedHitQueue}.
|
||||
*
|
||||
* <p><h3>Object Reuse</h3>
|
||||
*
|
||||
* <p>One of these objects can be
|
||||
* used multiple times and the sort order changed between usages.
|
||||
*
|
||||
* <p>This class is thread safe.
|
||||
*
|
||||
* <p><h3>Memory Usage</h3>
|
||||
*
|
||||
* See {@link FieldSortedHitQueue FieldSortedHitQueue} for
|
||||
* information on the memory requirements of sorting hits.
|
||||
*
|
||||
* <p>Created: Feb 12, 2004 10:53:57 AM
|
||||
*
|
||||
* <p>Created: Feb 12, 2004 10:53:57 AM
|
||||
*
|
||||
* @author Tim Jones (Nacimiento Software)
|
||||
* @since lucene 1.4
|
||||
* @version $Id$
|
||||
|
@ -31,80 +81,95 @@ import java.io.Serializable;
|
|||
public class Sort
|
||||
implements Serializable {
|
||||
|
||||
/** Represents sorting by computed relevance. Using this sort criteria
|
||||
* returns the same results with slightly more overhead as calling
|
||||
* Searcher#search() without a sort criteria. */
|
||||
public static final Sort RELEVANCE =
|
||||
new Sort (new SortField[] { SortField.FIELD_SCORE, SortField.FIELD_DOC });
|
||||
/** Represents sorting by computed relevance. Using this sort criteria
|
||||
* returns the same results with slightly more overhead as calling
|
||||
* Searcher#search() without a sort criteria. */
|
||||
public static final Sort RELEVANCE = new Sort ();
|
||||
|
||||
/** Represents sorting by index order. */
|
||||
public static final Sort INDEXORDER = new Sort (SortField.FIELD_DOC);
|
||||
/** Represents sorting by index order. */
|
||||
public static final Sort INDEXORDER = new Sort (SortField.FIELD_DOC);
|
||||
|
||||
// internal representation of the sort criteria
|
||||
SortField[] fields;
|
||||
|
||||
|
||||
// internal representation of the sort criteria
|
||||
SortField[] fields;
|
||||
/** Sorts by computed relevance. This is the same sort criteria as
|
||||
* calling Searcher#search() without a sort criteria, only with
|
||||
* slightly more overhead. */
|
||||
public Sort() {
|
||||
this (new SortField[]{SortField.FIELD_SCORE, SortField.FIELD_DOC});
|
||||
}
|
||||
|
||||
|
||||
/** Sorts by the terms in <code>field</code> then by index order (document
|
||||
* number). */
|
||||
public Sort (String field) {
|
||||
setSort (field, false);
|
||||
}
|
||||
/** Sorts by the terms in <code>field</code> then by index order (document
|
||||
* number). */
|
||||
public Sort (String field) {
|
||||
setSort (field, false);
|
||||
}
|
||||
|
||||
/** Sorts possibly in reverse by the terms in <code>field</code> then by
|
||||
* index order (document number). */
|
||||
public Sort (String field, boolean reverse) {
|
||||
setSort (field, reverse);
|
||||
}
|
||||
|
||||
/** Sorts in succession by the terms in each field. */
|
||||
public Sort (String[] fields) {
|
||||
setSort (fields);
|
||||
}
|
||||
/** Sorts possibly in reverse by the terms in <code>field</code> then by
|
||||
* index order (document number). */
|
||||
public Sort (String field, boolean reverse) {
|
||||
setSort (field, reverse);
|
||||
}
|
||||
|
||||
/** Sorts by the criteria in the given SortField. */
|
||||
public Sort (SortField field) {
|
||||
setSort (field);
|
||||
}
|
||||
|
||||
/** Sorts in succession by the criteria in each SortField. */
|
||||
public Sort (SortField[] fields) {
|
||||
setSort (fields);
|
||||
}
|
||||
/** Sorts in succession by the terms in each field. */
|
||||
public Sort (String[] fields) {
|
||||
setSort (fields);
|
||||
}
|
||||
|
||||
/** Sets the sort to the terms in <code>field</code> then by index order
|
||||
* (document number). */
|
||||
public final void setSort (String field) {
|
||||
setSort (field, false);
|
||||
}
|
||||
|
||||
/** Sets the sort to the terms in <code>field</code> possibly in reverse,
|
||||
* then by index order (document number). */
|
||||
public void setSort (String field, boolean reverse) {
|
||||
SortField[] nfields = new SortField[] {
|
||||
new SortField (field, SortField.AUTO, reverse),
|
||||
new SortField (field, SortField.DOC)
|
||||
};
|
||||
fields = nfields;
|
||||
}
|
||||
/** Sorts by the criteria in the given SortField. */
|
||||
public Sort (SortField field) {
|
||||
setSort (field);
|
||||
}
|
||||
|
||||
/** Sets the sort to the terms in each field in succession. */
|
||||
public void setSort (String[] fieldnames) {
|
||||
final int n = fieldnames.length;
|
||||
SortField[] nfields = new SortField[n];
|
||||
for (int i=0; i<n; ++i) {
|
||||
nfields[i] = new SortField (fieldnames[i], SortField.AUTO);
|
||||
}
|
||||
fields = nfields;
|
||||
}
|
||||
|
||||
/** Sets the sort to the given criteria. */
|
||||
public void setSort (SortField field) {
|
||||
this.fields = new SortField[] { field };
|
||||
}
|
||||
/** Sorts in succession by the criteria in each SortField. */
|
||||
public Sort (SortField[] fields) {
|
||||
setSort (fields);
|
||||
}
|
||||
|
||||
/** Sets the sort to the given criteria in succession. */
|
||||
public void setSort (SortField[] fields) {
|
||||
this.fields = fields;
|
||||
}
|
||||
|
||||
/** Sets the sort to the terms in <code>field</code> then by index order
|
||||
* (document number). */
|
||||
public final void setSort (String field) {
|
||||
setSort (field, false);
|
||||
}
|
||||
|
||||
|
||||
/** Sets the sort to the terms in <code>field</code> possibly in reverse,
|
||||
* then by index order (document number). */
|
||||
public void setSort (String field, boolean reverse) {
|
||||
SortField[] nfields = new SortField[]{
|
||||
new SortField (field, SortField.AUTO, reverse),
|
||||
new SortField (field, SortField.DOC)
|
||||
};
|
||||
fields = nfields;
|
||||
}
|
||||
|
||||
|
||||
/** Sets the sort to the terms in each field in succession. */
|
||||
public void setSort (String[] fieldnames) {
|
||||
final int n = fieldnames.length;
|
||||
SortField[] nfields = new SortField[n];
|
||||
for (int i = 0; i < n; ++i) {
|
||||
nfields[i] = new SortField (fieldnames[i], SortField.AUTO);
|
||||
}
|
||||
fields = nfields;
|
||||
}
|
||||
|
||||
|
||||
/** Sets the sort to the given criteria. */
|
||||
public void setSort (SortField field) {
|
||||
this.fields = new SortField[]{field};
|
||||
}
|
||||
|
||||
|
||||
/** Sets the sort to the given criteria in succession. */
|
||||
public void setSort (SortField[] fields) {
|
||||
this.fields = fields;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ implements Serializable {
|
|||
* @param field Name of field to sort by, cannot be <code>null</code>.
|
||||
*/
|
||||
public SortField (String field) {
|
||||
this.field = field;
|
||||
this.field = field.intern();
|
||||
}
|
||||
|
||||
/** Creates a sort, possibly in reverse, by terms in the given field where
|
||||
|
@ -83,7 +83,7 @@ implements Serializable {
|
|||
* @param reverse True if natural order should be reversed.
|
||||
*/
|
||||
public SortField (String field, boolean reverse) {
|
||||
this.field = field;
|
||||
this.field = field.intern();
|
||||
this.reverse = reverse;
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,7 @@ implements Serializable {
|
|||
* @param type Type of values in the terms.
|
||||
*/
|
||||
public SortField (String field, int type) {
|
||||
this.field = field;
|
||||
this.field = (field != null) ? field.intern() : field;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
@ -106,7 +106,7 @@ implements Serializable {
|
|||
* @param reverse True if natural order should be reversed.
|
||||
*/
|
||||
public SortField (String field, int type, boolean reverse) {
|
||||
this.field = field;
|
||||
this.field = (field != null) ? field.intern() : field;
|
||||
this.type = type;
|
||||
this.reverse = reverse;
|
||||
}
|
||||
|
|
|
@ -223,4 +223,4 @@ extends FieldSortedHitQueue {
|
|||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,341 @@
|
|||
package org.apache.lucene.search;
|
||||
|
||||
/**
|
||||
* Copyright 2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed 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.store.RAMDirectory;
|
||||
import org.apache.lucene.index.IndexWriter;
|
||||
import org.apache.lucene.index.Term;
|
||||
import org.apache.lucene.analysis.SimpleAnalyzer;
|
||||
import org.apache.lucene.document.Document;
|
||||
import org.apache.lucene.document.Field;
|
||||
|
||||
import java.rmi.Naming;
|
||||
import java.rmi.registry.LocateRegistry;
|
||||
import java.rmi.registry.Registry;
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
import junit.textui.TestRunner;
|
||||
|
||||
/**
|
||||
* Unit tests for sorting code.
|
||||
*
|
||||
* <p>Created: Feb 17, 2004 4:55:10 PM
|
||||
*
|
||||
* @author Tim Jones (Nacimiento Software)
|
||||
* @since lucene 1.4
|
||||
* @version $Id$
|
||||
*/
|
||||
|
||||
public class TestSort
|
||||
extends TestCase {
|
||||
|
||||
private Searcher full;
|
||||
private Searcher searchX;
|
||||
private Searcher searchY;
|
||||
private Query queryX;
|
||||
private Query queryY;
|
||||
private Query queryA;
|
||||
private Sort sort;
|
||||
|
||||
|
||||
public TestSort (String name) {
|
||||
super (name);
|
||||
}
|
||||
|
||||
public static void main (String[] argv) {
|
||||
if (argv == null || argv.length < 1)
|
||||
TestRunner.run (suite());
|
||||
else if ("server".equals (argv[0])) {
|
||||
TestSort test = new TestSort (null);
|
||||
try {
|
||||
test.startServer();
|
||||
Thread.sleep (500000);
|
||||
} catch (Exception e) {
|
||||
System.out.println (e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
return new TestSuite (TestSort.class);
|
||||
}
|
||||
|
||||
|
||||
// document data:
|
||||
// the tracer field is used to determine which document was hit
|
||||
// the contents field is used to search and sort by relevance
|
||||
// the int field to sort by int
|
||||
// the float field to sort by float
|
||||
// the string field to sort by string
|
||||
private String[][] data = new String[][] {
|
||||
// tracer contents int float string
|
||||
{ "A", "x a", "5", "4f", "c" },
|
||||
{ "B", "y a", "5", "3.4028235E38", "i" },
|
||||
{ "C", "x a b c", "2147483647", "1.0", "j" },
|
||||
{ "D", "y a b c", "-1", "0.0f", "a" },
|
||||
{ "E", "x a b c d", "5", "2f", "h" },
|
||||
{ "F", "y a b c d", "2", "3.14159f", "g" },
|
||||
{ "G", "x a b c d", "3", "-1.0", "f" },
|
||||
{ "H", "y a b c d", "0", "1.4E-45", "e" },
|
||||
{ "I", "x a b c d e f", "-2147483648", "1.0e+0", "d" },
|
||||
{ "J", "y a b c d e f", "4", ".5", "b" },
|
||||
};
|
||||
|
||||
// create an index of all the documents, or just the x, or just the y documents
|
||||
private Searcher getIndex (boolean even, boolean odd)
|
||||
throws IOException {
|
||||
RAMDirectory indexStore = new RAMDirectory ();
|
||||
IndexWriter writer = new IndexWriter (indexStore, new SimpleAnalyzer(), true);
|
||||
for (int i=0; i<data.length; ++i) {
|
||||
if (((i%2)==0 && even) || ((i%2)==1 && odd)) {
|
||||
Document doc = new Document(); // store, index, token
|
||||
doc.add (new Field ("tracer", data[i][0], true, false, false));
|
||||
doc.add (new Field ("contents", data[i][1], false, true, true));
|
||||
doc.add (new Field ("int", data[i][2], false, true, false));
|
||||
doc.add (new Field ("float", data[i][3], false, true, false));
|
||||
doc.add (new Field ("string", data[i][4], false, true, false));
|
||||
writer.addDocument (doc);
|
||||
}
|
||||
}
|
||||
writer.optimize ();
|
||||
writer.close ();
|
||||
return new IndexSearcher (indexStore);
|
||||
}
|
||||
|
||||
private Searcher getFullIndex()
|
||||
throws IOException {
|
||||
return getIndex (true, true);
|
||||
}
|
||||
|
||||
private Searcher getXIndex()
|
||||
throws IOException {
|
||||
return getIndex (true, false);
|
||||
}
|
||||
|
||||
private Searcher getYIndex()
|
||||
throws IOException {
|
||||
return getIndex (false, true);
|
||||
}
|
||||
|
||||
public void setUp() throws Exception {
|
||||
full = getFullIndex();
|
||||
searchX = getXIndex();
|
||||
searchY = getYIndex();
|
||||
queryX = new TermQuery (new Term ("contents", "x"));
|
||||
queryY = new TermQuery (new Term ("contents", "y"));
|
||||
queryA = new TermQuery (new Term ("contents", "a"));
|
||||
sort = new Sort();
|
||||
}
|
||||
|
||||
// test the sorts by score and document number
|
||||
public void testBuiltInSorts() throws Exception {
|
||||
sort = new Sort();
|
||||
assertMatches (full, queryX, sort, "ACEGI");
|
||||
assertMatches (full, queryY, sort, "BDFHJ");
|
||||
|
||||
sort.setSort(SortField.FIELD_DOC);
|
||||
assertMatches (full, queryX, sort, "ACEGI");
|
||||
assertMatches (full, queryY, sort, "BDFHJ");
|
||||
}
|
||||
|
||||
// test sorts where the type of field is specified
|
||||
public void testTypedSort() throws Exception {
|
||||
sort.setSort (new SortField[] { new SortField ("int", SortField.INT), SortField.FIELD_DOC });
|
||||
assertMatches (full, queryX, sort, "IGAEC");
|
||||
assertMatches (full, queryY, sort, "DHFJB");
|
||||
|
||||
sort.setSort (new SortField[] { new SortField ("float", SortField.FLOAT), SortField.FIELD_DOC });
|
||||
assertMatches (full, queryX, sort, "GCIEA");
|
||||
assertMatches (full, queryY, sort, "DHJFB");
|
||||
|
||||
sort.setSort (new SortField[] { new SortField ("string", SortField.STRING), SortField.FIELD_DOC });
|
||||
assertMatches (full, queryX, sort, "AIGEC");
|
||||
assertMatches (full, queryY, sort, "DJHFB");
|
||||
}
|
||||
|
||||
// test sorts where the type of field is determined dynamically
|
||||
public void testAutoSort() throws Exception {
|
||||
sort.setSort("int");
|
||||
assertMatches (full, queryX, sort, "IGAEC");
|
||||
assertMatches (full, queryY, sort, "DHFJB");
|
||||
|
||||
sort.setSort("float");
|
||||
assertMatches (full, queryX, sort, "GCIEA");
|
||||
assertMatches (full, queryY, sort, "DHJFB");
|
||||
|
||||
sort.setSort("string");
|
||||
assertMatches (full, queryX, sort, "AIGEC");
|
||||
assertMatches (full, queryY, sort, "DJHFB");
|
||||
}
|
||||
|
||||
// test sorts in reverse
|
||||
public void testReverseSort() throws Exception {
|
||||
sort.setSort (new SortField[] { new SortField (null, SortField.SCORE, true), SortField.FIELD_DOC });
|
||||
assertMatches (full, queryX, sort, "IEGCA");
|
||||
assertMatches (full, queryY, sort, "JFHDB");
|
||||
|
||||
sort.setSort (new SortField (null, SortField.DOC, true));
|
||||
assertMatches (full, queryX, sort, "IGECA");
|
||||
assertMatches (full, queryY, sort, "JHFDB");
|
||||
|
||||
sort.setSort ("int", true);
|
||||
assertMatches (full, queryX, sort, "CAEGI");
|
||||
assertMatches (full, queryY, sort, "BJFHD");
|
||||
|
||||
sort.setSort ("float", true);
|
||||
assertMatches (full, queryX, sort, "AECIG");
|
||||
assertMatches (full, queryY, sort, "BFJHD");
|
||||
|
||||
sort.setSort ("string", true);
|
||||
assertMatches (full, queryX, sort, "CEGIA");
|
||||
assertMatches (full, queryY, sort, "BFHJD");
|
||||
}
|
||||
|
||||
// test sorts using a series of fields
|
||||
public void testSortCombos() throws Exception {
|
||||
sort.setSort (new String[] {"int","float"});
|
||||
assertMatches (full, queryX, sort, "IGEAC");
|
||||
|
||||
sort.setSort (new SortField[] { new SortField ("int", true), new SortField (null, SortField.DOC, true) });
|
||||
assertMatches (full, queryX, sort, "CEAGI");
|
||||
|
||||
sort.setSort (new String[] {"float","string"});
|
||||
assertMatches (full, queryX, sort, "GICEA");
|
||||
}
|
||||
|
||||
// test a variety of sorts using more than one searcher
|
||||
public void testMultiSort() throws Exception {
|
||||
MultiSearcher searcher = new MultiSearcher (new Searchable[] { searchX, searchY });
|
||||
runMultiSorts (searcher);
|
||||
}
|
||||
|
||||
// test a variety of sorts using a parallel multisearcher
|
||||
public void testParallelMultiSort() throws Exception {
|
||||
Searcher searcher = new ParallelMultiSearcher (new Searchable[] { searchX, searchY });
|
||||
runMultiSorts (searcher);
|
||||
}
|
||||
|
||||
// test a variety of sorts using a remote searcher
|
||||
public void testRemoteSort() throws Exception {
|
||||
Searchable searcher = getRemote();
|
||||
MultiSearcher multi = new MultiSearcher (new Searchable[] { searcher });
|
||||
runMultiSorts (multi);
|
||||
}
|
||||
|
||||
// runs a variety of sorts useful for multisearchers
|
||||
private void runMultiSorts (Searcher multi) throws Exception {
|
||||
sort.setSort (SortField.FIELD_DOC);
|
||||
assertMatchesPattern (multi, queryA, sort, "[AB]{2}[CD]{2}[EF]{2}[GH]{2}[IJ]{2}");
|
||||
|
||||
sort.setSort (new SortField ("int", SortField.INT));
|
||||
assertMatchesPattern (multi, queryA, sort, "IDHFGJ[ABE]{3}C");
|
||||
|
||||
sort.setSort (new SortField[] {new SortField ("int", SortField.INT), SortField.FIELD_DOC});
|
||||
assertMatchesPattern (multi, queryA, sort, "IDHFGJ[AB]{2}EC");
|
||||
|
||||
sort.setSort ("int");
|
||||
assertMatchesPattern (multi, queryA, sort, "IDHFGJ[AB]{2}EC");
|
||||
|
||||
sort.setSort (new SortField[] {new SortField ("float", SortField.FLOAT), SortField.FIELD_DOC});
|
||||
assertMatchesPattern (multi, queryA, sort, "GDHJ[CI]{2}EFAB");
|
||||
|
||||
sort.setSort ("float");
|
||||
assertMatchesPattern (multi, queryA, sort, "GDHJ[CI]{2}EFAB");
|
||||
|
||||
sort.setSort ("string");
|
||||
assertMatches (multi, queryA, sort, "DJAIHGFEBC");
|
||||
|
||||
sort.setSort ("int", true);
|
||||
assertMatchesPattern (multi, queryA, sort, "C[AB]{2}EJGFHDI");
|
||||
|
||||
sort.setSort ("float", true);
|
||||
assertMatchesPattern (multi, queryA, sort, "BAFE[IC]{2}JHDG");
|
||||
|
||||
sort.setSort ("string", true);
|
||||
assertMatches (multi, queryA, sort, "CBEFGHIAJD");
|
||||
|
||||
sort.setSort (new String[] {"int","float"});
|
||||
assertMatches (full, queryA, sort, "IDHFGJEABC");
|
||||
|
||||
sort.setSort (new String[] {"float","string"});
|
||||
assertMatches (full, queryA, sort, "GDHJICEFAB");
|
||||
}
|
||||
|
||||
// make sure the documents returned by the search match the expected list
|
||||
private void assertMatches (Searcher searcher, Query query, Sort sort, String expectedResult)
|
||||
throws IOException {
|
||||
Hits result = searcher.search (query, sort);
|
||||
StringBuffer buff = new StringBuffer(10);
|
||||
int n = result.length();
|
||||
for (int i=0; i<n; ++i) {
|
||||
Document doc = result.doc(i);
|
||||
String[] v = doc.getValues("tracer");
|
||||
for (int j=0; j<v.length; ++j) {
|
||||
buff.append (v[j]);
|
||||
}
|
||||
}
|
||||
assertEquals (expectedResult, buff.toString());
|
||||
}
|
||||
|
||||
// make sure the documents returned by the search match the expected list pattern
|
||||
private void assertMatchesPattern (Searcher searcher, Query query, Sort sort, String pattern)
|
||||
throws IOException {
|
||||
Hits result = searcher.search (query, sort);
|
||||
StringBuffer buff = new StringBuffer(10);
|
||||
int n = result.length();
|
||||
for (int i=0; i<n; ++i) {
|
||||
Document doc = result.doc(i);
|
||||
String[] v = doc.getValues("tracer");
|
||||
for (int j=0; j<v.length; ++j) {
|
||||
buff.append (v[j]);
|
||||
}
|
||||
}
|
||||
// System.out.println ("matching \""+buff+"\" against pattern \""+pattern+"\"");
|
||||
assertTrue (Pattern.compile(pattern).matcher(buff.toString()).matches());
|
||||
}
|
||||
|
||||
|
||||
private Searchable getRemote () throws Exception {
|
||||
try {
|
||||
return lookupRemote ();
|
||||
} catch (Throwable e) {
|
||||
startServer ();
|
||||
return lookupRemote ();
|
||||
}
|
||||
}
|
||||
|
||||
private Searchable lookupRemote () throws Exception {
|
||||
return (Searchable) Naming.lookup ("//localhost/SortedSearchable");
|
||||
}
|
||||
|
||||
private void startServer () throws Exception {
|
||||
// construct an index
|
||||
Searcher local = getFullIndex();
|
||||
// local.search (queryA, new Sort());
|
||||
|
||||
// publish it
|
||||
Registry reg = LocateRegistry.createRegistry (1099);
|
||||
RemoteSearchable impl = new RemoteSearchable (local);
|
||||
Naming.rebind ("//localhost/SortedSearchable", impl);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue