Lucene — получение частоты документов — termsEnum.docFreq() всегда возвращает 1

В настоящее время я пытаюсь рассчитать матрицу tf-idf для терминов в индексе lucene. Я пытаюсь сделать это с помощью следующей функции:

public Table<Integer, BytesRef, Double> tfidf(String field) throws IOException, ParseException{
    //variables in complete context
    int totalNoOfDocs = reader.numDocs();                                   //total no of docs
    HashBasedTable<Integer, BytesRef, Double> tfidfPerDocAndTerm = HashBasedTable.create(); //tfidf value for each document(integer) and term(Byteref) pair.

    //variables in loop context
    BytesRef    term;                                                       //term as BytesRef
    int         noOfDocs;                                                   //number of documents (a term occours in)
    int         tf;                                                         //term frequency (of a term in a doc)
    double      idf;                                                        //inverse document frequency (of a term in a doc)
    double      tfidf;                                                      //term frequency - inverse document frequency value (of a term in a doc)
    Terms       termVector;                                                 //all terms of current doc in current field
    TermsEnum   termsEnum;                                                  //iterator for terms
    DocsEnum    docsEnum;                                                   //iterator for documents (of current term)

    List<Integer> docIds = getDocIds(totalNoOfDocs);                        //get internal documentIds of documents

    try {
        for(int doc : docIds){
            termVector  = reader.getTermVector(doc, field);                 //get termvector for document
            termsEnum   = termVector.iterator(null);                        //get iterator of termvector to iterate over terms


            while((term = termsEnum.next()) != null){                       //iterate of terms

                    noOfDocs = termsEnum.docFreq();                         //add no of docs the term occurs in to list

                    docsEnum = termsEnum.docs(null, null);                  //get document iterator for this term (all documents the term occours in)
                    while((doc = docsEnum.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS){ //iterate over documents - computation of all tf-idf values for this term
                        tf      = docsEnum.freq();                          //get termfrequency of current term in current doc
                        idf     = Math.log((double)totalNoOfDocs / (double)noOfDocs); //calculate idf
                        tfidf   = (double) tf * idf;                        //caculate tfidf
                        tfidfPerDocAndTerm.put(doc, term, tfidf);           //add tf-idf value to matrix

                    }
            }
        }

    } catch (IOException ex) {
        Logger.getLogger(Index.class.getName()).log(Level.SEVERE, null, ex);
    }   
    return tfidfPerDocAndTerm;
}

Проблема в следующем: noOfDocs = termsEnum.docFreq(); всегда возвращает 1. Даже если есть очевидные термины, которые встречаются более чем в одном документе (проверено вручную, напечатав «термин»).

Я также узнал, что docsEnum я получаю с помощью: docsEnum = termsEnum.docs(null, null); всегда содержит только 1 документ (doc 0).

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

Так в чем моя проблема? :/

Спасибо за вашу помощь!


person dburgmann    schedule 19.01.2013    source источник
comment
Сначала следует использовать Luke, чтобы проверить, выглядит ли индекс должным образом.   -  person Daniel Naber    schedule 19.01.2013
comment
Я делаю это в индексе RAMDirectory, но меняю его на реальный каталог для открытия в Люке. Лука говорит: Версия формата не поддерживается... при попытке открыть файл index. ?? (Я использую Lucen 4.0)   -  person dburgmann    schedule 19.01.2013
comment
Загрузите новейшую версию кода. .google.com/p/luke/downloads/   -  person RobAu    schedule 20.01.2013
comment
Я использовал lukeall-4.0.0-ALPHA.jar. Кажется, это самая новая версия.   -  person dburgmann    schedule 20.01.2013
comment
есть такая же проблема. любое решение?   -  person Alexey Grigorev    schedule 14.03.2016
comment
Хорошо, я нашел ответ в соответствующих вопросах справа.   -  person Alexey Grigorev    schedule 14.03.2016


Ответы (2)


На самом деле ваш термин, который имеет тип BytesRef, зацикливается вместо ваших терминов, но, к сожалению, BytesRef не поддерживает метод, называемый freq() или docfreq()

person Aries    schedule 30.10.2013

Действительно, перечислитель всегда возвращает 1. Но вы можете получить правильное значение, используя CollectionStatistics:

DefaultSimilarity similarity = new DefaultSimilarity();

IndexReader reader = searcher.getIndexReader();
IndexReaderContext context = searcher.getTopReaderContext();
CollectionStatistics collectionStats = searcher.collectionStatistics(FIELD);
long totalDocCount = collectionStats.docCount();

Terms termVector = reader.getTermVector(docId, FIELD);
TermsEnum iterator = termVector.iterator(null);

while (true) {
    BytesRef ref = iterator.next();
    if (ref == null) {
        break;
    }

    long termFreq = iterator.totalTermFreq();
    float tf = similarity.tf(termFreq);

    Term term = new Term(FIELD, ref);
    TermContext termContext = TermContext.build(context, term);

    TermStatistics termStats = searcher.termStatistics(term, termContext);
    long docFreq = termStats.docFreq();
    float idf = similarity.idf(docFreq, totalDocCount);

    // do something with tf and idf
}

Обратите внимание, что для этого вам необходимо хранить векторы терминов в индексе.

person Alexey Grigorev    schedule 14.03.2016