您的位置:首页 > 其它

Lucene实现自定义中文同义词分词器

2015-04-08 10:08 549 查看
----------------------------------------------------------

lucene的分词_中文分词介绍

----------------------------------------------------------

Paoding:庖丁解牛分词器。已经没有更新了

mmseg:使用搜狗的词库

1.导入包(有两个包:1.带dic的,2.不带dic的)

如果使用不带dic的,得自己指定词库位置

2.创建MMSegAnalyzer(指明词库所在的位置)

----------------------------------------------------------

lucene的分词_实现自定义同义词分词器_思路分析(analyzer---->TokenStream ---> TokenFilter --->Tokenizer)与得到分词器详细信息的构造顺序相反

----------------------------------------------------------

/*
* 实现自定义中文同义词分词器(mmseg词库)
*/
public class MySameAnalyzer extends Analyzer {
@Override
public TokenStream tokenStream(String fieldName, Reader read) {
Dictionary dic = Dictionary
.getInstance("F:\\BaiduYunDownload\\Cache\\lucune\\chinesedic");
return new MySameTokenFilter(new MMSegTokenizer(new MaxWordSeg(dic), read));
}
}


---------------------------------------------------------

lucene的分词_实现自定义同义词分词器_实现分词器

---------------------------------------------------------

Reader ---->MMSegTokenizer(进行分词)---->(添加同义词)MySameTokenFilter(自定义分词器)---->获取同义词(在相同的位置存储同义词)

--->发现同义词--->保存当前状态--->跳到下一个元素--->根据同义词列表来存储元素--->还原状态--->在同一位置保存元素

/*
* 自定义同义词分词过滤器
*/
public class MySameTokenFilter extends TokenFilter {
// 存储分词数据
private CharTermAttribute cta = null;
// 存储语汇单元的位置信息
private PositionIncrementAttribute pia = null;
// 添加是否有同义词的判断变量属性,保存当前元素的状态信息
private AttributeSource.State current;
// 栈存储
private Stack<String> sames = null;

protected MySameTokenFilter(TokenStream input) {
super(input);
cta = this.addAttribute(CharTermAttribute.class);
pia = this.addAttribute(PositionIncrementAttribute.class);
sames = new Stack<String>();
}

@Override
public boolean incrementToken() throws IOException {

// 保存上一个语汇的同义词
while (sames.size() > 0) {
// 出栈,并获取同义词
String str = sames.pop();
// 还原上一个语汇的状态
restoreState(current);
// 在上一个语汇上保存元素
cta.setEmpty();
cta.append(str);
// 设置同义词位置为0
pia.setPositionIncrement(0);
return true;
}
// 跳到下个cta
if (!this.input.incrementToken())
// 没有元素返回false
return false;

if (getSameWords(cta.toString())) {
// 如果有同义词,改变词汇的current状态信息,把当前状态保存(捕获当前状态)
current = captureState();
}
return true;
}
/*
*
* 获取同义词
*/
private Boolean getSameWords(String name) {
Map<String, String[]> maps = new HashMap<String, String[]>();
maps.put("我", new String[] { "俺", "咱" });
maps.put("湖南", new String[] { "鱼米之乡", "湘" });
String[] sws = maps.get(name);
if (sws != null) {
// 添加进栈中
for (String str : sws) {
sames.push(str);
}
return true;
}
return false;
}
}


----------------------------------------------------

lucene的分词_实现自定义同义词分词器_实现分词器(良好设计方案)

----------------------------------------------------

思路:针对接口编程才是王道

1.创建管理同义词的接口

/*
* 用于存储同义词的接口
*/
public interface MySameContxt {
//获取同义词String[]
public String[] getSameWords(String name);
}


2.实现接口,添加同义词库

public class MySimpleSameContxt implements MySameContxt {
/*
* 实现同义词接口
*/
Map<String, String[]> maps = new HashMap<String, String[]>();

public MySimpleSameContxt() {
maps.put("我", new String[] { "俺", "咱" });
maps.put("湖南", new String[] { "鱼米之乡", "湘" });
}

public String[] getSameWords(String name) {
return maps.get(name);
}
}


