analysis说明
lucene ananlysis应用场景
lucene提供了analysis用来将文本转换到索引文件或提供给IndexSearcher查询索引;
对于lucene而言,不管是索引还是检索,都是针对于纯文本输入来讲的;
通过lucene的强大类库我们可以访问各种格式的文档,如HTML、XML、PDF、Word、TXT等,
我们需要传递给lucene的只是文件中的纯文本内容;
lucene的词语切分
lucene的索引和检索前提是其对文本内容的分析和词组的切分;比如,文档中有一句话叫“Hello World,Welcome to Lucene”
我们想找到包含这段话的文档,而用户输入的查询条件又不尽详细(可能只是hello)
这里我们就需要用到lucene索引该文档的时候预先对文档内容进行切分,将词源和文本对应起来。
有时候对词语进行简单切分还远远不够,我们还需要对字符串进行深度切分,lucene不仅能够对索引内容预处理还可以对请求参数进行切分;
使用analyzer
lucene的索引使用如下:
package com.github.houbb.lucene.learn.chap03;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.analysis.tokenattributes.OffsetAttribute;
import java.io.IOException;
import java.io.StringReader;
/**
* @author binbin.hou
* @since 1.0.0
*/
public class AnalysisDemo {
public static void main(String[] args) {
// or any other analyzer
try (Analyzer analyzer = new StandardAnalyzer();
TokenStream ts = analyzer.tokenStream("myfield", new StringReader(
"some text goes here"));) {
OffsetAttribute offsetAtt = ts.addAttribute(OffsetAttribute.class);
ts.reset(); // Resets this stream to the beginning. (Required)
while (ts.incrementToken()) {
// Use AttributeSource.reflectAsString(boolean)
// for token stream debugging.
System.out.println("token: " + ts.reflectAsString(true));
System.out.println("token start offset: "
+ offsetAtt.startOffset());
System.out.println("token end offset: "
+ offsetAtt.endOffset());
System.out.println();
}
ts.end();
} catch (IOException e) {
e.printStackTrace();
}
}
}
这里是标准的分词,输出如下:
token: org.apache.lucene.analysis.tokenattributes.CharTermAttribute#term=some,org.apache.lucene.analysis.tokenattributes.TermToBytesRefAttribute#bytes=[73 6f 6d 65],org.apache.lucene.analysis.tokenattributes.OffsetAttribute#startOffset=0,org.apache.lucene.analysis.tokenattributes.OffsetAttribute#endOffset=4,org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute#positionIncrement=1,org.apache.lucene.analysis.tokenattributes.PositionLengthAttribute#positionLength=1,org.apache.lucene.analysis.tokenattributes.TypeAttribute#type=<ALPHANUM>,org.apache.lucene.analysis.tokenattributes.TermFrequencyAttribute#termFrequency=1
token start offset: 0
token end offset: 4
...
就是将我们的 some text goes here
进行分词,变成最基本的 Term: some text goes here。
当然,我们可以自定义属于自己的分词实现。
自定义Analyzer和实现自己的analysis模块
1.要实现自己的analyzer,我们需要继承Analyzer并重写其中的分词模块。
2.维护停止词词典
3.重写TokenStreamComponents方法,选择合适的分词方法,对词语进行过滤
例子
示例代码如下
package com.github.houbb.lucene.learn.chap03;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.CharArraySet;
import org.apache.lucene.analysis.StopFilter;
import org.apache.lucene.analysis.Tokenizer;
import org.apache.lucene.analysis.core.LowerCaseTokenizer;
import org.apache.lucene.analysis.core.StopAnalyzer;
/**
* @author binbin.hou
* @since 1.0.0
*/
public class MyAnalyzer extends Analyzer {
private CharArraySet stopWordSet;//停止词词典
public CharArraySet getStopWordSet() {
return stopWordSet;
}
public void setStopWordSet(CharArraySet stopWordSet) {
this.stopWordSet = stopWordSet;
}
public MyAnalyzer() {
super();
this.stopWordSet = StopAnalyzer.ENGLISH_STOP_WORDS_SET;//可在此基础上拓展停止词
}
/**
* 扩展停止词
*
* @param stops
*/
public MyAnalyzer(String[] stops) {
this();
stopWordSet.addAll(StopFilter.makeStopSet(stops));
}
@Override
protected TokenStreamComponents createComponents(String fieldName) {
//正则匹配分词
Tokenizer source = new LowerCaseTokenizer();
return new TokenStreamComponents(source, new StopFilter(source, stopWordSet));
}
}
我们自定义一个可以指定 stopword 的分析器。
测试代码
String words = "A AN yuyu";
try (Analyzer analyzer = new MyAnalyzer();
TokenStream stream = analyzer.tokenStream("myField", words)) {
stream.reset();
CharTermAttribute offsetAtt = stream.addAttribute(CharTermAttribute.class);
while (stream.incrementToken()) {
System.out.println(offsetAtt.toString());
}
stream.end();
} catch (IOException e) {
e.printStackTrace();
}
输出结果为:
yuyu
因为其中的 A AN 都是停顿词,被过滤掉了。
总结
当然,除了常规的停顿词,,我们也可以添加其他各种丰富的过滤策略。
比如长度低于 2 个字符进行过滤等等。