出于某些原因,当我的索引未优化时,我的FieldComparatorSource无法正常工作(我删除了一些文档并且重新编入索引再次使用相同的数据,所以我结束了使用分段索引。"不工作"意味着永远不会为这些重新编制索引的文档调用比较方法。
我正在使用 Lucene 3.6.2 和Hibernate Search(这不太相关)。
这是我的FieldComparatorSource。您可以传递首选排序顺序,比较器会相应地对其进行排序。 适用于优化索引。
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 that doesn't sort normal values but sort all the
* specified preferred values to the front
*
* can be used for Boolean Values (just submit a list containing a true
* value and you are 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<>();
for (int i = 0; i < preferred.size(); ++i) {
preference.put(preferred.get(i), i);
}
return preference;
}
}
实用工具类,便于细分。
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);
}
}
我的索引如下:
答案 0 :(得分:0)
我修好了。我只是错误地使用FieldComparatorSource API而且我处理了相对于0的所有文档,而不是相对于docBase处理它们。
整个Wrapper构造完全没必要。