【问题标题】:Lucene and tokens that are too longLucene 和太长的令牌
【发布时间】:2016-03-10 14:06:01
【问题描述】:

我正在使用Lucene 开发一个索引器,上周在代码中添加了存储TermVectors 以便我可以尝试反馈和其他有趣的东西。在存储术语向量的这一步之后,我开始收到以下错误:

java.lang.IllegalArgumentException: 文档包含至少一个 field="f_common.document.text" 中的巨大术语(其 UTF8 编码 比最大长度 32766 长),所有这些都被跳过了。 请更正分析器以不产生此类术语。前缀 第一个巨大的术语是:'[34, 60, 97, 99, 114, 101, 58, 98, 108、111、99、107、62、32、32、32、60、100、105、118、32、97、99、 114, 101, 58, 100, 101, 102, 61]...',原消息:字节可以 长度最多为 32766;得到 34444

好的,没问题。 (嗯,死在一个过长的令牌上对我来说感觉像是一个错误,但这是在 4.8 中有意识的 API 移动。)所以我添加了以下 AnalyzerWrapper 来解决这个问题:

import java.io.IOException;
import java.io.StringReader;
import java.util.HashSet;
import java.util.Set;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.AnalyzerWrapper;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.miscellaneous.LengthFilter;
import org.apache.lucene.index.IndexWriter;

/*
 * Lucene's IndexWriter.addDocument() will pitch an exception if the document contains a token that is too long.
 * I would rather just drop long tokens.
 */

public class SafetyAnalyzer extends AnalyzerWrapper {

    private Analyzer baseAnalyzer;

    public SafetyAnalyzer(Analyzer baseAnalyzer) {
        super(Analyzer.PER_FIELD_REUSE_STRATEGY);
        this.baseAnalyzer = baseAnalyzer;
    }

    @Override
    public void close() {
        baseAnalyzer.close();
        super.close();
    }

    @Override
    protected Analyzer getWrappedAnalyzer(String fieldName) {
        return baseAnalyzer;
    }

    @Override
    protected TokenStreamComponents wrapComponents(String fieldName, TokenStreamComponents components) {
        TokenStream ts = components.getTokenStream();
        LengthFilter drop_long_tokens = new LengthFilter(ts, 0, IndexWriter.MAX_TERM_LENGTH);
        return new TokenStreamComponents(components.getTokenizer(), drop_long_tokens);
    }
}

这应该会丢弃IndexWriter 会吐出的长标记。这像这样包装其他分析器:

public Analyzer getDefaultIndexAnalyzer() throws Exception {
    if (defaultIndexAnalyzer == null) {
        String defaultAnalyzerName = getConfig("LUCENE_INDEX_ANALYZER_DEFAULT");
        if (defaultAnalyzerName == null)
            defaultAnalyzerName = "org.apache.lucene.analysis.standard.StandardAnalyzer";
        defaultIndexAnalyzer = new SafetyAnalyzer((Analyzer)Class.forName(defaultAnalyzerName).newInstance());
    }
    return defaultIndexAnalyzer;
}

只是,它不起作用。我仍然在这些令牌上获得 IllegalArgumentExceptions。我能找到的唯一解决方案是在 writer.addDocument() 上抓住 IAE。

我是不是写错了分析器?

【问题讨论】:

    标签: java lucene


    【解决方案1】:

    字段长度小于 IndexWriter 的 characters 限制,但超过 bytes 限制。 LengthFilter 根据字符长度(UTF-16 代码单元)过滤掉标记。另一方面,IndexWriter.MAX_TERM_LENGTH 是 UTF-8 编码字节。

    此过滤器应该可以满足您的需求。与LengthFilter 的工作方式相同,因此应该很容易将这样的内容放入您的SafetyAnalyzer(实际上它只是LengthFilter 的副本,带有修改后的accept() 方法):

    import java.nio.CharBuffer;
    import java.nio.charset.Charset;
    
    import org.apache.lucene.analysis.TokenStream;
    import org.apache.lucene.analysis.util.FilteringTokenFilter;
    import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
    
    public final class ByteLengthFilter extends FilteringTokenFilter {
    
      private final int min;
      private final int max;
      private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class);
    
      public ByteLengthFilter(TokenStream in, int min, int max) {
        super(in);
        if (min < 0) {
          throw new IllegalArgumentException("minimum length must be greater than or equal to zero");
        }
        if (min > max) {
          throw new IllegalArgumentException("maximum length must not be greater than minimum length");
        }
        this.min = min;
        this.max = max;
      }
    
      @Override
      public boolean accept() {
        final int len = Charset.forName("UTF-8").encode(CharBuffer.wrap(termAtt)).remaining();
        return (len >= min && len <= max);
      }
    }
    

    警告:不确定在实践中的表现如何。肯定比LengthFilter贵,后者只是用CharSequence.length()来获取长度。

    【讨论】:

    • 谢谢你的线索。换一种方式可能会更好,计算我希望能够为传入的数据保留多少个字符。我会尝试两种方式,看看会发生什么。
    • @IanSoboroff - 当然,您可以放心地将其限制为 IndexWriter.MAX_TERM_LENGTH / 4,我相信。
    猜你喜欢
    • 2012-09-10
    • 1970-01-01
    • 2015-07-15
    • 2018-05-03
    • 1970-01-01
    • 2013-07-02
    • 1970-01-01
    • 2016-08-18
    • 2020-03-10
    相关资源
    最近更新 更多