我正在使用Lucene
处理索引器,上周又添加了TermVectors
存储代码,以便我可以尝试反馈和其他有趣的东西。在存储术语向量的这一步之后,我开始收到以下错误:
java.lang.IllegalArgumentException:Document包含至少一个 字段中的巨大术语=“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
好的,没问题。 (好吧,死在一个过长的令牌上对我来说感觉就像一个错误,但这是一个有意识的API在4.8中的移动。)所以我添加了以下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。
我是否错误地编写了分析仪?
答案 0 :(得分:0)
字段的长度小于字符中的IndexWriter限制,但超过字节的限制。 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()
来获取长度。