FieldComparatorSource不处理未优化的索引

时间:2014-03-24 19:59:10

标签: sorting solr lucene hibernate-search

出于某些原因,当我的索引未优化时,我的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);
    }

}

我的索引如下:

The Index

1 个答案:

答案 0 :(得分:0)

我修好了。我只是错误地使用FieldComparatorSource API而且我处理了相对于0的所有文档,而不是相对于docBase处理它们。

整个Wrapper构造完全没必要。