IKAnalyzer如何自定義遠端詞庫
IKAnalyzer1.3.4要自定義我們自己的詞庫,而且我們可以隨時新增分詞,網上查了一圈沒有相關資料,看來只有自己搞定了。這裡大家需要熟悉HTTP協議中的Last-Modified、ETags這些概念,這樣能更容易理解IKAnalyzer作者的設計思路。
觀察了下IKAnalyzer分詞器的配置檔案IKAnalyzer.cfg.xml發現其中有這樣一個選項:
<!--使用者可以在這裡配置遠端擴充套件字典 --><entry key="remote_ext_dict"><entry>,而且作者做了註釋說這個就是擴充套件遠端詞典的。於是開啟IKAnalyzer的原始碼檢視,最後在Dictronary這類下找到這個方法:getRemoteWords。經過檢視發現其實用的是HttpClient去獲取分詞。於是我就用SpringMVC寫了個Controller來解決。這裡要注意:每個分詞之間要使用換行符即“\r\n”來分割,貌似問題圓滿解決,
可是,我發現IKAnalyzer的這個獲取分詞的動作只是在啟動的時候去訪問我寫的Controller。很顯然這是不行的,這就違背了我隨時新增分詞的願望了,看來我要擴充套件這個分詞器了。於是我開始從頭翻這個開源分詞器的原始碼,我在Dictronary最後找到以下的程式碼,頓時讓我眼前一亮:
public void reLoadMainDict(){
logger.info("重新載入詞典...");
loadMainDict();
loadStopWordDict();
}
顧名思義,這個是過載分詞的。於是我問自己,什麼時候過載?如何過載?於是我搜了下,最後再Monitor這個類下找到run這個方法,這是Monitor實現Runnable介面的,在這個方法裡這個分詞器先去構造httphead,並且帶上If-None-Match、If-Modified-Since這倆引數去訪問Controller(關於這倆引數的概念,大家可以上網查),然後根據返回來的response的head裡的Last-Modified和ETags來和Monitor快取的變數進行比較,如果任何一個不相同就需要重新訪問Controller中去獲取資料,說到這裡可以總下:可以在服務端(Controller)中設定這倆變數,來控制IKAnalyzer是否重新載入分詞。OK,分析到這裡問題解決了。最後我寫的Controller中程式碼大概如下:
/**
* 獲取分詞
* @return
*/
@RequestMapping("getDict")
@ResponseBody
public String getDict(HttpServletRequest request, HttpServletResponse response) {
String result = "";
StringBuilder sb = new StringBuilder();
List<Word> wordList = wordService.selectAllWord();//獲取所有分詞,這裡可以改進使用快取等。
String eTag = request.getHeader("If-None-Match");
Long modified= request.getDateHeader("If-Modified-Since");
//設定頭
if(null == modified || -1 == modified) {
//如果沒有,則使用當前時間
modified = System.currentTimeMillis();
}
/ /設定頭資訊。
String oldEtag = wordList.size() + "";
response.setDateHeader("Last-Modified", Long.valueOf(modified));
response.setHeader("ETags", wordList.size() + "");
if(!oldEtag.equals(eTag)) {
//拼裝結果
for(Word tempWord : wordList) {
//分詞之間以換行符連線
if(StringUtils.isNotEmpty(sb.toString())) {
sb.append("\r\n");
}
sb.append(tempWord.getValue());
}
result = sb.toString();
//更新時間
response.setDateHeader("Last-Modified", System.currentTimeMillis());
}
return result;
}
這裡還可以再優化,這是後話了,有了這個思路其餘的都是錦上添花。