sorting - FieldComparatorSource not working on unoptimized index -
for reason fieldcomparatorsource doesn't work when index not optimized (i deleted documents , re-indexed same data again end segmented index. "not working" meaning compare method never called these re-indexed documents.
i using lucene 3.6.2 hibernate search (which not relevant).
this fieldcomparatorsource. can pass preferred sort order , comparator sorts accordingly. it works optimized index though.
import java.io.ioexception; import java.util.arrays; import java.util.hashmap; import java.util.list; import java.util.map; import org.apache.lucene.index.indexreader; import org.apache.lucene.search.fieldcache; import org.apache.lucene.search.fieldcomparator; import org.apache.lucene.search.fieldcomparatorsource; import org.hibernate.search.bridge.twowaystringbridge; import com.google.common.collect.range; import com.google.common.collect.rangemap; import com.google.common.collect.treerangemap; /** * provides fieldcomparators doesn't sort normal values sort * specified preferred values front * * can used boolean values (just submit list containing true * value , fine) * * <br> * <br> * todo: maybe use fieldcache?: <br> * <br> * * <b>http://lucene.472066.n3.nabble.com/custom-fieldcomparator-and-incorrect- * sort- order-td561154.html<b> <br> * <b>http://lucene.apache.org/core/3_6_0/api/all/org/apache/lucene * /search/fieldcache.html<b> <br> * * @author martin braun */ public class preferencefieldcomparatorsource<t> extends fieldcomparatorsource { private static final long serialversionuid = -8959374194451783596l; private final map<t, integer> preference; private final twowaystringbridge stringbridge; @safevarargs public preferencefieldcomparatorsource(twowaystringbridge stringbridge, t... preferred) { this(stringbridge, arrays.aslist(preferred)); } public preferencefieldcomparatorsource(twowaystringbridge stringbridge, list<t> preferred) { this(stringbridge, tomap(preferred)); } public preferencefieldcomparatorsource(twowaystringbridge stringbridge, map<t, integer> preference) { this.stringbridge = stringbridge; this.preference = preference; } @override public fieldcomparator<string> newcomparator(final string fieldname, int numhits, int sortpos, final boolean reversed) throws ioexception { return new fieldcomparator<string>() { private rangemap<integer, docbasevaluewrapper<string>> values = treerangemap .create(); private string bottom; private rangemap<integer, docbasevaluewrapper<string>> currentreadervalues = treerangemap .create(); @override public int compare(int slot1, int slot2) { return this.compare(this.values.get(slot1).get(slot1), this.values.get(slot2).get(slot2)); } @override public int comparebottom(int doc) throws ioexception { return this.compare(this.bottom, this.currentreadervalues.get(doc).get(doc)); } @override public void copy(int slot, int doc) throws ioexception { this.values.get(slot).put(slot, this.currentreadervalues.get(doc).get(doc)); } @override public void setbottom(int slot) { this.bottom = this.values.get(slot).get(slot); } @override public void setnextreader(indexreader reader, int docbase) throws ioexception { this.currentreadervalues.put(range.closed(docbase, docbase + reader.maxdoc()), docbasevaluewrapper.create(docbase, fieldcache.default.getstrings(reader, fieldname))); this.values.put( range.closed(docbase, docbase + reader.maxdoc()), docbasevaluewrapper.create(docbase, new string[reader.maxdoc()])); } @override public string value(int slot) { return this.values.get(slot).get(slot); } private int compare(object first, object second) { if (first == null && second == null) { return 0; } else if (first == null) { return 1; } else if (second == null) { return -1; } integer firstpos = preferencefieldcomparatorsource.this.preference .get(preferencefieldcomparatorsource.this.stringbridge .stringtoobject((string) first)); integer secondpos = preferencefieldcomparatorsource.this.preference .get(preferencefieldcomparatorsource.this.stringbridge .stringtoobject((string) second)); int firstindex = firstpos != null ? firstpos : -1; int secondindex = secondpos != null ? secondpos : -1; int result; if (firstindex == -1 || secondindex == -1) { if (firstindex == secondindex) { result = 0; } else if (firstindex == -1) { result = 1; } else { result = -1; } } else { result = integer.compare(firstindex, secondindex); } if (reversed) { result *= -1; } return result; } }; } private static <t> map<t, integer> tomap(list<t> preferred) { map<t, integer> preference = new hashmap<>(); (int = 0; < preferred.size(); ++i) { preference.put(preferred.get(i), i); } return preference; } }
the utility class easy segmentation.
public class docbasevaluewrapper<t> { private docbasevaluewrapper(int slotbase, t[] values) { this.slotbase = slotbase; this.values = values; } private final int slotbase; private final t[] values; public t get(int doc) { return this.values[doc - slotbase]; } public void put(int doc, t value) { this.values[doc - slotbase] = value; } public static <t> docbasevaluewrapper<t> create(int slotbase, t[] values) { return new docbasevaluewrapper<>(slotbase, values); } }
my index looks this:
i fixed it. using fieldcomparatorsource api wrong , handled docs relative 0 instead of handling them relative docbase.
the whole wrapper construct unnecessary.
Comments
Post a Comment