【发布时间】:2014-03-24 19:59:09
【问题描述】:
由于某种原因,当我的索引未优化时,我的 FieldComparatorSource 不起作用(我删除了一些文档并再次重新索引相同的数据,所以我最终得到一个分段索引。“不工作”意味着永远不会为这些重新索引的文档调用 compare 方法。
我正在将 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);
}
}
我的索引如下所示:
【问题讨论】:
-
是否有可能在优化之后才打开新的
IndexReader? -
我修好了。我只是错误地使用了 FieldComparatorSource API,我处理了相对于 0 的所有文档,而不是相对于 docBase 处理它们。
标签: sorting solr lucene hibernate-search