lucene 查询部分字段总是返回 null

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了lucene 查询部分字段总是返回 null相关的知识,希望对你有一定的参考价值。

我用lucene 做个索引,关键代码如下 :
document.add(new Field("path", dataFiles[i].getCanonicalPath(),
Field.Store.YES, Field.Index.NOT_ANALYZED));
document.add(new Field("contents", txtReader,
Field.TermVector.WITH_POSITIONS));
查找关键代码如下:
Document doc=searcher.doc(hits[i].doc);
System.out.print("Query"+doc.get("contents")+"\t");
FilePath += "<br/>File: " + doc.get("path")+"";

但是输出时 contents 的字段总是为null
,而 path字段却输出正确的内容,请问这是什么原因?

我用的是 lucene-3.0.1

参考技术A Field.TermVector.WITH_POSITIONS只表示额外索引这个索引项的当前位置信息

并没有存储数据 所以内容为null

如果需要检索内容必须用Field.Store.YES来存储数据信息
用Field(name, value, store, index)或者Field(name, value, store, index,termvector)
参考技术B 应该可以帮到你:
Document doc = new Document();
Field FieldPath = new Field("path",file.getCanonicalPath(), Field.Store.YES, Field.Index.NO);
Field FieldBody = new Field("contents", txtReader, Field.Store.YES,
Field.Index.ANALYZED,Field.TermVector.WITH_POSITIONS_OFFSETS);
doc.add(FieldPath);
doc.add(FieldBody);
writer.addDocument(doc);

注:IndexWriter writer = new IndexWriter(FSDirectory.open(INDEX_DIR),
analyzer, true, IndexWriter.MaxFieldLength.LIMITED);

Lucene - 获取文档频率 - termsEnum.docFreq() 总是返回 1

【中文标题】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 查询部分字段总是返回 null的主要内容,如果未能解决你的问题,请参考以下文章

ELK:kibana使用的lucene查询语法

Lucene - 获取文档频率 - termsEnum.docFreq() 总是返回 1

kibana查询语法基础

在一个字段中为多个值构建Lucene查询

lucene 多字段查询-MultiFieldQueryParser

lucene卷曲查询的多个术语