SOLR-1299: use FieldComparator to derive sort field values in distributed search, fix a bug in the SortMissingLast comparator

git-svn-id: https://svn.apache.org/repos/asf/lucene/solr/trunk@800857 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Yonik Seeley 2009-08-04 15:53:34 +00:00
parent b7afc29aac
commit ba2baa2f47
3 changed files with 13 additions and 244 deletions

View File

@ -185,7 +185,6 @@ public class QueryComponent extends SearchComponent
if(fsv){
Sort sort = rb.getSortSpec().getSort();
SortField[] sortFields = sort==null ? new SortField[]{SortField.FIELD_SCORE} : sort.getSort();
ScoreDoc sd = new ScoreDoc(0,1.0f); // won't work for comparators that look at the score
NamedList sortVals = new NamedList(); // order is important for the sort fields
Field field = new Field("dummy", "", Field.Store.YES, Field.Index.NO); // a dummy Field
@ -203,8 +202,8 @@ public class QueryComponent extends SearchComponent
int type = sortField.getType();
if (type==SortField.SCORE || type==SortField.DOC) continue;
ScoreDocComparator comparator = null;
ScoreDocComparator comparators[] = (readers==null) ? null : new ScoreDocComparator[readers.length];
FieldComparator comparator = null;
FieldComparator comparators[] = (readers==null) ? null : new FieldComparator[readers.length];
String fieldname = sortField.getField();
FieldType ft = fieldname==null ? null : req.getSchema().getFieldTypeNoEx(fieldname);
@ -217,23 +216,25 @@ public class QueryComponent extends SearchComponent
int idx = 0;
while(it.hasNext()) {
sd.doc = it.nextDoc();
int doc = it.nextDoc();
if (readers != null) {
idx = SolrIndexReader.readerIndex(sd.doc, offsets);
idx = SolrIndexReader.readerIndex(doc, offsets);
subReader = readers[idx];
offset = offsets[idx];
comparator = comparators[idx];
}
if (comparator == null) {
comparator = getComparator(subReader, sortField);
comparator = sortField.getComparator(1,0,sortField.getReverse());
comparator.setNextReader(subReader, offset, 0);
if (comparators != null)
comparators[idx] = comparator;
}
sd.doc -= offset; // adjust for what segment this is in
Object val = comparator.sortValue(sd);
doc -= offset; // adjust for what segment this is in
comparator.copy(0, doc);
Object val = comparator.value(0);
// Sortable float, double, int, long types all just use a string
// comparator. For these, we need to put the type into a readable
// format. One reason for this is that XML can't represent all
@ -244,6 +245,7 @@ public class QueryComponent extends SearchComponent
field.setValue((String)val);
val = ft.toObject(field);
}
vals.add(val);
}
@ -260,36 +262,6 @@ public class QueryComponent extends SearchComponent
}
}
private ScoreDocComparator getComparator(SolrIndexReader reader, SortField sortField) throws IOException {
ScoreDocComparator comparator = null;
String fieldname = sortField.getField();
switch (sortField.getType()) {
case SortField.INT:
comparator = comparatorInt (reader, fieldname, sortField.getParser());
break;
case SortField.FLOAT:
comparator = comparatorFloat (reader, fieldname, sortField.getParser());
break;
case SortField.LONG:
comparator = comparatorLong(reader, fieldname, sortField.getParser());
break;
case SortField.DOUBLE:
comparator = comparatorDouble(reader, fieldname, sortField.getParser());
break;
case SortField.STRING:
if (sortField.getLocale() != null) comparator = comparatorStringLocale (reader, fieldname, sortField.getLocale());
else comparator = comparatorString (reader, fieldname);
break;
case SortField.CUSTOM:
comparator = sortField.getFactory().newComparator (reader, fieldname);
// comparator = sortField.getComparatorSource().newComparator(fieldname,2,1,false);
break;
default:
throw new RuntimeException ("unknown field type: "+sortField.getType());
}
return comparator;
}
@Override
public int distributedProcess(ResponseBuilder rb) throws IOException {
if (rb.stage < ResponseBuilder.STAGE_PARSE_QUERY)
@ -570,210 +542,6 @@ public class QueryComponent extends SearchComponent
}
}
/////////////////////////////////////////////
/// Comparators copied from Lucene
/////////////////////////////////////////////
/**
* Returns a comparator for sorting hits according to a field containing integers.
* @param reader Index to use.
* @param fieldname Fieldable containg integer values.
* @param parser used to parse term values, null for default.
* @return Comparator for sorting hits.
* @throws IOException If an error occurs reading the index.
*/
static ScoreDocComparator comparatorInt (final IndexReader reader, final String fieldname, Parser parser)
throws IOException {
final String field = fieldname.intern();
final int[] fieldOrder = parser == null ? FieldCache.DEFAULT.getInts (reader, field) : FieldCache.DEFAULT.getInts (reader, field, (IntParser) parser);
return new ScoreDocComparator() {
public final int compare (final ScoreDoc i, final ScoreDoc j) {
final int fi = fieldOrder[i.doc];
final int fj = fieldOrder[j.doc];
if (fi < fj) return -1;
if (fi > fj) return 1;
return 0;
}
public Comparable sortValue (final ScoreDoc i) {
return new Integer (fieldOrder[i.doc]);
}
public int sortType() {
return SortField.INT;
}
};
}
/**
* Returns a comparator for sorting hits according to a field containing integers.
* @param reader Index to use.
* @param fieldname Fieldable containg integer values.
* @param parser used to parse term values, null for default.
* @return Comparator for sorting hits.
* @throws IOException If an error occurs reading the index.
*/
static ScoreDocComparator comparatorLong (final IndexReader reader, final String fieldname, Parser parser)
throws IOException {
final String field = fieldname.intern();
final long[] fieldOrder = parser == null ? FieldCache.DEFAULT.getLongs(reader, field) : FieldCache.DEFAULT.getLongs(reader, field, (LongParser) parser);
return new ScoreDocComparator() {
public final int compare (final ScoreDoc i, final ScoreDoc j) {
final long li = fieldOrder[i.doc];
final long lj = fieldOrder[j.doc];
if (li < lj) return -1;
if (li > lj) return 1;
return 0;
}
public Comparable sortValue (final ScoreDoc i) {
return new Long(fieldOrder[i.doc]);
}
public int sortType() {
return SortField.LONG;
}
};
}
/**
* Returns a comparator for sorting hits according to a field containing floats.
* @param reader Index to use.
* @param fieldname Fieldable containg float values.
* @param parser used to parse term values, null for default.
* @return Comparator for sorting hits.
* @throws IOException If an error occurs reading the index.
*/
static ScoreDocComparator comparatorFloat (final IndexReader reader, final String fieldname, Parser parser)
throws IOException {
final String field = fieldname.intern();
final float[] fieldOrder = parser == null ? FieldCache.DEFAULT.getFloats(reader, field) : FieldCache.DEFAULT.getFloats(reader, field, (FloatParser) parser);
return new ScoreDocComparator () {
public final int compare (final ScoreDoc i, final ScoreDoc j) {
final float fi = fieldOrder[i.doc];
final float fj = fieldOrder[j.doc];
if (fi < fj) return -1;
if (fi > fj) return 1;
return 0;
}
public Comparable sortValue (final ScoreDoc i) {
return new Float (fieldOrder[i.doc]);
}
public int sortType() {
return SortField.FLOAT;
}
};
}
/**
* Returns a comparator for sorting hits according to a field containing doubles.
* @param reader Index to use.
* @param fieldname Fieldable containg float values.
* @param parser used to parse term values, null for default.
* @return Comparator for sorting hits.
* @throws IOException If an error occurs reading the index.
*/
static ScoreDocComparator comparatorDouble(final IndexReader reader, final String fieldname, Parser parser)
throws IOException {
final String field = fieldname.intern();
final double[] fieldOrder = parser == null ? FieldCache.DEFAULT.getDoubles(reader, field) : FieldCache.DEFAULT.getDoubles(reader, field, (DoubleParser) parser);
return new ScoreDocComparator () {
public final int compare (final ScoreDoc i, final ScoreDoc j) {
final double di = fieldOrder[i.doc];
final double dj = fieldOrder[j.doc];
if (di < dj) return -1;
if (di > dj) return 1;
return 0;
}
public Comparable sortValue (final ScoreDoc i) {
return new Double (fieldOrder[i.doc]);
}
public int sortType() {
return SortField.DOUBLE;
}
};
}
/**
* Returns a comparator for sorting hits according to a field containing strings.
* @param reader Index to use.
* @param fieldname Fieldable containg string values.
* @return Comparator for sorting hits.
* @throws IOException If an error occurs reading the index.
*/
static ScoreDocComparator comparatorString (final IndexReader reader, final String fieldname)
throws IOException {
final String field = fieldname.intern();
final FieldCache.StringIndex index = FieldCache.DEFAULT.getStringIndex (reader, field);
return new ScoreDocComparator () {
public final int compare (final ScoreDoc i, final ScoreDoc j) {
final int fi = index.order[i.doc];
final int fj = index.order[j.doc];
if (fi < fj) return -1;
if (fi > fj) return 1;
return 0;
}
public Comparable sortValue (final ScoreDoc i) {
return index.lookup[index.order[i.doc]];
}
public int sortType() {
return SortField.STRING;
}
};
}
/**
* Returns a comparator for sorting hits according to a field containing strings.
* @param reader Index to use.
* @param fieldname Fieldable containg string values.
* @return Comparator for sorting hits.
* @throws IOException If an error occurs reading the index.
*/
static ScoreDocComparator comparatorStringLocale (final IndexReader reader, final String fieldname, final Locale locale)
throws IOException {
final Collator collator = Collator.getInstance (locale);
final String field = fieldname.intern();
final String[] index = FieldCache.DEFAULT.getStrings (reader, field);
return new ScoreDocComparator() {
public final int compare(final ScoreDoc i, final ScoreDoc j) {
String is = index[i.doc];
String js = index[j.doc];
if (is == js) {
return 0;
} else if (is == null) {
return -1;
} else if (js == null) {
return 1;
} else {
return collator.compare(is, js);
}
}
public Comparable sortValue (final ScoreDoc i) {
return index[i.doc];
}
public int sortType() {
return SortField.STRING;
}
};
}
/////////////////////////////////////////////
/// SolrInfoMBean
////////////////////////////////////////////

View File

@ -206,7 +206,7 @@ class MissingLastOrdComparator extends FieldComparator {
public Comparable value(int slot) {
Comparable v = values[slot];
return v==null ? nullVal : null;
return v==null ? nullVal : v;
}
public String[] getValues() {

View File

@ -497,6 +497,7 @@ public class TestDistributedSearch extends TestCase {
// these queries should be exactly ordered and scores should exactly match
query("q","*:*", "sort",i1+" desc");
query("q","*:*", "sort",i1+" asc");
query("q","*:*", "sort",i1+" desc", "fl","*,score");
query("q","*:*", "sort",tlong+" desc");
handle.put("maxScore", SKIPVAL);