当初的产品需求是根据后台新增的扩展词及停止词三天更新到ik中,由于ik-analyzer,是一次加载所有类及配置文件的,所以解决这个问题的第一思路就是在类的初始化方法中写一个定时调度,每三天去读取数据库中扩展次及停止词。
由于小弟我也是刚刚接到需求后才开始看的ik-analyzer分词器,所以有很多不懂的地方如有大神刚好看见有其他更好的方式来解决这样的问题欢迎留言。
实体类:
public class DictionaryParticiple implements Serializable {
/**
* 主键
*/
private Long id;
/**
* 词典
*/
private String word;
/**
* 词汇类型
*/
private Byte type;
/**
* 创建时间
*/
private Date createTime;
/**
* 操作人
*/
private String optUser;
public DictionaryParticiple(Long id, String word, Byte type, Date createTime, String optUser) {
this.id = id;
this.word = word;
this.type = type;
this.createTime = createTime;
this.optUser = optUser;
}
public DictionaryParticiple() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getWord() {
return word;
}
public void setWord(String word) {
this.word = word;
}
public Byte getType() {
return type;
}
public void setType(Byte type) {
this.type = type;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public String getOptUser() {
return optUser;
}
public void setOptUser(String optUser) {
this.optUser = optUser;
}
@Override
public String toString() {
return "DictionaryParticiple{" +
"id=" + id +
", word='" + word + '\'' +
", type=" + type +
", createTime=" + createTime +
", optUser='" + optUser + '\'' +
'}';
}
}
初始化:
/**
* 词典初始化
* 由于IK Analyzer的词典采用Dictionary类的静态方法进行词典初始化
* 只有当Dictionary类被实际调用时,才会开始载入词典,
* 这将延长首次分词操作的时间
* 该方法提供了一个在应用加载阶段就初始化字典的手段
* @return DictionaryParticiple
*/
public static Dictionary initial(Configuration cfg){
if(singleton == null){
synchronized(Dictionary.class){
if(singleton == null){
singleton = new Dictionary(cfg);
singleton.loadMainDict();
Dictionary.addExtensionWord();
return singleton;
}
}
}
return singleton;
}
定时调度获取数据库数据:
/**
* 定时调度查询数据库
* 查询黑白名单实现Runnable接口
* 0 (延迟)
* (间隔时间)
* TimeUnit.SECONDS (计时单位秒)
*/
public static void addExtensionWord(){
ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);
pool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
DictionaryParticipleService dictionaryParticipleService = new DictionaryParticipleService();
String currentTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
logger.info("本次调度时间为:"+currentTime+",三天后再次加载。");
_StopWordDict = new DictSegment((char)0);
List<DictionaryParticiple> list = dictionaryParticipleService.selectDictionary();
for (DictionaryParticiple dictionaryParticiple : list) {
if (dictionaryParticiple.getType() == 1) {
String mainDictWord = dictionaryParticiple.getWord();
singleton._MainDict.fillSegment(mainDictWord.trim().toCharArray());
logger.info(mainDictWord);
}else {
String stopWordDict = dictionaryParticiple.getWord();
logger.info(stopWordDict);
_StopWordDict.fillSegment(stopWordDict.trim().toCharArray());
}
}
}
}, 0, ONEDAY_SECOND*3, TimeUnit.SECONDS);
}
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
源码中是有已存在的配置文件也就是扩展次与停用词(ext.dic,stopword.dic),那么当在数据库加载到内存的时候,存储扩展次与停用词的对象必须得用同一个,不然只会加载最后存储的对象,也算是个小细节吧。
其中
dictionaryParticipleService.selectDictionary();为jdbc查询数据库方法也就是查扩展次及停止词,将查询出的结果放到
singleton._MainDict.fillSegment(mainDictWord.trim().toCharArray());与
_StopWordDict.fillSegment(stopWordDict.trim().toCharArray());里面,
ScheduledExecutorService类在这里使用的是创建一个线程的线程池,网上有很多大神的解释我就不在露怯了。