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:
Doug Cutting 2004-02-24 19:34:58 +00:00
parent 12eee6df5a
commit 60f1d192c7
9 changed files with 527 additions and 102 deletions

View File

@ -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();

View File

@ -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();

View File

@ -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();

View File

@ -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();

View File

@ -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);
}

View File

@ -18,9 +18,59 @@ 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
*
@ -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;
}
}

View File

@ -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;
}

View File

@ -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);
}
}