如何从Lucene TokenStream中获取Token?

77
4个回答

119

是的,相对于旧方法来说,这有点复杂,但这应该可以解决问题:

TokenStream tokenStream = analyzer.tokenStream(fieldName, reader);
OffsetAttribute offsetAttribute = tokenStream.getAttribute(OffsetAttribute.class);
TermAttribute termAttribute = tokenStream.getAttribute(TermAttribute.class);

while (tokenStream.incrementToken()) {
    int startOffset = offsetAttribute.startOffset();
    int endOffset = offsetAttribute.endOffset();
    String term = termAttribute.term();
}

编辑: 方法

根据Donotello的说法,TermAttribute已被弃用,取而代之的是CharTermAttribute。根据jpountz(以及Lucene的文档),addAttributegetAttribute更可取。

TokenStream tokenStream = analyzer.tokenStream(fieldName, reader);
OffsetAttribute offsetAttribute = tokenStream.addAttribute(OffsetAttribute.class);
CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);

tokenStream.reset();
while (tokenStream.incrementToken()) {
    int startOffset = offsetAttribute.startOffset();
    int endOffset = offsetAttribute.endOffset();
    String term = charTermAttribute.toString();
}

6
现在 TermAttribute 已经被弃用。根据我的观察,我们可以使用类似 CharTermAttributeImpl.toString() 的东西来替代它。 - Donotello
6
建议使用addAttribute而不是getAttribute。根据Lucene的Java文档:“建议即使在TokenStreams的消费者中也始终使用addAttribute(java.lang.Class),因为您无法知道特定的TokenStream是否真正使用特定的Attribute”。http://lucene.apache.org/core/old_versioned_docs/versions/3_5_0/api/all/org/apache/lucene/util/AttributeSource.html#getAttribute(java.lang.Class) - jpountz
1
@jpountz:谢谢你的提示!我已经相应地修改了答案。 - Adam Paynter
2
必须在Lucene 4.3中调用reset(),因此我冒昧添加了它。 - Enno Shioji
最后,我在帖子问题上没有看到答案:“如何从Lucene TokenStream中获取一个Token?” - serhio
显示剩余3条评论

41

这是应该的方式(Adam答案的简化版):

TokenStream stream = analyzer.tokenStream(null, new StringReader(text));
CharTermAttribute cattr = stream.addAttribute(CharTermAttribute.class);
stream.reset();
while (stream.incrementToken()) {
  System.out.println(cattr.toString());
}
stream.end();
stream.close();

10
在while循环之前添加stream.reset()后,您的代码才正常工作。我正在使用Lucene 4.0,所以这可能是最近进行的更改。请参考此页面底部附近的示例: http://lucene.apache.org/core/4_0_0-BETA/core/org/apache/lucene/analysis/package-summary.html - user785262
尝试编辑以添加reset()调用,避免在incrementToken()内部出现NPE,但除一个同行外,所有人都拒绝了该编辑,认为其不正确。Lucene文档明确指出,在TokenStream API中,“消费者在调用incrementToken()之前调用reset()”。(http://lucene.apache.org/core/4_0_0/core/org/apache/lucene/analysis/TokenStream.html) - William Price
还必须在Lucene 4.3中调用reset(),所以我冒昧地加了进去。 - Enno Shioji
也许这个问题有点奇怪,但最终并不是很清楚如何获取下一个Token(而不是下一个字符串)? - serhio

3

最新版本的lucene是7.3.1

    // Test the tokenizer
    Analyzer testAnalyzer = new CJKAnalyzer();
    String testText = "Test Tokenizer";
    TokenStream ts = testAnalyzer.tokenStream("context", new StringReader(testText));
    OffsetAttribute offsetAtt = ts.addAttribute(OffsetAttribute.class);
    try {
        ts.reset(); // Resets this stream to the beginning. (Required)
        while (ts.incrementToken()) {
            // Use AttributeSource.reflectAsString(boolean)
            // for token stream debugging.
            System.out.println("token: " + ts.reflectAsString(true));

            System.out.println("token start offset: " + offsetAtt.startOffset());
            System.out.println("  token end offset: " + offsetAtt.endOffset());
        }
        ts.end();   // Perform end-of-stream operations, e.g. set the final offset.
    } finally {
        ts.close(); // Release resources associated with this stream.
    }

参考:https://lucene.apache.org/core/7_3_1/core/org/apache/lucene/analysis/package-summary.html
这是一个关于IT技术的链接,介绍了Lucene分析器的核心功能。Lucene分析器提供了创建、处理和解析文本的工具,以便搜索引擎可以更好地理解和搜索文本。这个链接详细说明了Lucene分析器的各种功能和用途。

1

OP的问题有两个变化:

  1. “如何从TokenStream获取令牌的过程是什么?”
  2. “有人能解释一下如何从TokenStream获取类似令牌的信息吗?”

Lucene文档关于Token的最新版本表示(重点加粗):

注意:自2.9版本以来...不再需要使用Token,使用新的TokenStream API作为实现所有属性的便捷类,可特别方便地从旧的TokenStream API切换到新的API。

TokenStream的API表示:

...已经从基于Token转移到了基于Attribute...存储Token信息的首选方法是使用AttributeImpls。

本问题的其他答案涵盖了#2:如何使用属性以“新”推荐的方式从TokenStream获取类似令牌的信息。通过阅读文档,Lucene开发人员建议部分原因是为了减少一次创建的单个对象数量。
但正如一些人在这些答案的评论中指出的那样,它们并没有直接回答#1:如果您真的想/需要该类型,如何获取Token
通过使TokenStream成为AttributeSource的同一API更改,Token现在实现Attribute,并且可以像其他答案所显示的CharTermAttributeOffsetAttribute一样与TokenStream.addAttribute一起使用。因此,他们确实回答了原始问题的那部分,只是没有显示出来。

重要的是,尽管这种方法允许您在循环时访问 Token,但它仍然只是一个对象,无论流中有多少逻辑标记。每次调用 incrementToken() 都会更改从 addAttribute 返回的 Token 的状态; 因此,如果您的目标是构建一组不同的 Token 对象以在循环外使用,则需要额外的工作来制作一个(深度?)副本作为一个新的Token对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接