lucene3.5实现自定义同义词分词器
来源:互联网 发布:淘宝宝贝图片尺寸用750 编辑:程序博客网 时间:2024/05/29 02:52
最近一直在学Lucene3.5,感觉里面的知识真的很棒。今天就和大家一起分享一下我们自己来实现一个同义词的分词器。
一个分词器由多个Tokenizer和TokenFilter组成,这篇文章讲解的就是我们利用这两个特性实现自己的一个简单的同义词分词器,不妥之处请大家指出。
一、设计思路
什么叫同义词搜索呢?比如我们在搜 ”中国“ 这个词的时候,我们也可以搜索 ”大陆“ 这个词,后者搜索的要包含 ”中国“ 这个单词的文章, 前者搜索的要包含 ”大陆“ 这个单词的文章。这里我们就必须要了解Lucene是怎么处理我们的文档了,首先我们得了解这3个类:
PositionIncrementAttribute (位置增量的属性,存储语汇单元之间的距离)
OffsetAttribute (每个语汇单元的位置偏移量)
CharTermAttribute (存储每一个语汇单元的信息,即分词单元信息)
如图:
这些东西都有一个叫做AttributeSource的类决定,这个类中保存了这些信息。里面有一个叫做STATE的静态内部类。我们在以后的过程中可以用下面这个方法捕获当前状态。
/** * Captures the state of all Attributes. The return value can be passed to * {@link #restoreState} to restore the state of this or another AttributeSource. */ public State captureState() { final State state = this.getCurrentState(); return (state == null) ? null : (State) state.clone(); }Lucene通过位置增量来判断位置,那么我们只要在相应的位置加上自己的同义词就ok了。
二、实现
1、首先我们定义一个同义词的接口(为了提高我们程序的扩展性)
package com.dhb.util;public interface SamewordContext {public String[] getSamewords(String name);}
2、我们继承这个接口(把同义词放进我们的Map)
package com.dhb.util;import java.util.HashMap;import java.util.Map;public class SimpleSamewordContext implements SamewordContext {Map<String , String[]> maps = new HashMap<String, String[]>();public SimpleSamewordContext() {maps.put("中国", new String[] {"天朝", "大陆"});maps.put("我", new String[] {"俺", "咱"});}@Overridepublic String[] getSamewords(String name) {return maps.get(name);}}
package com.dhb.util;import java.io.Reader;import org.apache.lucene.analysis.Analyzer;import org.apache.lucene.analysis.TokenStream;import com.chenlb.mmseg4j.Dictionary;import com.chenlb.mmseg4j.MaxWordSeg;import com.chenlb.mmseg4j.analysis.MMSegTokenizer;public class MySameAnalyzer extends Analyzer {private SamewordContext samewordContext;public MySameAnalyzer(SamewordContext samewordContext) {this.samewordContext = samewordContext;}@Overridepublic TokenStream tokenStream(String fieldName, Reader reader) {Dictionary dic = Dictionary.getInstance("F:\\邓海波jar\\mmseg4j\\mmseg4j-1.8.5\\data");return new MySameTokenFilter(new MMSegTokenizer(new MaxWordSeg(dic), reader), samewordContext);}}
4、看我们的filter,主要看注释,关键都在注释里面
package com.dhb.util;import java.io.IOException;import java.util.HashMap;import java.util.Map;import java.util.Stack;import org.apache.lucene.analysis.TokenFilter;import org.apache.lucene.analysis.TokenStream;import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute;import org.apache.lucene.util.AttributeSource;public class MySameTokenFilter extends TokenFilter {private CharTermAttribute cta = null;private PositionIncrementAttribute pia = null;private AttributeSource.State current;private Stack<String> sames = null;private SamewordContext samewordContext;protected MySameTokenFilter(TokenStream input, SamewordContext samewordContext) {super(input);cta = this.addAttribute(CharTermAttribute.class);pia = this.addAttribute(PositionIncrementAttribute.class);sames = new Stack<String>();this.samewordContext = samewordContext;}@Overridepublic boolean incrementToken() throws IOException {//System.out.println(cta);/*if(cta.toString().equals("中国")) {cta.setEmpty();cta.append("大陆");}*/while(sames.size() > 0) {// 将元素出栈,并且获取这个同义词String str = sames.pop();// 还原状态restoreState(current);//System.out.println("--------"+cta);cta.setEmpty();cta.append(str);//设置位置0pia.setPositionIncrement(0);return true; // 如果不返回true,会把之前的覆盖掉}if(!input.incrementToken()) return false; // 不能放在开头,放在这里是因为不会把之前的给覆盖掉if(addSames(cta.toString())) { //getSameWords改成addSames//如果捕获到有同义词,则将当前状态先保存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 s : sws) {sames.push(s);}return true;}return false;}*/private boolean addSames(String name) {String[] sws = samewordContext.getSamewords(name);if(sws != null) {for(String s : sws) {sames.push(s);}return true;}return false;}}
5、最后我们的测试工具类里的一个方法
@Test public void test06() {Analyzer a = new MySameAnalyzer(new SimpleSamewordContext());String txt = "我来自中国重庆南岸区崇文路2号重庆邮电大学";Directory dir =new RAMDirectory();try {IndexWriter writer = new IndexWriter(dir, new IndexWriterConfig(Version.LUCENE_35, a));Document doc = new Document();doc.add(new Field("content", txt, Field.Store.YES, Field.Index.ANALYZED));writer.addDocument(doc);writer.close();IndexSearcher searcher = new IndexSearcher(IndexReader.open(dir));//搜大陆或者中国都可以搜到TopDocs tds = searcher.search(new TermQuery(new Term("content", "大陆")), 10);Document d =searcher.doc(tds.scoreDocs[0].doc);System.out.println(d.get("content"));} catch (CorruptIndexException e) {e.printStackTrace();} catch (LockObtainFailedException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}
这是一个位置信息:
1:我[0-1]-->word0:咱[0-1]-->word0:俺[0-1]-->word1:来自[1-3]-->word1:中国[3-5]-->word0:大陆[3-5]-->word0:天朝[3-5]-->word1:重庆[5-7]-->word1:南岸[7-9]-->word1:区[9-10]-->word1:崇文[10-12]-->word1:路[12-13]-->word1:2[13-14]-->digit1:号[14-15]-->word1:重庆[15-17]-->word1:邮电[17-19]-->word1:电大[18-20]-->word1:大学[19-21]-->word
有没有发现,同义词已经加进去了,而且他们的偏移量和位置增量都是一样的,然后我们搜索【】的时候就可以把这篇文档搜索出来了。
这是我的思路图:
0 0
- lucene3.5实现自定义同义词分词器
- Lucene实现自定义中文同义词分词器
- 【Lucene3.6.2入门系列】第05节_自定义停用词分词器和同义词分词器
- 【Lucene3.6.2入门系列】第05节_自定义停用词分词器和同义词分词器
- Lucene自定义同义词分词器
- MMSegAnalyzer 自定义 同义词分词器
- Lucene实现自定义分词器(同义词查询与高亮)
- Lucene 5.3 自定义同义词分词器
- 自定义lucene的同义词分词器
- 三、lucene3.5的分词语法[停用词扩展、同义词搜索等]
- Lucene同义词分词器简单实现
- lucene3 分词器的使用
- Lucene3 分词
- Lucene 3.6.2入门:自定义停用词分词器和同义词分词器
- Lucene5中编写自定义同义词分词器(基于IK中文分词器)
- Lucene5中编写自定义同义词分词器(基于IK中文分词器)二
- lucene构建同义词分词器
- mmseg 分词器 同义词总结
- iOS开发-比较好的文章和资源链接
- MessageFormat.Format的用法,亲测好使!
- 教你怎么分割PDF文档
- NGUI中的DrawCalls数量
- 推动共建丝绸之路经济带和21世纪海上丝绸之路的愿景与行动
- lucene3.5实现自定义同义词分词器
- BZOJ 1142 POI2009 Tab Hash
- Linux 内核资源
- 外部程序调用四五打印乱码
- c++非公有虚函数探究
- sql之left join、right join、inner join的区别
- Xcode6中将productName修改成中文后不能真机调试
- android 双击返回键退出 拦截menu键
- python Wing IDE编辑器的中文显示解决方法