Question

I am using Hibernate Search 3.6.2 and I want to sort specific documents to the front. For that reason, I have written a custom comparator-Source, but somehow it doesn't seem to work.

I want documents, that have these preferred values in them to be sorted to the front.

Here is what I have so far:

public class PreferenceFieldComparatorSource<T> extends FieldComparatorSource {

    private static final long serialVersionUID = -8959374194451783596L;

    private final List<?> preferred;
    private final Class<?> clazz;
    private final StringBridge stringBridge;

    @SafeVarargs
    public PreferenceFieldComparatorSource(Class<T> clazz,
            StringBridge stringBridge, T... preferred) {
        this(clazz, stringBridge, Arrays.asList(preferred));
    }

    public PreferenceFieldComparatorSource(Class<T> clazz,
            StringBridge stringBridge, List<T> preferred) {
        this.clazz = clazz;
        this.stringBridge = stringBridge;
        this.preferred = preferred;
    }

    @Override
    public FieldComparator<String> newComparator(final String fieldName,
            int numHits, int sortPos, final boolean reversed)
            throws IOException {
        return new FieldComparator<String>() {

            private String[] values;
            private String bottom;
            private String[] currentReaderValues;

            @Override
            public int compare(int slot1, int slot2) {
                return this.compare(this.values[slot1], this.values[slot2]);
            }

            @Override
            public int compareBottom(int doc) throws IOException {
                return this.compare(this.bottom, this.currentReaderValues[doc]);
            }

            @Override
            public void copy(int slot, int doc) throws IOException {
                this.values[slot] = this.currentReaderValues[doc];
            }

            @Override
            public void setBottom(int slot) {
                this.bottom = this.values[slot];
            }

            @Override
            public void setNextReader(IndexReader reader, int docBase)
                    throws IOException {
                System.out.println("fieldName: " + fieldName);

                this.currentReaderValues = new String[reader.maxDoc()];
                this.values = new String[reader.maxDoc()];
                for (int i = 0; i < currentReaderValues.length; ++i) {
                    try {
                        this.currentReaderValues[i] = reader.document(docBase)
                                .get(fieldName);
                    } catch (ClassCastException e) {
                        throw new IllegalArgumentException(
                                PreferenceFieldComparatorSource.this.stringBridge
                                        + " doesn't convert strings into "
                                        + PreferenceFieldComparatorSource.this.clazz);
                    }
                }
            }

            @Override
            public String value(int slot) {
                return this.values[slot];
            }

            private int compare(Object first, Object second) {
                // if none of the given values is in the preferred lists
                // the index is -1 but the compare function will still work
                // correctly
                // and will only move the preferred ones.
                int firstIndex = PreferenceFieldComparatorSource.this.preferred
                        .indexOf(PreferenceFieldComparatorSource.this.stringBridge
                                .objectToString(first));
                int secondIndex = PreferenceFieldComparatorSource.this.preferred
                        .indexOf(PreferenceFieldComparatorSource.this.stringBridge
                                .objectToString(second));
                int result = Integer.compare(firstIndex, secondIndex);
                if (reversed) {
                    result *= -1;
                }
                return result;
            }

        };
    }

}

The compare method doesn't seem to get called. What am I doing wrong in this class for that to be the case?

EDIT:

for clarification of a statement in the comments:

         @Override
         protected boolean lessThan(final Entry hitA, final Entry hitB) {

             assert hitA != hitB;
             assert hitA.slot != hitB.slot;

             int numComparators = comparators.length;
             for (int i = 0; i < numComparators; ++i) {
                 final int c = reverseMul[i] * comparators[i].compare(hitA.slot,
             hitB.slot);
             if (c != 0) {
             // Short circuit
             return c > 0;
             }
         }

         // avoid random sort order that could lead to duplicates (bug
         #31241):
         return hitA.doc > hitB.doc;
        }
Was it helpful?

Solution

i got it. Either i misread the documentation of the Sort class or it's wrong. It clearly states that it sorts in succession but it doesn't in the sense like sorting a java list 3 times in succession. Instead it behaves more like the inverse of that.

from the Hibernate-Search sourcecode:

     @Override
     protected boolean lessThan(final Entry hitA, final Entry hitB) {

         assert hitA != hitB;
         assert hitA.slot != hitB.slot;

         int numComparators = comparators.length;
         for (int i = 0; i < numComparators; ++i) {
             final int c = reverseMul[i] * comparators[i].compare(hitA.slot,
         hitB.slot);
         if (c != 0) {
         // Short circuit
         return c > 0;
         }
     }

     // avoid random sort order that could lead to duplicates (bug
     #31241):
     return hitA.doc > hitB.doc;
    }

and furthermore my comparator was wrong:

public class PreferenceFieldComparatorSource<T> extends FieldComparatorSource {

    private static final long serialVersionUID = -8959374194451783596L;

    private final List<?> preferred;
    private final Class<?> clazz;
    private final TwoWayStringBridge stringBridge;

    @SafeVarargs
    public PreferenceFieldComparatorSource(Class<T> clazz,
            TwoWayStringBridge stringBridge, T... preferred) {
        this(clazz, stringBridge, Arrays.asList(preferred));
    }

    public PreferenceFieldComparatorSource(Class<T> clazz,
            TwoWayStringBridge stringBridge, List<T> preferred) {
        this.clazz = clazz;
        this.stringBridge = stringBridge;
        this.preferred = preferred;
    }

    @Override
    public FieldComparator<String> newComparator(final String fieldName,
            int numHits, int sortPos, final boolean reversed)
            throws IOException {
        return new FieldComparator<String>() {

            private String[] values;
            private String bottom;
            private String[] currentReaderValues;

            @Override
            public int compare(int slot1, int slot2) {
                return this.compare(this.values[slot1], this.values[slot2]);
            }

            @Override
            public int compareBottom(int doc) throws IOException {
                return this.compare(this.bottom, this.currentReaderValues[doc]);
            }

            @Override
            public void copy(int slot, int doc) throws IOException {
                this.values[slot] = this.currentReaderValues[doc];
            }

            @Override
            public void setBottom(int slot) {
                this.bottom = this.values[slot];
            }

            @Override
            public void setNextReader(IndexReader reader, int docBase)
                    throws IOException {                
                this.currentReaderValues = new String[reader.maxDoc()];
                this.values = new String[reader.maxDoc()];
                for (int i = 0; i < currentReaderValues.length; ++i) {
                    try {
                        this.currentReaderValues[i] = reader.document(i)
                                .get(fieldName);
                    } catch (ClassCastException e) {
                        throw new IllegalArgumentException(
                                PreferenceFieldComparatorSource.this.stringBridge
                                        + " doesn't convert strings into "
                                        + PreferenceFieldComparatorSource.this.clazz);
                    }
                }
            }

            @Override
            public String value(int slot) {
                return this.values[slot];
            }

            private int compare(Object first, Object second) {
                int firstIndex = PreferenceFieldComparatorSource.this.preferred
                        .indexOf(PreferenceFieldComparatorSource.this.stringBridge
                                .stringToObject((String) first));
                int secondIndex = PreferenceFieldComparatorSource.this.preferred
                        .indexOf(PreferenceFieldComparatorSource.this.stringBridge
                                .stringToObject((String) second));
                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;
            }

        };
    }

}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top