Как отсортировать результаты поиска на нескольких полях с помощью функции взвешивания?

Если вы действительно настаиваете на использовании пакета, я бы посоветовал вам добавить рамку в середине только для записей.

class test(Alarm.Frame):
    def __init__(self, parent):
        Alarm.Frame.__init__(self, parent)
        self.prompt = Alarm.Label(self, text="Enter hours (Max: 24 hours) , minutes, seconds:", anchor="w")
        self.prompt2 = Alarm.Label(self, text="Alarm Message:", anchor="w")
        self.entry4 = Alarm.Entry(self)
        self.output = Alarm.Label(self, text="00:00:00",font=(24))
        self.submit = Alarm.Button(self, text="Start", command = self.startTimer)
        self.prompt.pack(side="top", fill="x")
        mid_frame = Alarm.Frame(self)
        mid_frame.pack()
        self.entry = Alarm.Entry(mid_frame, width=1)
        self.entry2 = Alarm.Entry(mid_frame, width=1)
        self.entry3 = Alarm.Entry(mid_frame, width=1)
        self.entry.pack(side="left", fill="x",padx=10)
        self.entry2.pack(side="left",fill="x", padx=10)
        self.entry3.pack(side="left",fill="x", padx=10)
        self.prompt2.pack(side="top", fill="x")
        self.entry4.pack(side="top", fill="x", padx=20)
        self.output.pack(side="top", fill="x", expand=True)
        self.submit.pack(side="bottom")
        self.pack()
8
задан double-beep 1 February 2019 в 15:54
поделиться

4 ответа

Вы можете попробовать реализовать собственный ScoreDocComparator . Например:

public class ScaledScoreDocComparator implements ScoreDocComparator {

    private int[][] values;
    private float[] scalars;

    public ScaledScoreDocComparator(IndexReader reader, String[] fields, float[] scalars) throws IOException {
        this.scalars = scalars;
        this.values = new int[fields.length][];
        for (int i = 0; i < values.length; i++) {
            this.values[i] = FieldCache.DEFAULT.getInts(reader, fields[i]);
        }
    }

    protected float score(ScoreDoc scoreDoc) {
        int doc = scoreDoc.doc;

        float score = 0;
        for (int i = 0; i < values.length; i++) {
            int value = values[i][doc];
            float scalar = scalars[i];
            score += (value * scalar);
        }
        return score;
    }

    @Override
    public int compare(ScoreDoc i, ScoreDoc j) {
        float iScore = score(i);
        float jScore = score(j);
        return Float.compare(iScore, jScore);
    }

    @Override
    public int sortType() {
        return SortField.CUSTOM;
    }

    @Override
    public Comparable<?> sortValue(ScoreDoc i) {
        float score = score(i);
        return Float.valueOf(score);
    }

}

Вот пример ScaledScoreDocComparator в действии. Я полагаю, что это работает в моем тесте, но я призываю вас проверить это на основе ваших данных.

final String[] fields = new String[]{ "field1", "field2", "field3" };
final float[] scalars = new float[]{ 0.5f, 1.4f, 1.8f };

Sort sort = new Sort(
    new SortField(
        "",
        new SortComparatorSource() {
            public ScoreDocComparator newComparator(IndexReader reader, String fieldName) throws IOException {
                return new ScaledScoreDocComparator(reader, fields, scalars);
            }
        }
    )
);

IndexSearcher indexSearcher = ...;
Query query = ...;
Filter filter = ...; // can be null
int nDocs = 100;

TopFieldDocs topFieldDocs = indexSearcher.search(query, filter, nDocs, sort);
ScoreDoc[] scoreDocs = topFieldDocs.scoreDocs;

Бонус!

Похоже, что разработчики Lucene устарели в интерфейсе ScoreDocComparator (в настоящее время он устарел в Хранилище Subversion). Вот пример ScaledScoreDocComparator , модифицированного для присоединения к преемнику ScoreDocComparator , FieldComparator :

public class ScaledComparator extends FieldComparator {

    private String[] fields;
    private float[] scalars;
    private int[][] slotValues;
    private int[][] currentReaderValues;
    private int bottomSlot;

    public ScaledComparator(int numHits, String[] fields, float[] scalars) {
        this.fields = fields;
        this.scalars = scalars;

        this.slotValues = new int[this.fields.length][];
        for (int fieldIndex = 0; fieldIndex < this.fields.length; fieldIndex++) {
            this.slotValues[fieldIndex] = new int[numHits];
        }

        this.currentReaderValues = new int[this.fields.length][];
    }

