Lucene - 获取文档频率 - termsEnum.docFreq() 总是返回 1
Posted
技术标签:
【中文标题】Lucene - 获取文档频率 - termsEnum.docFreq() 总是返回 1【英文标题】:Lucene - getting document frequency - termsEnum.docFreq() always returns 1 【发布时间】:2013-01-03 04:03:09 【问题描述】:我目前正在尝试为 lucene 索引中的术语计算 tf-idf 矩阵。 我尝试使用以下功能来做到这一点:
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)。
在创建索引时,我使用了带有停用词列表的标准分析器,因此所有术语都是小写的。
那么我的问题是什么? :/
感谢您的帮助!
【问题讨论】:
您应该首先使用Luke 来查看索引是否看起来应该。 我在 RAMDirectory 索引上执行此操作 - 但更改为在 Luke 中打开的“真实”目录。卢克说:不支持格式版本...尝试打开索引时。 ?? (我使用的是 lucen 4.0) 下载最新版本code.google.com/p/luke/downloads/… 我确实使用了 lukeall-4.0.0-ALPHA.jar。这似乎是最新版本。 有同样的问题。有什么解决办法吗? 【参考方案1】:实际上,您的术语是 BytesRef 类型,是循环的,而不是您的术语集,但不幸的是,BytesRef 不支持称为 freq() 或 docfreq() 的方法
【讨论】:
【参考方案2】:确实,枚举器总是返回 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
请注意,要使其工作,您需要将术语向量存储在索引中。
【讨论】:
以上是关于Lucene - 获取文档频率 - termsEnum.docFreq() 总是返回 1的主要内容,如果未能解决你的问题,请参考以下文章