Lucene代码拥有很强的扩展性,很多的关键代码都提供了用户自定义方式,可以根据特定的场景自定义处理方式,这篇文章就探讨一下lucene在数据写入过程中有哪些可扩展的地方。
下面是lucene数据写入的代码:
- 自定义分词器
一个分词器有以下几个属性:
Filter : 分词过滤器 , 比如:LowerCaseFilterFactory,小写转换
Tokenizer:分词处理器,用于具体的分词处理
Attribute:分词属性对象,包括CharTermAttribute,PayloadAttribute等等,用于存储分词之后的值。
其中Tokenizer,Filter 是同级的,多个Filter 和Tokenizer组成一个相互引用的串,一次处理传来的文本值,看下StandardAnalyzer分词器中是如何相互引用的
Field的文本值首先进入stopFilter中的incrementToken方法中处理,并以此调用之前的类的incrementToken完成对整个串的调用。
自定义分词器需要继承Analyzer类,createComponent方法获取分词器对象,下面是一个自定义分词器的完整的例子:
public class PayloadAnylzer extends Anlyzer{
/** Default maximum allowed token length */
public static final int DEFAULT_MAX_TOKEN_LENGTH = 255;
private int maxTokenLength = DEFAULT_MAX_TOKEN_LENGTH;
/** An unmodifiable set containing some common English words that are usually not
useful for searching. */
public static final CharArraySet STOP_WORDS_SET = StopAnalyzer.ENGLISH_STOP_WORDS_SET;
private char delimiter;
public PayloadAnylzer(char delimiter){
this.delimiter = delimiter;
}
public void setMaxTokenLength(int length) {
maxTokenLength = length;
}
public int getMaxTokenLength() {
return maxTokenLength;
}
protected TokenStreamComponents createComponents(final String fieldName) {
Tokenizer src = new PayloadTokenizer(this.delimiter);
tok = new LowerCaseFilter(tok);
tok = new StopFilter(tok, stopwords);
return new TokenStreamComponents(src, tok) {
@Override
protected void setReader(final Reader reader) throws IOException {
int m = StandardAnalyzer.this.maxTokenLength;
if (src instanceof StandardTokenizer) {
((StandardTokenizer)src).setMaxTokenLength(m);
} else {
((StandardTokenizer40)src).setMaxTokenLength(m);
}
super.setReader(reader);
}
};
}
}
}
- 不同的列选择不同的分词器
Lucene提供了为不同的列选择不同分词器的能力,lucene包里面有个PerFieldAnalyzerWrapper类,解决了这一问题,用法如下:
PerFieldAnalyzerWrapper aWrapper = new PerFieldAnalyzerWrapper(new StandardAnalyzer());
aWrapper.addAnalyzer("firstname", new KeywordAnalyzer());
aWrapper.addAnalyzer("lastname", new KeywordAnalyzer());上面的例子中列"firstname"和"lastname"会使用KeywordAnalyzer作为分词器,其余的列会使用的默认的分词器StandardAnalyzer。其中aWrapper 可以被当作任何analyzer来使用,用于索引和查询数据。下面是一个完整的例子:
- 自定义codec
Codec是lucene与文件交互的组件,通过自定义codec可以改变文件lucene中个文件存储和读取的方式,首先继承类FilterCodec,复写其中的方法,下面是一个自定义codec的例子:
Lucene中所有的codec都需要在services下的文件org.apache.lucene.codecs.codec中记录,如下:
- 自定义indexingchain
indexingchain是数据写入的核心类,包括数据的写入和刷盘。Indexwriter类中提供了indexingchain的set方法:
通过复写DocConsumer中的三个方法实现自定义indexingchain。
- 自定义mergePolicy
mergePolicy是用于段检测,找到符合合并的段,并将所有符合合并的段封装到内部类OneMerge中,用于后续的合并。
Lucene的indexwriterConfig中提供了set方法:
Lucene的默认实现是TieredMergePolicy,通过重写父类MergePolicy中的findMerges等方法可完成自定义mergePolicy。
- 自定义mergescheduler
mergescheduler是合并的核心类,执行真正的合并操作,Lucene的indexwriterConfig中提供了set方法:
复写类MergeScheduler中的merge等方法实现自定义mergescheduler。