链接:/portal/article/index/id/59.html
当前IKAnalyzer从发布最后一个版本后就一直没有再更新,使用过程中,经常遇到需要扩展词库以及动态更新字典表的问题,此处给出一种解决办法(注意:本方法中的IKAnalyzer代码我已经将源码移植到了自己的工程中,目录结构也进行了修改):
1、将扩展字典表做成可动态生成:
1)、在IKAnalyzer.cfg.xml中添加扩展字典路径
2)、在分词的时候,先采取动态生成上面两个字典表的方式进行更新,例如事先将字典词库放在数据表中,需要分词之前先更新字典。当然此方法只支持第一次调用的时候动态加载词库,如果服务没有重启之前,数据库中添加的词是不会进行重新加载的。下面是动态生成字典表的实现类:
packagecom.chz.apps.sm.IKAnalyzer;importjava.io.ByteArrayInputStream;importjava.io.IOException;importjava.io.InputStream;importjava.io.InputStreamReader;importjava.io.Reader;importjava.util.ArrayList;importjava.util.List;importcom.chz.apps.sm.model.IkanalyzerExtendModel;importcom.chz.base.util.FileUtil;importcom.chz.plugin.IKAnalyzer.core.IKSegmenter;importcom.chz.plugin.IKAnalyzer.core.Lexeme;/***@Description分词工具类*@authorgongstring<1@>*@createTime11月28日下午2:46:06*/publicclassIKAnalyzerTool{/***是否已经初始化过词库,如果没有,则会自动先调用词库*/privatestaticbooleaninit_words=false;/***扩展关键字*/privatestaticList<String>extendWords=newArrayList<String>();/***停用关键字*/privatestaticList<String>stopWords=newArrayList<String>();/***@Description初始化词库以及停用词*@authorgongstring<1@>*@createTime11月28日下午2:29:59*/publicstaticvoidinitWords(){//从关键字表中查询扩展关键字,并生成到指定文件中IKAnalyzerTool.extendWords=newArrayList<String>();List<IkanalyzerExtendModel>extendWords=IkanalyzerExtendModel.dao.findByProperty("status",1);StringfileDirPath=IKAnalyzerTool.class.getResource("/com/chz/apps/sm/IKAnalyzer/").getPath();StringfilePath=fileDirPath+"extend.dic";FileUtil.removeFile(filePath);//先删除文件,此处重新生成for(inti=0;i<extendWords.size();i++){Stringtxt=extendWords.get(i).getStr("extend_word");FileUtil.appendToFile(filePath,txt,true);IKAnalyzerTool.extendWords.add(txt);}//从关键字表中查询停用关键字,并生成到指定文件中IKAnalyzerTool.stopWords=newArrayList<String>();List<IkanalyzerExtendModel>stopWords=IkanalyzerExtendModel.dao.findByProperty("status",0);StringstopFilePath=fileDirPath+"stopword.dic";FileUtil.removeFile(stopFilePath);//先删除文件,此处重新生成for(inti=0;i<stopWords.size();i++){Stringtxt=stopWords.get(i).getStr("extend_word");FileUtil.appendToFile(stopFilePath,txt,true);IKAnalyzerTool.stopWords.add(txt);}init_words=true;}/***@Description分词操作*@authorgongstring<1@>*@createTime11月28日下午3:30:10*@paramstr*@paramjustExist是否只显示已经在词库中维护了的关键词*@return*/publicstaticList<String>IKAnalysis(Stringstr,booleanjustExist){List<String>tmp=IKAnalysis(str);List<String>result=newArrayList<String>();if(justExist){for(inti=0;i<tmp.size();i++){if(IKAnalyzerTool.extendWords.contains(tmp.get(i))){result.add(tmp.get(i));}}}else{result=tmp;}returnresult;}/***@Description根据字符串自动拆分成关键字集合*@authorgongstring<1@>*@createTime11月28日下午2:55:24*@paramstr*@return*/publicstaticList<String>IKAnalysis(Stringstr){if(!init_words){initWords();}List<String>result=newArrayList<String>();try{//InputStreamin=newFileInputStream(str);//byte[]bt=str.getBytes();//strInputStreamip=newByteArrayInputStream(bt);Readerread=newInputStreamReader(ip);IKSegmenteriks=newIKSegmenter(read,true);Lexemet;while((t=iks.next())!=null){result.add(t.getLexemeText());}}catch(IOExceptione){//TODOAuto-generatedcatchblocke.printStackTrace();}returnresult;}}
2、修改源码,实现动态更新字典表。通过查看源码IKAnalyzer.dic.Dictionary.java文件得出,字典对象是采取单例模式,也就是第一次加载后,后续不在重新加载,这样即使字典表内容变化,缓存中的字典库是不会变更的,所以需要修改源码,可以手动更新单例对象的内容,此处我采取添加clear方法,在需要更新时候调用,将instance对象设置为null,下次调用字典的时候,程序就会自动加载了
/***@Description清空字典缓存,用于动态更新字典表*@authorgongstring<1@>*@createTime11月29日上午9:56:15*/publicstaticvoidclear(){singleton=null;}
源码修改完后,可以选择编译重新打包,或者将jar包中的class文件删除,java类在工程中按照源目录存放。
3、手动调用,我这里是做的一个页面,点击更新字典库时,调用更新代码:
/***@Description刷新关键词缓存*@authorgongstring<1@>*@createTime11月29日上午9:33:49*/publicvoidrefreshCache(){IKAnalyzerTool.initWords();//重新加载词汇Dictionary.clear();//将字典表缓存清空this.renderSuccessJson(EnvConfig.APP_PATH+"/sm/ikanalyzerExtend");}
4、可能存在的性能问题:由于词库一般会比较大,所以每次大批量更新可能会出现性能损耗。。。