SOLR-2198: handle null values in collapse field

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1038295 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Yonik Seeley 2010-11-23 19:34:32 +00:00
parent 59c9b46422
commit bcf1dcccbe
20 changed files with 186 additions and 58 deletions

View File

@ -512,7 +512,8 @@ public abstract class FieldType extends FieldProperties {
*/ */
@Deprecated @Deprecated
public ValueSource getValueSource(SchemaField field) { public ValueSource getValueSource(SchemaField field) {
return new OrdFieldSource(field.name); // return new OrdFieldSource(field.name);
return new StrFieldSource(field.name);
} }
/** /**

View File

@ -107,6 +107,8 @@ class SortableDoubleFieldSource extends FieldCacheSource {
final double def = defVal; final double def = defVal;
return new StringIndexDocValues(this, reader, field) { return new StringIndexDocValues(this, reader, field) {
private final BytesRef spare = new BytesRef();
protected String toTerm(String readableValue) { protected String toTerm(String readableValue) {
return NumberUtils.double2sortableStr(readableValue); return NumberUtils.double2sortableStr(readableValue);
} }
@ -125,7 +127,7 @@ class SortableDoubleFieldSource extends FieldCacheSource {
public double doubleVal(int doc) { public double doubleVal(int doc) {
int ord=termsIndex.getOrd(doc); int ord=termsIndex.getOrd(doc);
return ord==0 ? def : NumberUtils.SortableStr2double(termsIndex.lookup(ord, new BytesRef())); return ord==0 ? def : NumberUtils.SortableStr2double(termsIndex.lookup(ord, spare));
} }
public String strVal(int doc) { public String strVal(int doc) {
@ -148,7 +150,14 @@ class SortableDoubleFieldSource extends FieldCacheSource {
@Override @Override
public void fillValue(int doc) { public void fillValue(int doc) {
mval.value = doubleVal(doc); int ord=termsIndex.getOrd(doc);
if (ord == 0) {
mval.value = def;
mval.exists = false;
} else {
mval.value = NumberUtils.SortableStr2double(termsIndex.lookup(ord, spare));
mval.exists = true;
}
} }
}; };
} }

View File

@ -107,13 +107,15 @@ class SortableFloatFieldSource extends FieldCacheSource {
final float def = defVal; final float def = defVal;
return new StringIndexDocValues(this, reader, field) { return new StringIndexDocValues(this, reader, field) {
private final BytesRef spare = new BytesRef();
protected String toTerm(String readableValue) { protected String toTerm(String readableValue) {
return NumberUtils.float2sortableStr(readableValue); return NumberUtils.float2sortableStr(readableValue);
} }
public float floatVal(int doc) { public float floatVal(int doc) {
int ord=termsIndex.getOrd(doc); int ord=termsIndex.getOrd(doc);
return ord==0 ? def : NumberUtils.SortableStr2float(termsIndex.lookup(ord, new BytesRef())); return ord==0 ? def : NumberUtils.SortableStr2float(termsIndex.lookup(ord, spare));
} }
public int intVal(int doc) { public int intVal(int doc) {
@ -148,7 +150,14 @@ class SortableFloatFieldSource extends FieldCacheSource {
@Override @Override
public void fillValue(int doc) { public void fillValue(int doc) {
mval.value = floatVal(doc); int ord=termsIndex.getOrd(doc);
if (ord == 0) {
mval.value = def;
mval.exists = false;
} else {
mval.value = NumberUtils.SortableStr2float(termsIndex.lookup(ord, spare));
mval.exists = true;
}
} }
}; };
} }

View File

@ -111,6 +111,8 @@ class SortableIntFieldSource extends FieldCacheSource {
final int def = defVal; final int def = defVal;
return new StringIndexDocValues(this, reader, field) { return new StringIndexDocValues(this, reader, field) {
private final BytesRef spare = new BytesRef();
protected String toTerm(String readableValue) { protected String toTerm(String readableValue) {
return NumberUtils.int2sortableStr(readableValue); return NumberUtils.int2sortableStr(readableValue);
} }
@ -121,7 +123,7 @@ class SortableIntFieldSource extends FieldCacheSource {
public int intVal(int doc) { public int intVal(int doc) {
int ord=termsIndex.getOrd(doc); int ord=termsIndex.getOrd(doc);
return ord==0 ? def : NumberUtils.SortableStr2int(termsIndex.lookup(ord, new BytesRef()),0,3); return ord==0 ? def : NumberUtils.SortableStr2int(termsIndex.lookup(ord, spare),0,3);
} }
public long longVal(int doc) { public long longVal(int doc) {
@ -152,7 +154,14 @@ class SortableIntFieldSource extends FieldCacheSource {
@Override @Override
public void fillValue(int doc) { public void fillValue(int doc) {
mval.value = intVal(doc); int ord=termsIndex.getOrd(doc);
if (ord == 0) {
mval.value = def;
mval.exists = false;
} else {
mval.value = NumberUtils.SortableStr2int(termsIndex.lookup(ord, spare),0,3);
mval.exists = true;
}
} }
}; };
} }

View File

@ -108,6 +108,8 @@ class SortableLongFieldSource extends FieldCacheSource {
final long def = defVal; final long def = defVal;
return new StringIndexDocValues(this, reader, field) { return new StringIndexDocValues(this, reader, field) {
private final BytesRef spare = new BytesRef();
protected String toTerm(String readableValue) { protected String toTerm(String readableValue) {
return NumberUtils.long2sortableStr(readableValue); return NumberUtils.long2sortableStr(readableValue);
} }
@ -122,7 +124,7 @@ class SortableLongFieldSource extends FieldCacheSource {
public long longVal(int doc) { public long longVal(int doc) {
int ord=termsIndex.getOrd(doc); int ord=termsIndex.getOrd(doc);
return ord==0 ? def : NumberUtils.SortableStr2long(termsIndex.lookup(ord, new BytesRef()),0,5); return ord==0 ? def : NumberUtils.SortableStr2long(termsIndex.lookup(ord, spare),0,5);
} }
public double doubleVal(int doc) { public double doubleVal(int doc) {
@ -149,7 +151,14 @@ class SortableLongFieldSource extends FieldCacheSource {
@Override @Override
public void fillValue(int doc) { public void fillValue(int doc) {
mval.value = longVal(doc); int ord=termsIndex.getOrd(doc);
if (ord == 0) {
mval.value = def;
mval.exists = false;
} else {
mval.value = NumberUtils.SortableStr2long(termsIndex.lookup(ord, spare),0,5);
mval.exists = true;
}
} }
}; };
} }

View File

@ -18,7 +18,7 @@ package org.apache.solr.search;
/** @lucene.internal */ /** @lucene.internal */
public abstract class MutableValue implements Comparable { public abstract class MutableValue implements Comparable {
protected boolean exists = true; public boolean exists = true;
public abstract void copy(MutableValue source); public abstract void copy(MutableValue source);
public abstract MutableValue duplicate(); public abstract MutableValue duplicate();
@ -47,7 +47,7 @@ public abstract class MutableValue implements Comparable {
public boolean equals(Object other) { public boolean equals(Object other) {
Class c1 = this.getClass(); Class c1 = this.getClass();
Class c2 = other.getClass(); Class c2 = other.getClass();
return (c1 == c2) ? this.equalsSameType(other) : false; return (c1 == c2) && this.equalsSameType(other);
} }
public abstract int hashCode(); public abstract int hashCode();

View File

@ -21,13 +21,14 @@ import java.util.Date;
public class MutableValueDate extends MutableValueLong { public class MutableValueDate extends MutableValueLong {
@Override @Override
public Object toObject() { public Object toObject() {
return new Date(value); return exists ? new Date(value) : null;
} }
@Override @Override
public MutableValue duplicate() { public MutableValue duplicate() {
MutableValueDate v = new MutableValueDate(); MutableValueDate v = new MutableValueDate();
v.value = this.value; v.value = this.value;
v.exists = this.exists;
return v; return v;
} }
} }

View File

@ -21,29 +21,38 @@ public class MutableValueDouble extends MutableValue {
@Override @Override
public Object toObject() { public Object toObject() {
return value; return exists ? value : null;
} }
@Override @Override
public void copy(MutableValue source) { public void copy(MutableValue source) {
value = ((MutableValueDouble)source).value; MutableValueDouble s = (MutableValueDouble) source;
value = s.value;
exists = s.exists;
} }
@Override @Override
public MutableValue duplicate() { public MutableValue duplicate() {
MutableValueDouble v = new MutableValueDouble(); MutableValueDouble v = new MutableValueDouble();
v.value = this.value; v.value = this.value;
v.exists = this.exists;
return v; return v;
} }
@Override @Override
public boolean equalsSameType(Object other) { public boolean equalsSameType(Object other) {
return value == ((MutableValueDouble)other).value; MutableValueDouble b = (MutableValueDouble)other;
return value == b.value && exists == b.exists;
} }
@Override @Override
public int compareSameType(Object other) { public int compareSameType(Object other) {
return Double.compare(value, ((MutableValueDouble)other).value); // handles NaN MutableValueDouble b = (MutableValueDouble)other;
int c = Double.compare(value, b.value);
if (c != 0) return c;
if (!exists) return -1;
if (!b.exists) return 1;
return 0;
} }
@Override @Override
@ -51,4 +60,4 @@ public class MutableValueDouble extends MutableValue {
long x = Double.doubleToLongBits(value); long x = Double.doubleToLongBits(value);
return (int)x + (int)(x>>>32); return (int)x + (int)(x>>>32);
} }
} }

View File

@ -21,33 +21,41 @@ public class MutableValueFloat extends MutableValue {
@Override @Override
public Object toObject() { public Object toObject() {
return value; return exists ? value : null;
} }
@Override @Override
public void copy(MutableValue source) { public void copy(MutableValue source) {
value = ((MutableValueFloat)source).value; MutableValueFloat s = (MutableValueFloat) source;
value = s.value;
exists = s.exists;
} }
@Override @Override
public MutableValue duplicate() { public MutableValue duplicate() {
MutableValueFloat v = new MutableValueFloat(); MutableValueFloat v = new MutableValueFloat();
v.value = this.value; v.value = this.value;
v.exists = this.exists;
return v; return v;
} }
@Override @Override
public boolean equalsSameType(Object other) { public boolean equalsSameType(Object other) {
return value == ((MutableValueFloat)other).value; MutableValueFloat b = (MutableValueFloat)other;
return value == b.value && exists == b.exists;
} }
@Override @Override
public int compareSameType(Object other) { public int compareSameType(Object other) {
return Float.compare(value, ((MutableValueFloat)other).value); // handles NaN MutableValueFloat b = (MutableValueFloat)other;
int c = Float.compare(value, b.value);
if (c != 0) return c;
if (exists == b.exists) return 0;
return exists ? 1 : -1;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Float.floatToIntBits(value); return Float.floatToIntBits(value);
} }
} }

View File

@ -21,38 +21,46 @@ public class MutableValueInt extends MutableValue {
@Override @Override
public Object toObject() { public Object toObject() {
return value; return exists ? value : null;
} }
@Override @Override
public void copy(MutableValue source) { public void copy(MutableValue source) {
value = ((MutableValueInt)source).value; MutableValueInt s = (MutableValueInt) source;
value = s.value;
exists = s.exists;
} }
@Override @Override
public MutableValue duplicate() { public MutableValue duplicate() {
MutableValueInt v = new MutableValueInt(); MutableValueInt v = new MutableValueInt();
v.value = this.value; v.value = this.value;
v.exists = this.exists;
return v; return v;
} }
@Override @Override
public boolean equalsSameType(Object other) { public boolean equalsSameType(Object other) {
return value == ((MutableValueInt)other).value; MutableValueInt b = (MutableValueInt)other;
return value == b.value && exists == b.exists;
} }
@Override @Override
public int compareSameType(Object other) { public int compareSameType(Object other) {
int a = value; MutableValueInt b = (MutableValueInt)other;
int b = ((MutableValueInt)other).value; int ai = value;
return (int)((((long)a) - ((long)b)) >> 32); // any shift >= 32 should do. int bi = b.value;
int c = (int)((((long)ai) - ((long)bi)) >> 32); // any shift >= 32 should do.
if (c!=0) return c;
/* is there any pattern that the compiler would recognize as a single native CMP instruction? */ /* is there any pattern that the compiler would recognize as a single native CMP instruction? */
/*** /***
if (a<b) return -1; if (a<b) return -1;
else if (a>b) return 1; else if (a>b) return 1;
else return 0; else return 0;
***/ ***/
if (exists == b.exists) return 0;
return exists ? 1 : -1;
} }

View File

@ -21,32 +21,38 @@ public class MutableValueLong extends MutableValue {
@Override @Override
public Object toObject() { public Object toObject() {
return value; return exists ? value : null;
} }
@Override @Override
public void copy(MutableValue source) { public void copy(MutableValue source) {
value = ((MutableValueLong)source).value; MutableValueLong s = (MutableValueLong) source;
exists = s.exists;
value = s.value;
} }
@Override @Override
public MutableValue duplicate() { public MutableValue duplicate() {
MutableValueLong v = new MutableValueLong(); MutableValueLong v = new MutableValueLong();
v.value = this.value; v.value = this.value;
v.exists = this.exists;
return v; return v;
} }
@Override @Override
public boolean equalsSameType(Object other) { public boolean equalsSameType(Object other) {
return value == ((MutableValueLong)other).value; MutableValueLong b = (MutableValueLong)other;
return value == b.value && exists == b.exists;
} }
@Override @Override
public int compareSameType(Object other) { public int compareSameType(Object other) {
long b = ((MutableValueLong)other).value; MutableValueLong b = (MutableValueLong)other;
if (value<b) return -1; long bv = b.value;
else if (value>b) return 1; if (value<bv) return -1;
else return 0; if (value>bv) return 1;
if (exists == b.exists) return 0;
return exists ? 1 : -1;
} }
@ -54,4 +60,4 @@ public class MutableValueLong extends MutableValue {
public int hashCode() { public int hashCode() {
return (int)value + (int)(value>>32); return (int)value + (int)(value>>32);
} }
} }

View File

@ -24,29 +24,37 @@ public class MutableValueStr extends MutableValue {
@Override @Override
public Object toObject() { public Object toObject() {
return ByteUtils.UTF8toUTF16(value); return exists ? ByteUtils.UTF8toUTF16(value) : null;
} }
@Override @Override
public void copy(MutableValue source) { public void copy(MutableValue source) {
value.copy(((MutableValueStr)source).value); MutableValueStr s = (MutableValueStr) source;
exists = s.exists;
value.copy(s.value);
} }
@Override @Override
public MutableValue duplicate() { public MutableValue duplicate() {
MutableValueStr v = new MutableValueStr(); MutableValueStr v = new MutableValueStr();
v.value = new BytesRef(value); v.value.copy(value);
v.exists = this.exists;
return v; return v;
} }
@Override @Override
public boolean equalsSameType(Object other) { public boolean equalsSameType(Object other) {
return value.equals(((MutableValueStr)other).value); MutableValueStr b = (MutableValueStr)other;
return value.equals(b.value) && exists == b.exists;
} }
@Override @Override
public int compareSameType(Object other) { public int compareSameType(Object other) {
return value.compareTo(((MutableValueStr)other).value); MutableValueStr b = (MutableValueStr)other;
int c = value.compareTo(b.value);
if (c != 0) return c;
if (exists == b.exists) return 0;
return exists ? 1 : -1;
} }
@ -54,4 +62,4 @@ public class MutableValueStr extends MutableValue {
public int hashCode() { public int hashCode() {
return value.hashCode(); return value.hashCode();
} }
} }

View File

@ -18,6 +18,7 @@
package org.apache.solr.search.function; package org.apache.solr.search.function;
import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexReader;
import org.apache.lucene.util.Bits;
import org.apache.lucene.search.FieldCache; import org.apache.lucene.search.FieldCache;
import org.apache.lucene.search.cache.DoubleValuesCreator; import org.apache.lucene.search.cache.DoubleValuesCreator;
import org.apache.lucene.search.cache.FloatValuesCreator; import org.apache.lucene.search.cache.FloatValuesCreator;
@ -50,6 +51,7 @@ public class DoubleFieldSource extends NumericFieldCacheSource<DoubleValues> {
public DocValues getValues(Map context, IndexReader reader) throws IOException { public DocValues getValues(Map context, IndexReader reader) throws IOException {
final DoubleValues vals = cache.getDoubles(reader, field, creator); final DoubleValues vals = cache.getDoubles(reader, field, creator);
final double[] arr = vals.values; final double[] arr = vals.values;
final Bits valid = vals.valid;
return new DocValues() { return new DocValues() {
public float floatVal(int doc) { public float floatVal(int doc) {
@ -148,6 +150,7 @@ public class DoubleFieldSource extends NumericFieldCacheSource<DoubleValues> {
@Override @Override
public void fillValue(int doc) { public void fillValue(int doc) {
mval.value = doubleArr[doc]; mval.value = doubleArr[doc];
mval.exists = valid.get(doc);
} }
}; };
} }

View File

@ -21,6 +21,7 @@ import java.io.IOException;
import java.util.Map; import java.util.Map;
import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexReader;
import org.apache.lucene.util.Bits;
import org.apache.lucene.search.cache.FloatValuesCreator; import org.apache.lucene.search.cache.FloatValuesCreator;
import org.apache.lucene.search.cache.CachedArray.FloatValues; import org.apache.lucene.search.cache.CachedArray.FloatValues;
import org.apache.solr.search.MutableValue; import org.apache.solr.search.MutableValue;
@ -47,6 +48,7 @@ public class FloatFieldSource extends NumericFieldCacheSource<FloatValues> {
public DocValues getValues(Map context, IndexReader reader) throws IOException { public DocValues getValues(Map context, IndexReader reader) throws IOException {
final FloatValues vals = cache.getFloats(reader, field, creator); final FloatValues vals = cache.getFloats(reader, field, creator);
final float[] arr = vals.values; final float[] arr = vals.values;
final Bits valid = vals.valid;
return new DocValues() { return new DocValues() {
public float floatVal(int doc) { public float floatVal(int doc) {
@ -87,10 +89,11 @@ public class FloatFieldSource extends NumericFieldCacheSource<FloatValues> {
@Override @Override
public void fillValue(int doc) { public void fillValue(int doc) {
mval.value = floatArr[doc]; mval.value = floatArr[doc];
mval.exists = valid.get(doc);
} }
}; };
} }
}; };
} }
} }

View File

@ -18,6 +18,7 @@
package org.apache.solr.search.function; package org.apache.solr.search.function;
import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexReader;
import org.apache.lucene.util.Bits;
import org.apache.solr.search.MutableValueInt; import org.apache.solr.search.MutableValueInt;
import org.apache.solr.search.MutableValue; import org.apache.solr.search.MutableValue;
import org.apache.lucene.search.FieldCache; import org.apache.lucene.search.FieldCache;
@ -51,6 +52,7 @@ public class IntFieldSource extends NumericFieldCacheSource<IntValues> {
public DocValues getValues(Map context, IndexReader reader) throws IOException { public DocValues getValues(Map context, IndexReader reader) throws IOException {
final IntValues vals = cache.getInts(reader, field, creator); final IntValues vals = cache.getInts(reader, field, creator);
final int[] arr = vals.values; final int[] arr = vals.values;
final Bits valid = vals.valid;
return new DocValues() { return new DocValues() {
final MutableValueInt val = new MutableValueInt(); final MutableValueInt val = new MutableValueInt();
@ -127,6 +129,7 @@ public class IntFieldSource extends NumericFieldCacheSource<IntValues> {
@Override @Override
public void fillValue(int doc) { public void fillValue(int doc) {
mval.value = intArr[doc]; mval.value = intArr[doc];
mval.exists = valid.get(doc);
} }
}; };
} }

View File

@ -18,6 +18,7 @@
package org.apache.solr.search.function; package org.apache.solr.search.function;
import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexReader;
import org.apache.lucene.util.Bits;
import org.apache.lucene.search.cache.LongValuesCreator; import org.apache.lucene.search.cache.LongValuesCreator;
import org.apache.lucene.search.cache.CachedArray.LongValues; import org.apache.lucene.search.cache.CachedArray.LongValues;
import org.apache.solr.search.MutableValue; import org.apache.solr.search.MutableValue;
@ -52,6 +53,7 @@ public class LongFieldSource extends NumericFieldCacheSource<LongValues> {
public DocValues getValues(Map context, IndexReader reader) throws IOException { public DocValues getValues(Map context, IndexReader reader) throws IOException {
final LongValues vals = cache.getLongs(reader, field, creator); final LongValues vals = cache.getLongs(reader, field, creator);
final long[] arr = vals.values; final long[] arr = vals.values;
final Bits valid = vals.valid;
return new DocValues() { return new DocValues() {
public float floatVal(int doc) { public float floatVal(int doc) {
@ -126,6 +128,7 @@ public class LongFieldSource extends NumericFieldCacheSource<LongValues> {
@Override @Override
public void fillValue(int doc) { public void fillValue(int doc) {
mval.value = longArr[doc]; mval.value = longArr[doc];
mval.exists = valid.get(doc);
} }
}; };
} }

View File

@ -18,6 +18,9 @@
package org.apache.solr.search.function; package org.apache.solr.search.function;
import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexReader;
import org.apache.solr.search.MutableValue;
import org.apache.solr.search.MutableValueInt;
import org.apache.solr.util.NumberUtils;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;
@ -89,6 +92,24 @@ public class OrdFieldSource extends ValueSource {
public String toString(int doc) { public String toString(int doc) {
return description() + '=' + intVal(doc); return description() + '=' + intVal(doc);
}
@Override
public ValueFiller getValueFiller() {
return new ValueFiller() {
private final MutableValueInt mval = new MutableValueInt();
@Override
public MutableValue getValue() {
return mval;
}
@Override
public void fillValue(int doc) {
mval.value = termsIndex.getOrd(doc);
mval.exists = mval.value!=0;
}
};
} }
}; };
} }

View File

@ -104,7 +104,9 @@ public abstract class StringIndexDocValues extends DocValues {
@Override @Override
public void fillValue(int doc) { public void fillValue(int doc) {
mval.value = termsIndex.getTerm(doc, val.value); int ord = termsIndex.getOrd(doc);
mval.exists = ord != 0;
mval.value = termsIndex.lookup(ord, mval.value);
} }
}; };
} }

View File

@ -907,16 +907,16 @@ public abstract class SolrTestCaseJ4 extends LuceneTestCase {
if (which == fieldTypes.size()) { if (which == fieldTypes.size()) {
// sort by score // sort by score
sortSpec.append("score").append(asc ? " asc" : " desc"); sortSpec.append("score").append(asc ? " asc" : " desc");
comparators.add(createComparator("score", asc, false, false)); comparators.add(createComparator("score", asc, false, false, false));
} else if (which == fieldTypes.size() + 1) { } else if (which == fieldTypes.size() + 1) {
// sort by docid // sort by docid
sortSpec.append("_docid_").append(asc ? " asc" : " desc"); sortSpec.append("_docid_").append(asc ? " asc" : " desc");
comparators.add(createComparator("_docid_", asc, false, false)); comparators.add(createComparator("_docid_", asc, false, false, false));
} else { } else {
String field = fieldTypes.get(which).fname; String field = fieldTypes.get(which).fname;
sortSpec.append(field).append(asc ? " asc" : " desc"); sortSpec.append(field).append(asc ? " asc" : " desc");
SchemaField sf = schema.getField(field); SchemaField sf = schema.getField(field);
comparators.add(createComparator(field, asc, sf.sortMissingLast(), sf.sortMissingFirst())); comparators.add(createComparator(field, asc, sf.sortMissingLast(), sf.sortMissingFirst(), !(sf.sortMissingLast()||sf.sortMissingFirst()) ));
} }
} }
@ -924,13 +924,13 @@ public abstract class SolrTestCaseJ4 extends LuceneTestCase {
if (comparators.size() == 0) { if (comparators.size() == 0) {
// default sort is by score desc // default sort is by score desc
comparators.add(createComparator("score", false, false, false)); comparators.add(createComparator("score", false, false, false, false));
} }
return createComparator(comparators); return createComparator(comparators);
} }
public static Comparator<Doc> createComparator(final String field, final boolean asc, final boolean sortMissingLast, final boolean sortMissingFirst) { public static Comparator<Doc> createComparator(final String field, final boolean asc, final boolean sortMissingLast, final boolean sortMissingFirst, final boolean sortMissingAsZero) {
final int mul = asc ? 1 : -1; final int mul = asc ? 1 : -1;
if (field.equals("_docid_")) { if (field.equals("_docid_")) {
@ -943,15 +943,31 @@ public abstract class SolrTestCaseJ4 extends LuceneTestCase {
} }
if (field.equals("score")) { if (field.equals("score")) {
return createComparator("score_f", asc, sortMissingLast, sortMissingFirst); return createComparator("score_f", asc, sortMissingLast, sortMissingFirst, sortMissingAsZero);
} }
return new Comparator<Doc>() { return new Comparator<Doc>() {
private Comparable zeroVal(Comparable template) {
if (template == null) return null;
if (template instanceof String) return null; // fast-path for string
if (template instanceof Integer) return 0;
if (template instanceof Long) return (long)0;
if (template instanceof Float) return (float)0;
if (template instanceof Double) return (double)0;
if (template instanceof Short) return (short)0;
if (template instanceof Byte) return (byte)0;
if (template instanceof Character) return (char)0;
return null;
}
@Override @Override
public int compare(Doc o1, Doc o2) { public int compare(Doc o1, Doc o2) {
Comparable v1 = o1.getFirstValue(field); Comparable v1 = o1.getFirstValue(field);
Comparable v2 = o2.getFirstValue(field); Comparable v2 = o2.getFirstValue(field);
v1 = v1 == null ? zeroVal(v2) : v1;
v2 = v2 == null ? zeroVal(v1) : v2;
int c = 0; int c = 0;
if (v1 == v2) { if (v1 == v2) {
c = 0; c = 0;

View File

@ -326,14 +326,14 @@ public class TestGroupingSearch extends SolrTestCaseJ4 {
while (--indexIter >= 0) { while (--indexIter >= 0) {
int indexSize = random.nextInt(25 * RANDOM_MULTIPLIER); int indexSize = random.nextInt(25 * RANDOM_MULTIPLIER);
//indexSize=2;
List<FldType> types = new ArrayList<FldType>(); List<FldType> types = new ArrayList<FldType>();
types.add(new FldType("id",ONE_ONE, new SVal('A','Z',4,4))); types.add(new FldType("id",ONE_ONE, new SVal('A','Z',4,4)));
types.add(new FldType("score_f",ONE_ONE, new FVal(1,100))); // field used to score types.add(new FldType("score_f",ONE_ONE, new FVal(1,100))); // field used to score
types.add(new FldType("foo_i",ONE_ONE, new IRange(0,indexSize))); types.add(new FldType("foo_i",ZERO_ONE, new IRange(0,indexSize)));
types.add(new FldType("foo_s",ONE_ONE, new SVal('a','z',1,2))); types.add(new FldType("foo_s",ZERO_ONE, new SVal('a','z',1,2)));
types.add(new FldType("small_s",ONE_ONE, new SVal('a',(char)('c'+indexSize/10),1,1))); types.add(new FldType("small_s",ZERO_ONE, new SVal('a',(char)('c'+indexSize/10),1,1)));
types.add(new FldType("small_i",ONE_ONE, new IRange(0,5+indexSize/10))); types.add(new FldType("small_i",ZERO_ONE, new IRange(0,5+indexSize/10)));
clearIndex(); clearIndex();
Map<Comparable, Doc> model = indexDocs(types, null, indexSize); Map<Comparable, Doc> model = indexDocs(types, null, indexSize);
@ -403,9 +403,9 @@ public class TestGroupingSearch extends SolrTestCaseJ4 {
// Test specific case // Test specific case
if (false) { if (false) {
groupField="small_i"; groupField="small_i";
sortComparator=createComparator(Arrays.asList(createComparator("small_s", true, true, false))); sortComparator=createComparator(Arrays.asList(createComparator("small_s", true, true, false, true)));
sortStr = "small_s asc"; sortStr = "small_s asc";
groupComparator = createComparator(Arrays.asList(createComparator("small_s", true, true, false))); groupComparator = createComparator(Arrays.asList(createComparator("small_s", true, true, false, false)));
groupSortStr = "small_s asc"; groupSortStr = "small_s asc";
rows=1; start=0; group_offset=1; group_limit=1; rows=1; start=0; group_offset=1; group_limit=1;
} }