我正在尝试使用Apache Lucene进行分词,但从TokenStream
中获取标记的过程让我十分困惑。
最糟糕的是,我正在查看JavaDocs中解答我的问题的注释。
一些注释提到应该使用AttributeSource
而不是Token
。我完全不知所措。
有人能解释一下如何从TokenStream中获取类似标记的信息吗?
我正在尝试使用Apache Lucene进行分词,但从TokenStream
中获取标记的过程让我十分困惑。
最糟糕的是,我正在查看JavaDocs中解答我的问题的注释。
一些注释提到应该使用AttributeSource
而不是Token
。我完全不知所措。
有人能解释一下如何从TokenStream中获取类似标记的信息吗?
是的,相对于旧方法来说,这有点复杂,但这应该可以解决问题:
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();
}
这是应该的方式(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();
reset()
,所以我冒昧地加了进去。 - Enno Shioji最新版本的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.
}
OP的问题有两个变化:
Lucene文档关于Token
的最新版本表示(重点加粗):
注意:自2.9版本以来...不再需要使用Token,使用新的TokenStream API作为实现所有属性的便捷类,可特别方便地从旧的TokenStream API切换到新的API。
TokenStream
的API表示:
本问题的其他答案涵盖了#2:如何使用属性以“新”推荐的方式从...已经从基于Token转移到了基于Attribute...存储Token信息的首选方法是使用AttributeImpls。
TokenStream
获取类似令牌的信息。通过阅读文档,Lucene开发人员建议部分原因是为了减少一次创建的单个对象数量。Token
?TokenStream
成为AttributeSource
的同一API更改,Token
现在实现Attribute
,并且可以像其他答案所显示的CharTermAttribute
和OffsetAttribute
一样与TokenStream.addAttribute一起使用。因此,他们确实回答了原始问题的那部分,只是没有显示出来。
重要的是,尽管这种方法允许您在循环时访问 Token
,但它仍然只是一个对象,无论流中有多少逻辑标记。每次调用 incrementToken()
都会更改从 addAttribute
返回的 Token
的状态; 因此,如果您的目标是构建一组不同的 Token
对象以在循环外使用,则需要额外的工作来制作一个(深度?)副本作为一个新的Token
对象。
CharTermAttributeImpl.toString()
的东西来替代它。 - Donotelloreset()
,因此我冒昧添加了它。 - Enno Shioji