一、熱更新原理
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=北京霧霾
結果就是只有一個詞,不會被分詞了。
到這為止,可以實現動態添加自定義詞庫實現詞庫熱更新。~~