【问题标题】:Lucene TokenStream ExceptionLucene TokenStream 异常
【发布时间】:2014-06-16 13:06:11
【问题描述】:

我遇到了与this thread 完全相同的问题,所以我要提出一个新问题。很抱歉大家回答了链接的线程,顺便说一句。

所以:我正在尝试避免 java.lang.IllegalStateException: TokenStream 合同违规。

我有一个与上面链接非常相​​似的代码:

protected TokenStreamComponents createComponents( String fieldName, Reader reader ) {

String token;
CharArraySet stopWords = new CharArraySet( Version.LUCENE_48, 0, false );
stopWords.addAll( StopAnalyzer.ENGLISH_STOP_WORDS_SET );
keepWords.addAll( getKeepWordList() );

Tokenizer source = new StandardTokenizer( Version.LUCENE_48, reader );
TokenStream filter = new StandardFilter( Version.LUCENE_48, source );
filter = new StopFilter( Version.LUCENE_48, filter, stopWords );
ShingleFilter shiFilter = new ShingleFilter( filter, 2, 3 );
CharTermAttribute cta = shiFilter.addAttribute( CharTermAttribute.class );

try {
    shiFilter.reset();
    while( shiFilter.incrementToken() ) {

        token = cta.toString();
        System.out.println( token );
    }
    shiFilter.end();
    shiFilter.close();
} 
catch ( IOException ioe ) {

    ioe.printStackTrace();
}
return new TokenStreamComponents( source, filter );
}

我不明白建议的解决方案:“简单地构造一个新的 TokenStream”或“重置阅读器”是什么意思?我已经尝试了这两种解决方案,比如添加:

source.setReader( reader );

或改为:

filter = new StopFilter( Version.LUCENE_48, filter, stopWords );
ShingleFilter shiFilter = new ShingleFilter( filter, 2, 3 );

但错误最后。有什么建议吗?

【问题讨论】:

    标签: java exception lucene token tokenize


    【解决方案1】:

    您的问题是您正在使用过滤器中的所有内容并在将其从createComponents 调用传回之前将其关闭。

    我想你是在尝试调试分析是如何工作的:

    try {
        shiFilter.reset();
        while( shiFilter.incrementToken() ) {
            token = cta.toString();
            System.out.println( token );
        }
        shiFilter.end();
        shiFilter.close();
    } 
    catch ( IOException ioe ) {
        ioe.printStackTrace();
    }
    

    但请注意,当您完成它时,shiFilter 位于流的末尾,并且已关闭。您现在将它从 TokenStreamComponents 中的方法传回,此时 Lucene 现在将尝试使用它来索引文档。它将首先调用reset(),并在尝试使用已关闭的资源时抛出指示的异常。

    如果您想对此进行调试,我建议您只创建一个自定义分析器的实例,然后调用analyzer.tokenStream 以获取用于调试输出的流。如果您确实需要通过迭代过滤器实例而不是分析器来进行调试,则需要构建一个单独的实例,而不是使用 createComponents 中的流。

    【讨论】:

    • 所以,如果我理解正确的话,将那段代码放入 createComponents 涉及到对reset 的不正确使用,也就是说,将重置一个已经关闭的资源。这说得通。然后,我必须移动我的自定义分析器所在的那部分。无论如何,我的目的不是调试。我想创建自定义令牌,例如选择某些单词的邻域。我想我应该在 createComponents 中这样做。
    • 如果你想在分析中做一些处理来修改(或添加,或删除)令牌,你应该实现一个TokenFilter,并将它添加到你的过滤器链中(就像你的ShingleFilterStopFilter,例如)。
    • 那我唯一要做的就是从TokenFilter抽象类中重写incrementToken方法?
    【解决方案2】:

    我不完全明白你想要做什么。我相信除了一元组之外,您还想从令牌流中获取二元组和三元组。以下代码片段(我在对您的代码进行了一些清理后开发的)为我运行,并且是执行此操作的标准方式。

    import java.io.*;
    import org.apache.lucene.analysis.core.*;
    import org.apache.lucene.analysis.*;
    import org.apache.lucene.analysis.ngram.NGramTokenFilter;
    import org.apache.lucene.analysis.shingle.ShingleFilter;
    import org.apache.lucene.analysis.standard.*;
    import org.apache.lucene.util.*;
    import org.apache.lucene.analysis.util.*;
    import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
    
    class TestAnalyzer extends Analyzer {
    
    TestAnalyzer() {
        super();
    }
    
    protected TokenStreamComponents createComponents( String fieldName, Reader reader ) {
        String token;
        TokenStream result = null;
    
        Tokenizer source = new StandardTokenizer( Version.LUCENE_CURRENT, reader );
        result = new ShingleFilter(source, 2, 3);
    
        return new TokenStreamComponents( source, result );
    }
    }
    
    public class LuceneTest {
    
    public static void main(String[] args) {
    
        TestAnalyzer analyzer = new TestAnalyzer();
    
        try {
            TokenStream stream = analyzer.tokenStream("field", new StringReader("This is a damn test."));
            CharTermAttribute termAtt = stream.addAttribute(CharTermAttribute.class);
    
            stream.reset();
    
            // print all tokens until stream is exhausted
            while (stream.incrementToken()) {
                System.out.println(termAtt.toString());
            }
    
            stream.end();
            stream.close();
         }
         catch (Exception ex) {
             ex.printStackTrace();
         }
    }
    

    }

    【讨论】:

    • 感谢您的回复。
    • 你能得到预期的输出吗?
    • 我会尝试,然后提供反馈。无论如何:我的目的是分析令牌的邻域以获得个性化的 N-gram。例如,如果我标记匹配一个前缀单词列表,则在前后添加 2 或 3 标记。比如,考虑到“狐狸”这个标记,有“棕色狐狸跳过”或类似的意思。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多