将自定义分析器与Lucene 4.9一起使用时违反令牌流协定

将自定义分析器与Lucene 4.9一起使用时违反令牌流协定,lucene,analyzer,Lucene,Analyzer,我有一些像这样的自定义分析器: private static class ModelAnalyzer extends Analyzer { @Override protected TokenStreamComponents createComponents(String string, Reader reader) { return new TokenStreamComponents( new StandardTokenizer(V

我有一些像这样的自定义分析器:

private static class ModelAnalyzer extends Analyzer
{
    @Override
    protected TokenStreamComponents createComponents(String string, Reader reader)
    {
        return new TokenStreamComponents(
            new StandardTokenizer(Version.LUCENE_4_9, reader),
            new LowerCaseFilter(Version.LUCENE_4_9,
                new NGramTokenFilter(Version.LUCENE_4_9,
                    new CharTokenizer(Version.LUCENE_4_9, reader)
                    {
                        @Override
                        protected boolean isTokenChar(int c)
                        {
                            return Character.isLetterOrDigit(c);
                        }
                    }, 3, 20)));
    }
}
它们被添加到PerfielDanalyzerRapper并添加到我的IndexWriterConfig。当我尝试重建索引时,在将第二个文档添加到索引时,我总是会遇到错误:

java.lang.IllegalStateException: TokenStream contract violation: reset()/close() call missing, reset() called multiple times, or subclass does not call super.reset(). Please see Javadocs of TokenStream class for more information about the correct consuming workflow.
我所做的就是将文档添加到我的IndexWriter中。我没有以任何方式接触这些过滤器或标记器,因此没有干净的方式对它们调用reset()。没有我的帮助,IndexWriter不应该遵循“正确的消费工作流”吗


在网上阅读了8个小时后,我放弃了,只是将Version.LUCENE_4_5传递给了我的每个标记器和过滤器,这样就不会运行恼人的状态机检查(据我所知,是在4_6中添加的)。这已经解决了这个问题,但是我不知道如何用4.9实现这个功能。我不得不假设我的分析器出了问题,但我看不出我怎么能做得不同,在早期版本中它工作得很好。

可能问题在于你添加了两次阅读器。它必须以这种方式工作:

Tokenizer tokenizer = new StandardTokenizer(Version.LUCENE_4_9, reader);
TokenFilter filters = new LowerCaseFilter(Version.LUCENE_4_9, tokenizer);
filters = new NGramTokenFilter(Version.LUCENE_4_9, filters);
filters = ...
return new TokenStreamComponents(tokenizer, filters);

贾维给我指出了正确的方向,他说我的读者可能被使用了两次。我回到我的分析器,利用当前预先编写的组件从头重写它。现在,这项工作非常有效。基本上,关键是保持它的简单,而不是试图直接移植

private static class ModelAnalyzer extends Analyzer
{
    @Override
    protected TokenStreamComponents createComponents(String string, Reader reader)
    {
        Tokenizer tokenizer = new NGramTokenizer(Version.LUCENE_4_9, reader, 3, 20)
        {
            @Override
            protected boolean isTokenChar(int c)
            {
                return Character.isLetterOrDigit(c);
            }
        };
        return new TokenStreamComponents(tokenizer,
            new LowerCaseFilter(Version.LUCENE_4_9, tokenizer));
    }
}

谢谢你帮我找到解决办法。您确实标记了问题,但您的代码可能不是解决问题的正确方法。在绞尽脑汁讨论如何正确记录这个解决方案后,我决定发布确切的答案,以便让其他人更容易一眼就能看出我认为更正确的解决方案。