如何从Lucene TokenStream获取令牌?


74

我正在尝试使用Apache Lucene进行令牌化,但我对从中获取令牌的过程感到困惑TokenStream

最糟糕的部分是我正在查看JavaDocs中解决我的问题的注释。

http://lucene.apache.org/java/3_0_1/api/core/org/apache/lucene/analysis/TokenStream.html#incrementToken%28%29

不知何故,AttributeSource应该使用an而不是Tokens。我完全不知所措。

谁能解释如何从TokenStream获得类似令牌的信息?

Answers:


114

是的,这有点令人费解(与好的方式相比),但是应该这样做:

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的文档),addAttribute比更为可取getAttribute

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

@Donotello:非常感谢!
亚当·佩恩特

6
您应该使用addAttribute而不是getAttribute。来自lucene javadocs的文章:“即使在TokenStream的使用者中,也建议始终使用addAttribute(java.lang.Class),因为您不知道特定的TokenStream是否确实使用了特定的属性” lucene.apache.org/core/old_versioned_docs/versions / 3_5_0 / api /…
jpountz 2012年

1
@jpountz:谢谢小费!我已经相应地修改了答案。
Adam Paynter 2012年

2
不得不打电话reset()给Lucene 4.3,所以
随意

38

这应该是这样(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,所以可能是最近的更改。请参阅此页面底部附近的示例:lucene.apache.org/core/4_0_0-BETA/core/org/apache/lucene/…– user785262 2013

试图编辑以添加reset()调用,该调用避免了Lucene内部的incrementToken()处的NPE,但是除一个对等方外,所有其他人均拒绝编辑为不正确。Lucene文档明确表示在TokenStream API中
William Price

还必须致电reset()Lucene 4.3,所以我自由地添加了它
Enno Shioji 2013年

也许这个问题很奇怪,但是最后,不是很清楚如何获得下一个令牌(不是下一个字符串)吗?
serhio 2014年

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


1

OP问题有两种变体:

  1. 什么是“从TokenStream获取令牌的过程”?
  2. “谁能解释如何从TokenStream获得类似令牌的信息?”

说说Lucene文档的Token最新版本(添加了重点):

注意:从2.9版本开始...不再需要使用Token,对于新的TokenStream API,它可以用作实现所有属性的便捷类,这对于轻松地从旧的TokenStream API切换到新的TokenStream API特别有用。

TokenStream说它的API:

...已经从基于令牌的转变为基于属性的...存储令牌信息的首选方法是使用AttributeImpls。

此问题的其他答案包括上面的#2:如何使用属性以“新”推荐的方式从中获取类似令牌的信息TokenStream。通过阅读文档,Lucene开发人员建议进行此更改,部分是为了减少一次创建的单个对象的数量。

但是,正如某些人在这些答案的注释中指出的那样,他们没有直接回答#1:Token如果您确实想要/需要该类型,您将如何获得?

在相同的API的变化,使TokenStream一个AttributeSourceToken现在实现Attribute并可以搭配TokenStream.addAttribute就像其他的答案显示CharTermAttributeOffsetAttribute。因此,他们确实回答了原始问题的那一部分,只是没有显示出来。

重要的是,尽管这种方法将允许您Token在循环时进行访问,但是无论流中有多少逻辑标记,它仍然只是一个对象。每次致电incrementToken()都会改变Token返回状态addAttribute;因此,如果您的目标是构建Token要在循环外使用的不同对象的集合,那么您将需要做额外的工作来制作一个新的 Token对象(深层副本)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.