    protected float score(int[][] values, int secondaryIndex) {
        float score = 0;

        for (int fieldIndex = 0; fieldIndex < fields.length; fieldIndex++) {
            int value = values[fieldIndex][secondaryIndex];
            float scalar = scalars[fieldIndex];
            score += (value * scalar);
        }

        return score;
    }

    protected float scoreSlot(int slot) {
        return score(slotValues, slot);
    }

    protected float scoreDoc(int doc) {
        return score(currentReaderValues, doc);
    }

    @Override
    public int compare(int slot1, int slot2) {
        float score1 = scoreSlot(slot1);
        float score2 = scoreSlot(slot2);
        return Float.compare(score1, score2);
    }

    @Override
    public int compareBottom(int doc) throws IOException {
        float bottomScore = scoreSlot(bottomSlot);
        float docScore = scoreDoc(doc);
        return Float.compare(bottomScore, docScore);
    }

    @Override
    public void copy(int slot, int doc) throws IOException {
        for (int fieldIndex = 0; fieldIndex < fields.length; fieldIndex++) {
            slotValues[fieldIndex][slot] = currentReaderValues[fieldIndex][doc];
        }
    }

    @Override
    public void setBottom(int slot) {
        bottomSlot = slot;
    }

    @Override
    public void setNextReader(IndexReader reader, int docBase, int numSlotsFull) throws IOException {
        for (int fieldIndex = 0; fieldIndex < fields.length; fieldIndex++) {
            String field = fields[fieldIndex];
            currentReaderValues[fieldIndex] = FieldCache.DEFAULT.getInts(reader, field);
        }
    }

    @Override
    public int sortType() {
        return SortField.CUSTOM;
    }

    @Override
    public Comparable<?> value(int slot) {
        float score = scoreSlot(slot);
        return Float.valueOf(score);
    }

}

Использование этого нового класса очень похоже на оригинальный, за исключением того, что определение объекта sort немного отличается:

final String[] fields = new String[]{ "field1", "field2", "field3" };
final float[] scalars = new float[]{ 0.5f, 1.4f, 1.8f };

Sort sort = new Sort(
    new SortField(
        "",
        new FieldComparatorSource() {
            public FieldComparator newComparator(String fieldname, int numHits, int sortPos, boolean reversed) throws IOException {
                return new ScaledComparator(numHits, fields, scalars);
            }
        }
    )
);
13
ответ дан 5 December 2019 в 13:01
поделиться

I'm thinking one way to do this would be to accept these as parameters to your sorting function:

number of fields, array of documents, list of weight factors(based on the number of fields)

Calculate the weighing function for each document, storing the result in a separate array in the same order as the document array. Then, perform any sort you wish (quick sort would probably be best), making sure you are sorting not just the f(d) array, but the document array as well. Return the sorted documents array and you're done.

0
ответ дан 5 December 2019 в 13:01
поделиться

Создайте оболочку, которая содержит рейтинг и сопоставим. Что-то вроде:

public void sort(Datum[] data) {
   Rating[] ratings = new Rating[data.length];
   for(int i=0;i<data.length;i++)
     rating[i] = new Rating(data[i]);
   Arrays.sort(rating);
   for(int i=0;i<data.length;i++)
     data[i] = rating[i].datum;
}

class Rating implements Comparable<Datum> {
   final double rating;
   final Datum datum;

   public Rating(Datum datum) {
      this.datum = datum;
      rating = datum.field1 * 0.5 + datum.field2 * 1.4 + datum.field3 * 1.8
   }

   public int compareTo(Datum d) {
      return Double.compare(rating, d.rating);
   }
}
0
ответ дан 5 December 2019 в 13:01
поделиться

Реализуйте собственный класс подобия и переопределите метод idf (Term, Searcher) . В этом методе вы можете вернуть счет следующим образом. if (term.field.equals ("field1") {

    if (term.field.equals("field1") {
        score = 0.5 * Integer.parseInt(term.text());
    } else if (term.field.equals("field2") {
        score = 1.4 * Integer.parseInt(term.text());
    } // and so on
    return score;

Когда вы выполняете запрос, убедитесь, что он находится на всех полях. То есть запрос должен выглядеть как

field1: term field2: term field3: term

Окончательная оценка также добавит некоторые весовые коэффициенты, основанные на нормализации запроса, но это не повлияет на относительное ранжирование документов согласно указанному вами уравнению.

0
ответ дан 5 December 2019 в 13:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: