Java Lucene和太长的代币

Java Lucene和太长的代币,java,lucene,Java,Lucene,我正在使用Lucene开发一个索引器,上周在代码中添加了存储TermVectors,这样我就可以尝试反馈和其他有趣的东西。在存储术语向量的这一步之后,我开始出现以下错误: java.lang.IllegalArgumentException:文档至少包含一个 字段中的巨大术语=“f_common.document.text”(其UTF8编码 大于最大长度32766),所有这些都被跳过。 请更正分析器,使其不产生此类术语。前缀 第一个巨大的术语是:“[34,60,97,99,114,101,58,

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

java.lang.IllegalArgumentException:文档至少包含一个 字段中的巨大术语=“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个

好的,没问题。(好吧,死在超长的令牌上对我来说就像一个bug,但这是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


是否写入分析器错误?

字段长度小于IndexWriter的字符限制,但超过了字节限制
LengthFilter
根据令牌的字符长度(UTF-16代码单位)过滤掉令牌
IndexWriter.MAX_TERM_LENGTH
则以UTF-8编码字节为单位

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

import java.nio.CharBuffer;
导入java.nio.charset.charset;
导入org.apache.lucene.analysis.TokenStream;
导入org.apache.lucene.analysis.util.FilteringTokenFilter;
导入org.apache.lucene.analysis.tokenattributes.CharterMatAttribute;
公共最终类ByteLengthFilter扩展FilteringTokenFilter{
私人最终整数分钟;
私人最终整数最大值;
私有最终CharterMatAttribute termAtt=addAttribute(charterMatAttribute.class);
public ByTeleneghtFilter(令牌流输入、最小整数、最大整数){
超级(in),;
如果(最小值<0){
抛出新的IllegalArgumentException(“最小长度必须大于或等于零”);
}
如果(最小值>最大值){
抛出新的IllegalArgumentException(“最大长度不得大于最小长度”);
}
this.min=min;
this.max=max;
}
@凌驾
公共布尔接受(){
final int len=Charset.forName(“UTF-8”).encode(CharBuffer.wrap(termAtt)).remaining();

return(len>=min&&len字段的长度小于IndexWriter的字符限制,但超过了字节限制。
LengthFilter
根据标记的字符长度(UTF-16代码单位)过滤掉标记。
IndexWriter.MAX\u TERM\u length
则是UTF-8编码字节

此筛选器应该满足您的需要。其工作原理与
LengthFilter
相同,因此可以很容易地将类似的内容放入
SafetyAnalyzer
(它实际上只是
LengthFilter
的一个副本,带有修改的
accept()
方法):

import java.nio.CharBuffer;
导入java.nio.charset.charset;
导入org.apache.lucene.analysis.TokenStream;
导入org.apache.lucene.analysis.util.FilteringTokenFilter;
导入org.apache.lucene.analysis.tokenattributes.CharterMatAttribute;
公共最终类ByteLengthFilter扩展FilteringTokenFilter{
私人最终整数分钟;
私人最终整数最大值;
私有最终CharterMatAttribute termAtt=addAttribute(charterMatAttribute.class);
public ByTeleneghtFilter(令牌流输入、最小整数、最大整数){
超级(in),;
如果(最小值<0){
抛出新的IllegalArgumentException(“最小长度必须大于或等于零”);
}
如果(最小值>最大值){
抛出新的IllegalArgumentException(“最大长度不得大于最小长度”);
}
this.min=min;
this.max=max;
}
@凌驾
公共布尔接受(){
final int len=Charset.forName(“UTF-8”).encode(CharBuffer.wrap(termAtt)).remaining();

返回(len>=min&&len谢谢你提供的线索。也许最好换一种方式,计算我希望能够为即将到来的数据保留多少字符。我将尝试两种方式,看看会发生什么。@IanSoboroff-当然,你可以安全地将其限制在
IndexWriter.MAX\u TERM\u LENGTH/4
,我相信。谢谢你提供的线索最好换一种方式,计算我希望能为即将到来的数据保留多少个字符。我将尝试两种方法,看看会发生什么。@IanSoboroff-当然,我相信您可以安全地将其限制为
IndexWriter.MAX\u TERM\u LENGTH/4
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);
  }
}