IKAnalyzer如何自定义远端词库

梁明辉
2023-12-01

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

       这里还可以再优化,这是后话了,有了这个思路其余的都是锦上添花。

 

 

http://blog.csdn.net/achilles12345/article/details/43056093

 类似资料: