Пользовательский подсчет баллов - Точка продукта между увеличением поля и запросом - PullRequest
1 голос
/ 21 февраля 2012

Я хочу использовать Lucene со следующей логикой скоринга: Когда я индексирую свои документы, я хочу установить для каждого поля балл / вес.Когда я запрашиваю свой индекс, я хочу установить для каждого термина запроса оценку / вес.

Я НИКОГДА не буду индексировать или выполнять запрос со многими экземплярами одного и того же поля - в каждом запросе (документе) будет 0-1экземпляры с тем же именем поля.Мои поля / термин запроса не анализируются - они уже составлены из одного токена.

Я хочу, чтобы оценка была просто точечным произведением между полями запроса и полями документа, если они имеютто же значение.

Например:
Формат (Имя поля) (Значение поля) (Оценка поля)
Запрос:
1 AA 0.1
7 BB 0.2
8CC 0,3

Документ 1:
1 AA 0,2
2 DD 0,8
7 CC 0,999
10 FFF 0,1

Документ 2:
7 BB 0,3
8 CC 0,5

Баллы должны быть:
Оценка (q, d1) = FIELD_1_SCORE_Q * FILED_1_SCORE_D1 = 0,1 * 0,2 = 0,02
Оценка (q, d2) = FIELD_7_SCORE_Q * FILED_7_SCORE_D2 + FIELD_8_SCORE_Q * FILED_8_SCORE_D2 = (0,2 * 0,3) + (0,3 * 0,5)

Как лучше всего это реализовать?С точки зрения точности и производительности (мне не нужны вычисления TF и ​​IDF).

В настоящее время я реализовал это, установив повышение для полей и условий запроса.Затем я перезаписываю класс DefaultSogeneity и устанавливаю его по умолчанию перед индексацией / запросом:

public class MySimilarity extends DefaultSimilarity {

    @Override
    public float computeNorm(String field, FieldInvertState state) {
        return state.getBoost();
    }

    @Override
    public float queryNorm(float sumOfSquaredWeights) {
        return 1;
    }

    @Override
    public float tf(float freq) {
        return 1;
    }

    @Override
    public float idf(int docFreq, int numDocs) {
        return 1;
    }

    @Override
    public float coord(int overlap, int maxOverlap) {
        return 1;
    }

}


И на основе http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/scoring.html это должно работать.
Проблемы:

  1. Исполнения: Я вычисляю все вещи TF / IDF и NORMS впустую…
  2. Оценка, которую я получаю от TopScoreDocCollector, отличается от оценки, полученной из объяснения.

Вот часть моего кода:

indexSearcher = new IndexSearcher(IndexReader.open(directory, true));
TopScoreDocCollector collector = TopScoreDocCollector.create(iTopN, true);
indexSearcher.search(query, collector);
ScoreDoc[] hits = collector.topDocs().scoreDocs;
for (int i = 0; i < hits.length; ++i) {
  int docId = hits[i].doc;
  Document d = indexSearcher.doc(docId);
  double score = hits[i].score;
  String id = d.get(FIELD_ID);
  Explanation explanation = indexSearcher.explain(query, docId);
}

Спасибо!

Ответы [ 2 ]

0 голосов
/ 23 февраля 2012

Разобрался с ответом - он отлично работает!

Вдохновлен другим потоком в списке рассылки Lucene (Вопрос о CustomScoreQuery). Я использую это решение, которое работает очень хорошо (с одним недостатком):
Я обнаружил, что некоторые из моих проблем были связаны с тем, что мое предположение было неверным:
У меня было много полей / запросов с одним и тем же идентификатором поля.

Это разрушиломой подход, потому что запрос был агрегирован, а мои расчеты были неверными.

Во время индексации я добавил значение поля к идентификатору поля (объединил его с помощью '_') и в качестве значения поляиспользовал желаемую оценку.

Во время поиска я использую простую FieldScoreQuery (как есть, никаких изменений не требуется) со сложным идентификатором поля.

Здесь я все еще могуиспользуйте setBoost, чтобы установить счет, потому что теперь мои поля уникальны.

Логично, что это идеально - точечный продукт с использованием Lucene.

Недостаток - многомного разных типов полей.

ВАЖНО:
Так как я не использую нормы полей индексированных документов, потому что вес является значением поля, ятеперь индексируем поля, используя:

Field field = new Field(field_name, Float.toString(weight), Store.YES, Index.NOT_ANALYZED_NO_NORMS);<br>

И использование памяти возвращается к нормальному ...
Так круто!

0 голосов
/ 22 февраля 2012

Есть несколько вещей, которые вы можете исправить:

  • вы не устанавливаете свое пользовательское сходство в фрагменте кода, который вы вставили, см. IndexSearcher # setSimility ,

  • метод '' tf '' вашей реализации Сходства должен возвращать 0, когда freq равен 0.

Более того, выследует быть осторожным с увеличением индекса времени.Из-за того, что они закодированы в один байт, может быть некоторая потеря точности, см. В Lucene, почему мои увеличенные и не загруженные документы получают одинаковый счет? .

Oneальтернативой индексам повышения времени может быть индексирование значений повышения в другом числовом поле, а затем использование CustomScoreQuery и float FieldCacheSource для использования этих повышений в оценках.

...