Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Lucene рассчитать среднюю частоту терминов

Автор вопроса: scriptatorОтветов: 2

В настоящее время я реализую модификацию стандарта Lucene Сходство BM25, основанное на следующем статье. Реализация фактической формулы проста, но я борюсь с вычислением необходимой статистики.

Мне нужны следующие две статистики:

  • Средняя частота терминов в документе: length of document / # unique terms of the document (т. е. показатель повторяемости документа - для документа без повторений это будет 1, если каждый термин встречается дважды, это будет 2 и т. д. )
  • Средняя частота терминов. Это среднее арифметическое приведенного выше показателя по всем документам коллекции. Это можно рассматривать как среднюю повторяемость всего корпуса.

Я обнаружил, что могу рассчитать среднюю частоту терминов для каждого документа во время индексации, переопределив метод computeNorm моей реализации подобия. Я могу хранить значение вместе с нормальным значением с помощью битовых операций (не очень красиво, но пока это работает). Затем во время запроса я могу извлечь среднюю частоту и длину термина в документе.

Однако это не помогает найти среднюю среднюю частоту терминов. Очевидно, что это значение для всей коллекции, и поэтому его следует вычислять в length of document / # unique terms of the document0/core/org/apache/lucene/search/similarities/Similarity.html#computeWeight. -float-org.apache.lucene.search.CollectionStatistics-org.apache.lucene.search.TermStatistics...-" rel="nofollow noreferrer">Similarity.computeWeight насколько я понимаю, но не не вижу, как это можно сделать, учитывая аргументы функции.

Какое место было бы идеальным для расчета этой статистики?

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

solrlucenetf-idfsimilarityinformation-retrieval

Ответы

Ответ 1 · Mysterion

Similarity.computeWeight имеет параметр CollectionStatistics, который содержит maxDoc (возвращает общее количество документов, независимо от того, все ли они содержат значения для этого поля), и TermStatistics, который содержит term и totalTermFreq (возвращает общее количество вхождений этого термина) и по разделив его, вы можете получить среднюю частоту термина

Ответ 2 · John Foley

Вам нужно будет рассчитать свою собственную "норму", чтобы придерживаться индекса Lucene. По сути, вы можете сохранить дополнительные функции для использования в вашей оценке с помощью NumericDocValuesField.

Это означает, что во время индексации вы сами захотите токенизировать свой текст. У меня есть пример кода (на Kotlin, но с удовольствием отвечу на дополнительные вопросы, если вы предпочитаете Java)

Токенизация на основе любого анализатора Lucene: (выраженная как функция расширения Kotlin, просто представьте, что this является первым аргументом этого статического метода в качестве анализатора, если вам удобнее работать с Java.

fun Analyzer.tokenize(field: String, input: String): List<String> {
    val tokens = arrayListOf<String>()
    this.tokenStream(field, input).use { body ->
        val charTermAttr = body.addAttribute(CharTermAttribute::class.java)

        // iterate over tokenized field:
        body.reset()
        while(body.incrementToken()) {
            tokens.add(charTermAttr.toString())
        }
    }
    return tokens
}

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

    fun setTextField(field: String, text: String, terms: List<String>): List<IndexableField> {
        val length = terms.size
        val uniqLength = terms.toSet().size

        val keep = ArrayList<IndexableField>()
        keep.add(TextField(field, text, Field.Store.YES))
        keep.add(NumericDocValuesField("lengths:$field", length.toLong()))
        keep.add(NumericDocValuesField("unique:$field", uniqLength.toLong()))
        return keep
    }

Это статистика для каждого документа, поэтому вы можете отслеживать среднее значение при индексировании и хранить его отдельно от Lucene, т. е. я обычно создаю "meta.json" рядом с индексом для таких вещей.

Я не знаком с SOLR как таковой, но когда вы приступите к реализации подкласса Weight в Lucene, у вас будет доступ к этим числовым значениям документа следующим образом:

class SpecialBM25(...) : Weight(...) {
    ...
    override fun scorer(context: LeafReaderContext): Scorer {
        val uniq = context.reader().getNumericDocValues("unique:$field")
        val lengths = context.reader().getNumericDocValues("lengths:$field")
        ... generate Scorer and give it your additional features ...
    }
}

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы