1. 程式人生 > >IKAnalyzer如何自定義遠端詞庫

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;
}

       這裡還可以再優化,這是後話了,有了這個思路其餘的都是錦上添花。