首页 > 解决方案 > 在 Lucene 文档中获取术语位置的正确方法是什么?

问题描述

这个问题中的示例以及我在网络上看到的其他一些示例使用postingsa 的方法TermVector来获取术语位置。从链接问题的示例中复制粘贴:

IndexReader ir = obtainIndexReader();
Terms tv = ir.getTermVector( doc, field );
TermsEnum terms = tv.iterator();
PostingsEnum p = null;
while( terms.next() != null ) {
    p = terms.postings( p, PostingsEnum.ALL );
    while( p.nextDoc() != PostingsEnum.NO_MORE_DOCS ) {
        int freq = p.freq();
        for( int i = 0; i < freq; i++ ) {
            int pos = p.nextPosition();   // Always returns -1!!!
            BytesRef data = p.getPayload();
            doStuff( freq, pos, data ); // Fails miserably, of course.
        }
    }
}

这段代码对我有用,但让我抓狂的是Terms类型是保存位置信息的地方。我看到的所有文档都在说术语向量保留位置数据。但是,此类型没有获取该信息的方法!

较旧版本的 Lucene 显然有一种方法,但至少在 Lucene 的 6.5.1 版本中,情况并非如此。

相反,我应该使用postings方法并遍历文档,但我已经知道要处理哪个文档!

API文档没有说明只返回当前文档(术语向量所属的那个)的帖子,但是当我运行它时,我只得到当前文档。

这是从术语向量中获取位置数据的正确且唯一的方法吗?为什么会有这么不直观的 API?是否有文件解释为什么以前的方法改变了这一点?

标签: lucene

解决方案


不知道“对还是错”,但对于 6.6.3 版,这似乎可行。

private void run() throws Exception {
    Directory directory = new RAMDirectory();
    IndexWriterConfig indexWriterConfig = new IndexWriterConfig(new StandardAnalyzer());
    IndexWriter writer = new IndexWriter(directory, indexWriterConfig);

    Document doc = new Document();
    // Field.Store.NO, Field.Index.ANALYZED, Field.TermVector.YES
    FieldType type = new FieldType();
    type.setStoreTermVectors(true);
    type.setStoreTermVectorPositions(true);
    type.setStoreTermVectorOffsets(true);
    type.setIndexOptions(IndexOptions.DOCS);

    Field fieldStore = new Field("tags", "foo bar and then some", type);
    doc.add(fieldStore);
    writer.addDocument(doc);
    writer.close();

    DirectoryReader reader = DirectoryReader.open(directory);
    IndexSearcher searcher = new IndexSearcher(reader);

    Term t = new Term("tags", "bar");
    Query q = new TermQuery(t);
    TopDocs results = searcher.search(q, 1);

    for ( ScoreDoc scoreDoc: results.scoreDocs ) {
        Fields termVs = reader.getTermVectors(scoreDoc.doc);
        Terms f = termVs.terms("tags");
        TermsEnum te = f.iterator();
        PostingsEnum docsAndPosEnum = null;
        BytesRef bytesRef;
        while ( (bytesRef = te.next()) != null ) {
            docsAndPosEnum = te.postings(docsAndPosEnum, PostingsEnum.ALL);
            // for each term (iterator next) in this field (field)
            // iterate over the docs (should only be one)
            int nextDoc = docsAndPosEnum.nextDoc();
            assert nextDoc != DocIdSetIterator.NO_MORE_DOCS;
            final int fr = docsAndPosEnum.freq();
            final int p = docsAndPosEnum.nextPosition();
            final int o = docsAndPosEnum.startOffset();
            System.out.println("p="+ p + ", o=" + o + ", l=" + bytesRef.length + ", f=" + fr + ", s=" + bytesRef.utf8ToString());
        }
    }
}

推荐阅读