3.自定义的分词器的过滤器中TokenFilter中添加同义词属性

// 获取专门管理同义词的库

private MySameContxt sameContxt;

全代码

/*
* 自定义同义词分词过滤器
*/
public class MySameTokenFilter extends TokenFilter {
// 存储分词数据
private CharTermAttribute cta = null;
// 存储语汇单元的位置信息
private PositionIncrementAttribute pia = null;
// 添加是否有同义词的判断变量属性,保存当前元素的状态信息
private AttributeSource.State current;
// 栈存储
private Stack<String> sames = null;
// 获取专门管理同义词的库
private MySameContxt sameContxt;

protected MySameTokenFilter(TokenStream input, MySameContxt sameContxt) {
super(input);
cta = this.addAttribute(CharTermAttribute.class);
pia = this.addAttribute(PositionIncrementAttribute.class);
sames = new Stack<String>();
this.sameContxt = sameContxt;
}

@Override
public boolean incrementToken() throws IOException {

// 保存上一个语汇的同义词
while (sames.size() > 0) {
// 出栈,并获取同义词
String str = sames.pop();
// 还原上一个语汇的状态
restoreState(current);
// 在上一个语汇上保存元素
cta.setEmpty();
cta.append(str);
// 设置同义词位置为0
pia.setPositionIncrement(0);
return true;
}

// 跳到下个cta
if (!this.input.incrementToken())
// 没有元素返回false
return false;

if (getSameWords(cta.toString())) {
// 如果有同义词,改变词汇的current状态信息,把当前状态保存(捕获当前状态)
current = captureState();
}
return true;
}

/*
*
* 获取同义词
*/
private Boolean getSameWords(String name) {
// 通过接口sameContxt获取同义词的所有String[]
String[] sws = sameContxt.getSameWords(name);
if (sws != null) {
// 添加进栈中
for (String str : sws) {
sames.push(str);
}
return true;
}
return false;
}
}

4.实现TokenStream
/*
* 实现自定义中文同义词分词器(mmseg词库)
*/
public class MySameAnalyzer extends Analyzer {
// 添加同义词词库
private MySameContxt sameContxt;

public MySameAnalyzer(MySameContxt msc) {
this.sameContxt = msc;
}

@Override
public TokenStream tokenStream(String fieldName, Reader read) {
// z最后传递的是自定义的同义词库管理类
Dictionary dic = Dictionary
.getInstance("F:\\BaiduYunDownload\\Cache\\lucune\\chinesedic");
return new MySameTokenFilter(new MMSegTokenizer(new MaxWordSeg(dic),
read), sameContxt);
}
}


5.编写索引测试

public void test05() {
try {
//将同义词词库作为分词器Analyzer的属性获取TokenStream
Analyzer a1 = new MySameAnalyzer(new MySimpleSameContxt());
String txt = "我来自湖南邵阳";
// 创建索引
Directory dir = new RAMDirectory();
IndexWriter writer = new IndexWriter(dir, new IndexWriterConfig(
Version.LUCENE_35, a1));
Document doc = new Document();
doc.add(new Field("content", txt, Field.Store.YES,
Field.Index.ANALYZED));
writer.addDocument(doc);
writer.close();

// 创建搜索
IndexReader reader = IndexReader.open(dir);
IndexSearcher search = new IndexSearcher(reader);
TopDocs tds = search.search(new TermQuery(new Term("content",
"鱼米之乡")), 10);
for (ScoreDoc sdc : tds.scoreDocs) {
Document docc = search.doc(sdc.doc);
System.out.println(docc.get("content"));
}

// new AnalyzerUtils().displayToken(txt, a1);
} catch (CorruptIndexException e) {
e.printStackTrace();
} catch (LockObtainFailedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: