【问题标题】:FieldComparatorSource not working on unoptimized indexFieldComparatorSource 不适用于未优化的索引
【发布时间】: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


【解决方案1】:

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

整个 Wrapper 构造是完全没有必要的。

【讨论】:

    猜你喜欢
    • 2016-05-01
    • 2014-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-25
    • 2018-01-18
    • 2020-04-17
    相关资源
    最近更新 更多