ElasticStack系列之七 & IK自動熱更新原理與實現


一、熱更新原理

  elasticsearch開啟加載外部詞典功功能后,會每60s間隔進行刷新字典。具體原理代碼如下所示:

public void loadDic(HttpServletRequest req,HttpServletResponse response){
    String eTag =req.getParameter("If-None-Match");
    try {
        OutputStream out= response.getOutputStream();
        List<String> list=new ArrayList<String>();
        list.add("中華人民共和國");
        list.add("我愛你愛我");
        String oldEtag = list.size() + "";
        StringBuffer sb=new StringBuffer();
        if (oldEtag != eTag) {
            for (String str : list) {
                if(StringUtils.isNotBlank(str)){
                    sb.append("\r\n");
                }
                sb.append(str+"\r\n");
            }
        }
        String data=sb.toString();

        response.setHeader("Last-Modified", String.valueOf(list.size()));
        response.setHeader("ETag",String.valueOf(list.size()));
        response.setContentType("text/plain; charset=gbk");
        out.write(data.getBytes());
        out.flush();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

二、配置說明

  我們公司以及用戶常用的分詞器為 IK 分詞器,其中它有一個對應的核心配置文件名為:IKAnalyzer.cfg.xml,具體內容:

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">  
<properties>  
    <comment>IK Analyzer 擴展配置</comment>  
    <!--用戶可以在這里配置自己的擴展字典 -->  
    <entry key="ext_dict">custom/mydict.dic;custom/single_word_low_freq.dic</entry>  
     <!--用戶可以在這里配置自己的擴展停止詞字典-->  
    <entry key="ext_stopwords">custom/ext_stopword.dic</entry>  
    <!--用戶可以在這里配置遠程擴展字典 -->  
    <entry key="remote_ext_dict">location</entry>  
    <!--用戶可以在這里配置遠程擴展停止詞字典-->  
    <entry key="remote_ext_stopwords">http://xxx.com/xxx.dic</entry>  
</properties>

  熱更新 IK 分詞使用方法,目前該插件支持熱更新 IK 分詞,通過上文在 IK 配置文件中提到的如下配置

<!--用戶可以在這里配置遠程擴展字典 -->  
<entry key="remote_ext_dict">location</entry>  
<!--用戶可以在這里配置遠程擴展停止詞字典-->  
<entry key="remote_ext_stopwords">location</entry> 

  其中 location 是指一個 url,比如 http://yoursite.com/getCustomDict,該請求只需滿足以下兩點即可完成分詞熱更新。
  該 http 請求需要返回兩個頭部(header)

  1. 一個是 Last-Modified,

  2. 一個是 ETag

  這兩者都是字符串類型,只要有一個發生變化,該插件就會去抓取新的分詞進而更新詞庫。
  該 http 請求返回的內容格式是一行一個分詞,換行符用 \n 即可。

  滿足上面兩點要求就可以實現熱更新分詞了,不需要重啟 ES 實例。還需要注意的是獲取詞典的url,必須支持head訪問

下面自己做的訪問遠程擴展詞典的web api 服務接口(這一步可以直接忽略,看第三個即可,這里只是想說明也可以使用下面這種方式)

[HttpHead, HttpGet, HttpPost]  
public async Task<HttpResponseMessage> GetDictionary(string path)  
{  
    var response = this.Request.CreateResponse(HttpStatusCode.OK);  
    var content = File.ReadAllText(path);  
    response.Content = new StringContent(content, Encoding.UTF8);  
    response.Headers.Age = TimeSpan.FromHours(1);  
    response.Headers.ETag = EntityTagHeaderValue.Parse($"\"{content.ToMD5()}\"");  
    return response;  
}

三、Tomcat 服務器自動更新

 1、部署http服務

  在這使用 tomcat8 作為 web 容器,先下載一個 tomcat8.5.16,然后上傳到某一台服務器上(192.168.80.100)。

  再執行以下命令

tar -zxvf apache-tomcat-8.5.16.tar.gz
cd apache-tomcat-8.5.16/webapp/ROOT
vim hot_ext.dic
智能移動機器人
vim hot_stopwords.dic
項目

  之后驗證一下這個文件是否可以正常訪問   http://192.168.80.100:8080/hot.dic

  2、修改ik插件的配置文件

  修改 IK 核心配置文件 IKAnalyzer.cfg.xml 中的配置

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">  
<properties>  
    <comment>IK Analyzer 擴展配置</comment>  
    <!--用戶可以在這里配置自己的擴展字典 -->  
    <entry key="ext_dict">custom/mydict.dic;custom/single_word_low_freq.dic</entry>  
     <!--用戶可以在這里配置自己的擴展停止詞字典-->  
    <entry key="ext_stopwords">custom/ext_stopword.dic</entry>  
    <!--用戶可以在這里配置遠程擴展字典 -->  
    <entry key="remote_ext_dict">http://192.168.80.100:8080/hot_ext.dic</entry>  
    <!--用戶可以在這里配置遠程擴展停止詞字典-->  
    <entry key="remote_ext_stopwords">http://192.168.80.100:8080/hot_stopwords.dic</entry>  
</properties>

 3、驗證

  重啟es,會看到如下日志信息,說明遠程的詞典加載成功了。

  

  在瀏覽器中輸入如下命令:http://localhost:9200/patent/_analyze?analyzer=ik_smart&text=智能移動機器人

  正常情況下會分出很多次,這次發現只有這一個詞,不會被分詞,說明剛才配置遠程的詞庫生效了,那么我們再換一個:北京霧霾,正常情況下可能會被分成兩個詞:北京、霧霾,如果我直接修改 tomcat 下的 hot_ext.dic 詞庫文件,增加一個關鍵詞:北京霧霾,文件保存之后,查看es的日志會看到如下日志信息:

  

  此時,再執行下面命令查看分詞效果:http://localhost:9200/patent/_analyze?analyzer=ik_smart&text=北京霧霾

  結果就是只有一個詞,不會被分詞了。

  到這為止,可以實現動態添加自定義詞庫實現詞庫熱更新。~~

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM