Lucene实现自定义中文同义词分词器
----------------------------------------------------------
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(); } }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。