Lucene 中的Tokenizer, TokenFilter学习

java.io.Reader -> com.chenlb.mmseg4j.solr.MMSegTokenizer -> SynonymFilter -> StopFilter -> WordDelimiterFilter -> LowerCaseFilter -> RemoveDuplicatesTokenFilter
<fieldType name="nametext" class="solr.TextField">
<analyzer type="index">
<tokenizer class="solr.StandardTokenizerFactory"/>
<filter class="solr.LowerCaseFilterFactory"/>
<filter class="solr.KeepWordFilterFactory" words="keepwords.txt"/>
<filter class="solr.SynonymFilterFactory" synonyms="syns.txt"/>
</analyzer>
<analyzer type="query">
<tokenizer class="solr.StandardTokenizerFactory"/>
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
</fieldType>
public class SynonymFilter extends TokenFilter { private static final String TOKEN_TYPE_SYNONYM = "SYNONYM"; private Stack<String> synonymStack;
private SynonymEngine synonymEngine;
private AttributeSource.State current;
private final CharTermAttribute bytesTermAttribute;
private final PositionIncrementAttribute positionIncrementAttribute; /**
* Construct a token stream filtering the given input.
*
* @param input
*/
protected SynonymFilter(TokenStream input, SynonymEngine synonymEngine) {
super(input);
this.synonymEngine = synonymEngine;
synonymStack = new Stack<>(); this.bytesTermAttribute = addAttribute(CharTermAttribute.class);
this.positionIncrementAttribute = addAttribute(PositionIncrementAttribute.class);
} @Override
public boolean incrementToken() throws IOException {
if (!synonymStack.isEmpty()) {
String syn = synonymStack.pop();
restoreState(current); // bytesTermAttribute.setBytesRef(new BytesRef(syn.getBytes()));
// bytesTermAttribute.resizeBuffer(0);
bytesTermAttribute.append(syn); positionIncrementAttribute.setPositionIncrement(0);
return true;
} if (!input.incrementToken()) {
return false;
} if (addAliasesToStack()) {
current = captureState();
} return true;
} private boolean addAliasesToStack() throws IOException {
String[] synonyms = synonymEngine.getSynonyms(bytesTermAttribute.toString());
if (synonyms == null) {
return false;
}
for (String synonym : synonyms) {
synonymStack.push(synonym);
}
return true;
}
}
public class SynonymAnalyzer extends Analyzer {
@Override
protected TokenStreamComponents createComponents(String fieldName) {
StandardTokenizer source = new StandardTokenizer();
return new TokenStreamComponents(source, new SynonymFilter(new StopFilter(new LowerCaseFilter(source),
new CharArraySet(StopAnalyzer.ENGLISH_STOP_WORDS_SET, true)), new TestSynonymEngine()));
}
}
public interface SynonymEngine {
String[] getSynonyms(String s) throws IOException;
} public class TestSynonymEngine implements SynonymEngine { public static final Map<String, String[]> map = new HashMap<>(); static {
map.put("quick", new String[]{"fast", "speedy"});
} @Override
public String[] getSynonyms(String s) throws IOException {
return map.get(s);
}
}
public static void main(String[] args) throws IOException {
SynonymAnalyzer analyzer = new SynonymAnalyzer();
TokenStream tokenStream = analyzer.tokenStream("contents", new StringReader("The quick brown fox"));
tokenStream.reset(); CharTermAttribute charTermAttribute = tokenStream.addAttribute(CharTermAttribute.class);
OffsetAttribute offsetAttribute = tokenStream.addAttribute(OffsetAttribute.class);
PositionIncrementAttribute positionIncrementAttribute =
tokenStream.addAttribute(PositionIncrementAttribute.class);
TypeAttribute typeAttribute = tokenStream.addAttribute(TypeAttribute.class); int position = 0;
while (tokenStream.incrementToken()) {
int positionIncrement = positionIncrementAttribute.getPositionIncrement();
if (positionIncrement > 0) {
position += positionIncrement;
System.out.println();
System.out.print(position + " : ");
} System.out.printf("[%s : %d -> %d : %s]", charTermAttribute.toString(), offsetAttribute.startOffset(), offsetAttribute.endOffset(),
typeAttribute.type());
}
2 : [quick : 4 -> 9 : <ALPHANUM>][quickspeedy : 4 -> 9 : <ALPHANUM>][quickfast : 4 -> 9 : <ALPHANUM>]
3 : [brown : 10 -> 15 : <ALPHANUM>]
4 : [fox : 16 -> 19 : <ALPHANUM>]
<fieldtype name="textComplex" class="solr.TextField" positionIncrementGap="100">
<analyzer type="index">
<tokenizer class="com.chenlb.mmseg4j.solr.MMSegTokenizerFactory" mode="complex" dicPath="/Users/mazhiqiang/develop/tools/solr-5.5.0/server/solr/product/conf/dic" />
<filter class="solr.StopFilterFactory" ignoreCase="false" words="stopwords.txt"/>
<filter class="solr.WordDelimiterFilterFactory"/>
<filter class="solr.LowerCaseFilterFactory"/>
<filter class="solr.NGramFilterFactory" minGramSize="1" maxGramSize="20"/>
<filter class="solr.StandardFilterFactory"/>
</analyzer>
<analyzer type="query">
<tokenizer class="com.chenlb.mmseg4j.solr.MMSegTokenizerFactory" mode="complex" dicPath="/Users/mazhiqiang/develop/tools/solr-5.5.0/server/solr/product/conf/dic" />
<filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
<filter class="solr.StopFilterFactory" ignoreCase="false" words="stopwords.txt"/>
<filter class="solr.WordDelimiterFilterFactory"/>
<filter class="solr.LowerCaseFilterFactory"/>
<!-- <filter class="solr.EdgeNGramFilterFactory" minGramSize="1" maxGramSize="20"/> -->
<filter class="solr.RemoveDuplicatesTokenFilterFactory"/>
</analyzer>
</fieldtype>
String line = null;
while ((line = in.readLine()) != null) {
if (line.length() == 0 || line.charAt(0) == '#') {
continue; // ignore empty lines and comments
} // TODO: we could process this more efficiently.
String sides[] = split(line, "=>");
if (sides.length > 1) { // explicit mapping
if (sides.length != 2) {
throw new IllegalArgumentException("more than one explicit mapping specified on the same line");
}
String inputStrings[] = split(sides[0], ",");
CharsRef[] inputs = new CharsRef[inputStrings.length];
for (int i = 0; i < inputs.length; i++) {
inputs[i] = analyze(unescape(inputStrings[i]).trim(), new CharsRefBuilder());
} String outputStrings[] = split(sides[1], ",");
CharsRef[] outputs = new CharsRef[outputStrings.length];
for (int i = 0; i < outputs.length; i++) {
outputs[i] = analyze(unescape(outputStrings[i]).trim(), new CharsRefBuilder());
}
// these mappings are explicit and never preserve original
for (int i = 0; i < inputs.length; i++) {
for (int j = 0; j < outputs.length; j++) {
add(inputs[i], outputs[j], false);
}
}

@Override
protected TokenStreamComponents createComponents(String fieldName) {
Tokenizer tk = tokenizer.create();
TokenStream ts = tk;
for (TokenFilterFactory filter : filters) {
ts = filter.create(ts);
}
return new TokenStreamComponents(tk, ts);
}
@Override
public TokenStream create(TokenStream input) {
// if the fst is null, it means there's actually no synonyms... just return the original stream
// as there is nothing to do here.
return map.fst == null ? input : new SynonymFilter(input, map, ignoreCase);
}

StandardAnalyzer |
1 : [please : 0 -> 6 : <ALPHANUM>]
2 : [email : 7 -> 12 : <ALPHANUM>]
3 : [clark.ma : 13 -> 21 : <ALPHANUM>]
4 : [gmail.com : 22 -> 31 : <ALPHANUM>]
6 : [09 : 35 -> 37 : <NUM>]
7 : [re:aa : 39 -> 44 : <ALPHANUM>]
8 : [bb : 45 -> 47 : <ALPHANUM>]
|
去除空格,标点符号,@;
|
ClassicAnalyzer |
1 : [please : 0 -> 6 : <ALPHANUM>]
2 : [email : 7 -> 12 : <ALPHANUM>]
3 : [clark.ma@gmail.com : 13 -> 31 : <EMAIL>]
5 : [09 : 35 -> 37 : <ALPHANUM>]
6 : [re : 39 -> 41 : <ALPHANUM>]
7 : [aa : 42 -> 44 : <ALPHANUM>]
8 : [bb : 45 -> 47 : <ALPHANUM>]
|
能够识别互联网域名和email地址, |
LetterTokenizer |
1 : [Please : 0 -> 6 : word]
2 : [email : 7 -> 12 : word]
3 : [clark : 13 -> 18 : word]
4 : [ma : 19 -> 21 : word]
5 : [gmail : 22 -> 27 : word]
6 : [com : 28 -> 31 : word]
7 : [by : 32 -> 34 : word]
8 : [re : 39 -> 41 : word]
9 : [aa : 42 -> 44 : word]
10 : [bb : 45 -> 47 : word]
|
丢弃掉所有的非文本字符 |
KeywordTokenizer |
1 : [Please email clark.ma@gmail.com by 09, re:aa-bb : 0 -> 47 : word]
|
将整个文本当做一个词元 |
LowerCaseTokenizer |
1 : [please : 0 -> 6 : word]
2 : [email : 7 -> 12 : word]
3 : [clark : 13 -> 18 : word]
4 : [ma : 19 -> 21 : word]
5 : [gmail : 22 -> 27 : word]
6 : [com : 28 -> 31 : word]
7 : [by : 32 -> 34 : word]
8 : [re : 39 -> 41 : word]
9 : [aa : 42 -> 44 : word]
10 : [bb : 45 -> 47 : word]
|
对其所有非文本字符,过滤空格,标点符号,将所有的大写转换为小写 |
NGramTokenizer |
可以定义最小minGramSize(default=1), 最大切割值maxGramSize(default=2),生成的词元较多。
假设minGramSize=2, maxGramSize=3,输入abcde,输出:ab abc abc bc bcd cd cde
|
读取字段并在给定范围内生成多个token |
PathHierachyTokenizer |
c:\my document\filea\fileB,new PathHierarchyTokenizer('\\', '/')
1 : [c: : 0 -> 2 : word][c:/my document : 0 -> 14 : word][c:/my document/filea : 0 -> 20 : word][c:/my document/filea/fileB : 0 -> 26 : word]
|
使用新的文件目录符去代替文本中的目录符 |
PatternTokenizer |
需要两个参数,pattern正则表达式,group分组。
pattern=”[A-Z][A-Za-z]*” group=”0″
输入: “Hello. My name is Inigo Montoya. You killed my father. Prepare to die.”
输出: “Hello”, “My”, “Inigo”, “Montoya”, “You”, “Prepare”
|
进行正则表达式分组匹配 |
UAX29URLEmailTokenizer |
1 : [Please : 0 -> 6 : <ALPHANUM>]
2 : [email : 7 -> 12 : <ALPHANUM>]
3 : [clark.ma@gmail.com : 13 -> 31 : <EMAIL>]
4 : [by : 32 -> 34 : <ALPHANUM>]
5 : [09 : 35 -> 37 : <NUM>]
6 : [re:aa : 39 -> 44 : <ALPHANUM>]
7 : [bb : 45 -> 47 : <ALPHANUM>]
|
去除空格和标点符号,但保留url和email连接 |
ClassicFilter | “I.B.M. cat’s can’t” ==> “I.B.M”, “cat”, “can’t” | 经典过滤器,可以过滤无意义的标点,需要搭配ClassicTokenizer使用 |
ApostropheFilter |
1 : [abc : 0 -> 3 : <ALPHANUM>]
2 : [I.B.M : 4 -> 9 : <ALPHANUM>]
3 : [cat : 10 -> 15 : <ALPHANUM>]
4 : [can : 16 -> 21 : <ALPHANUM>]
|
省略所有的上撇号 |
LowerCaseFilter |
1 : [i.b.m : 0 -> 5 : <ALPHANUM>]
2 : [cat's : 6 -> 11 : <ALPHANUM>]
3 : [can't : 12 -> 17 : <ALPHANUM>]
|
转换成小写 |
TypeTokenFilter |
<filter class=”solr.TypeTokenFilterFactory” types=”email_type.txt” useWhitelist=”true”/>
如果email_type.txt设置为ALPHANUM,会保留该类型的所有分析结果,否则会被删除掉
|
给定一个文件并设置成白名单还是黑名单,只有符合条件的type才能被保留 |
TrimFilter | 去掉空格 | |
TruncateTokenFilter |
1 : [I.B : 0 -> 5 : <ALPHANUM>]
2 : [cat : 6 -> 11 : <ALPHANUM>]
3 : [can : 12 -> 17 : <ALPHANUM>]
|
截取文本长度,左边为prefixLength=3 |
PatternCaptureGroupFilter | 可配置属性pattern和preserve_original(是否保留原文) | 从输入文本中保留能够匹配正则表达式的 |
PatternReplaceFilter | ||
StopFilter | 创建一个自定义的停词词库列表,过滤器遇到停词就直接过滤掉 | |
KeepWordFilter | 与StopFilter的含义正好相反 | |
LengthFilter | 设置一个最小值min和最大值max | 为词元的长度设置在一个固定范围 |
WordDelimiterFilter |
A:-符号 wi-fi 变成wi fi 其他参数
splitOnCaseChange=”1″ 默认1,关闭设为0 规则B generateWordParts=”1″ 默认1 ,对应规则AB generateNumberParts=”1″ 默认1 对应规则F catenateWords=”1″ 默认0 对应规则A splitOnNumerics=”1″ 默认1,关闭设0 规则C stemEnglishPossessive 默认1,关闭设0 规则E catenateNumbers=”1″ 默认0 对应规则G catenateAll=”1″ 默认0 对应规则 H preserveOriginal=”1″ 默认0 对词元不做任何修改 除非有其他参数改变了词元 protected=”protwords.txt” 指定这个单词列表的单词不被修改
|
通过分隔符分割单元 |
Lucene 中的Tokenizer, TokenFilter学习的更多相关文章
- Lucene中TokenStream,Tokenizer,TokenFilter,TokenStreamComponents与Analyzer
TokenStream extends AttributeSource implements Closeable: incrementToken,end,reset,close Tokenizer直接 ...
- 《Lucene in Action 第二版》第4章节 学习总结 -- Lucene中的分析
通过第四章的学习,可以了解lucene的分析过程是怎样的,并且可以学会如何使用lucene内置分析器,以及自定义分析器.下面是具体总结 1. 分析(Analysis)是什么? 在lucene中,分析就 ...
- 理解Lucene中的Analyzer
学习一个库,最好去官网.因为很多库API变动十分大,从博客上找的教程都过时了. Lucene原理就是简简单单的"索引",以空间换时间.但是Lucene将这件事做到了极致,后人再有想 ...
- Lucene.net(4.8.0) 学习问题记录五: JIEba分词和Lucene的结合,以及对分词器的思考
前言:目前自己在做使用Lucene.net和PanGu分词实现全文检索的工作,不过自己是把别人做好的项目进行迁移.因为项目整体要迁移到ASP.NET Core 2.0版本,而Lucene使用的版本是3 ...
- Lucene.net(4.8.0) 学习问题记录一:分词器Analyzer的构造和内部成员ReuseStategy
前言:目前自己在做使用Lucene.net和PanGu分词实现全文检索的工作,不过自己是把别人做好的项目进行迁移.因为项目整体要迁移到ASP.NET Core 2.0版本,而Lucene使用的版本是3 ...
- Lucene.net(4.8.0) 学习问题记录六:Lucene 的索引系统和搜索过程分析
前言:目前自己在做使用Lucene.net和PanGu分词实现全文检索的工作,不过自己是把别人做好的项目进行迁移.因为项目整体要迁移到ASP.NET Core 2.0版本,而Lucene使用的版本是3 ...
- Python3中的字符串函数学习总结
这篇文章主要介绍了Python3中的字符串函数学习总结,本文讲解了格式化类方法.查找 & 替换类方法.拆分 & 组合类方法等内容,需要的朋友可以参考下. Sequence Types ...
- Android中的SQLite使用学习
Android中的SQLite使用学习 SQLite是非常流行的嵌入式关系型数据库,轻载, 速度快,而且是开源.在Android中,runtime提供SQLite,所以我们可以使用SQLite,而且是 ...
- 【Lucene3.6.2入门系列】第03节_简述Lucene中常见的搜索功能
package com.jadyer.lucene; import java.io.File; import java.io.IOException; import java.text.SimpleD ...
随机推荐
- POJ 3436 ACM Computer Factory(最大流+路径输出)
http://poj.org/problem?id=3436 题意: 每台计算机包含P个部件,当所有这些部件都准备齐全后,计算机就组装完成了.计算机的生产过程通过N台不同的机器来完成,每台机器用它的性 ...
- POJ 2195 Going Home(费用流)
http://poj.org/problem?id=2195 题意: 在一个网格地图上,有n个小人和n栋房子.在每个时间单位内,每个小人可以往水平方向或垂直方向上移动一步,走到相邻的方格中.对每个小人 ...
- 2016"百度之星" - 初赛(Astar Round2B)1003 瞬间移动 组合数学+逆元
瞬间移动 Accepts: 1018 Submissions: 3620 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/ ...
- Java Spring-AOP的概述
2017-11-08 19:31:23 AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP ...
- tp5集成淘宝,微信,网易,新浪等第三方登录
tp5集成淘宝,微信,网易,新浪等第三方登录 一.总结 一句话总结: 接口 链接 实现的话就是这些平台给的一个接口(链接),你通过这些接口登录进去之后,它会给你返回用户名,头像之类的信息,我们的网站存 ...
- 2018-2019-2《网络对抗技术》Exp0 Kali安装 Week1
2018-2019-2<网络对抗技术>Exp0 Kali安装 Week1 Kali的安装 设置虚拟机的名称和操作系统 为虚拟机分配虚拟内存,大小为4096M,分配存储空间,大小为25.0G ...
- 获取iframe(angular 动态页面)高度
问题比较特殊,google了好久才得到启示 开发的angular页面,需要嵌入到客户的web页中,以iframe方式.由于iframe的高度需要指定,而angular动态生成机制导致页面高度会随时变化 ...
- UVALive-2966 King's Quest(强连通+二分图匹配)
题目大意:有n个男孩和和n个女孩,已只每个男孩喜欢的女孩.一个男孩只能娶一个女孩.一个女孩只能嫁一个男孩并且男孩只娶自己喜欢的女孩,现在已知一种他们的结婚方案,现在要求找出每个男孩可以娶的女孩(娶完之 ...
- python学习笔记(五)---sublime text 多行代码注释快捷键
转载网址:https://blog.csdn.net/mycms5/article/details/70194045/ 多行选择后按下ctrl+/ 选择类 Ctrl+D 选中光标所占的文本,继续操作则 ...
- activity+fragment+listview+adapter+bean在同一个类中的套路
1.xml activity_main.xml <?xml version="1.0" encoding="utf-8"?><FrameLay ...