ES 7.7.0 版本
ik分詞字典更新,按照官方文檔,採用本地詞庫+熱更新方式
<?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">my_stars__sogou.dic;my_luxury_sogou.dic;</entry>
<!--用戶可以在這裏配置自己的擴展停止詞字典-->
<entry key="ext_stopwords"></entry>
<!--用戶可以在這裏配置遠程擴展字典 -->
<entry key="remote_ext_dict">http://192.168.0.200:8085/ik/customerDict.txt</entry>
<!--用戶可以在這裏配置遠程擴展停止詞字典-->
<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>
配置中的兩個dic文件,是從sogou拼音官方下載的兩個詞庫,然後使用"深藍詞庫轉換 imewlconverter"轉換成純文本文件。
熱更新文件customerDict.txt
中每行一個詞,以換行符\n
結尾。
測試的時候遇到一個奇怪的問題,達到108行的時候,就會更新失敗。log中顯示如下:
[2021-11-23T03:58:58,578][WARN ][stderr ] [ubuntuaben1] Nov 23, 2021 3:58:58 AM org.apache.http.impl.execchain.RetryExec execute
[2021-11-23T03:58:58,578][WARN ][stderr ] [ubuntuaben1] INFO: I/O exception (org.apache.http.NoHttpResponseException) caught when processing request to {}->http://192.168.0.200:8085: The target server failed to respond
[2021-11-23T03:58:58,578][WARN ][stderr ] [ubuntuaben1] Nov 23, 2021 3:58:58 AM org.apache.http.impl.execchain.RetryExec execute
[2021-11-23T03:58:58,578][WARN ][stderr ] [ubuntuaben1] INFO: Retrying request to {}->http://192.168.0.200:8085
[2021-11-23T05:31:49,175][WARN ][stderr ] [ubuntuaben1] Nov 23, 2021 5:31:49 AM org.apache.http.impl.execchain.RetryExec execute
[2021-11-23T05:31:49,175][WARN ][stderr ] [ubuntuaben1] INFO: I/O exception (java.net.SocketException) caught when processing request to {}->http://192.168.0.200:8085: Connection reset
熱更新的服務是放在nginx下的。正常情況下, 請求返回的header是:
Accept-Ranges: bytes
Content-Length: 992
Content-Type: text/plain; charset=utf-8
Date: Tue, 23 Nov 2021 05:41:40 GMT
ETag: "619c66ae-3e0"
Last-Modified: Tue, 23 Nov 2021 03:57:34 GMT
Server: nginx
異常時, 返回的是:
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/plain; charset=utf-8
Date: Tue, 23 Nov 2021 05:42:19 GMT
ETag: W/"619c7f33-413"
Last-Modified: Tue, 23 Nov 2021 05:42:11 GMT
Server: nginx
Transfer-Encoding: chunked
Vary: Accept-Encoding
so, 很明顯了, 這是nginx啓用了gzip壓縮導致的,而ik
7.7.0版本的插件尚不支持gzip。
要麼在nginx中關閉gzip, 但是nginx不支持指定站點設置gzip off
,蛋疼ing....
看來就剩一條路了:改源碼,使其支持gzip
網上有改源碼,直接去連接mysql
經過測試, ES7.15.2中已經解決了此問題, 下圖是插件主要修改的地方
值得注意的是,在數據沒有變更(就是返回304狀態,可以從nginx的access日誌中看到)時,ES7.7版本的ik也是會出現前面的異常,目前測試來看只是請求的間隔時間從1分鐘延長到了2分鐘,7分鐘,2分鐘。。。。。
舊版本的問題歸結爲2個:
- 服務端啓用了gzip的問題
- 服務端返回304的問題
新版本7.15.2
也還是有304
的問題.
但是在源碼src\main\java\org\wltea\analyzer\dic\Monitor.java
的方法runUnprivileged
中有做了處理啊:
/**
* 監控流程:
* ①向詞庫服務器發送Head請求
* ②從響應中獲取Last-Modify、ETags字段值,判斷是否變化
* ③如果未變化,休眠1min,返回第①步
* ④如果有變化,重新加載詞典
* ⑤休眠1min,返回第①步
*/
public void runUnprivileged() {
//超時設置
RequestConfig rc = RequestConfig.custom().setConnectionRequestTimeout(10*1000)
.setConnectTimeout(10*1000).setSocketTimeout(15*1000).build();
HttpHead head = new HttpHead(location);
head.setConfig(rc);
//設置請求頭
if (last_modified != null) {
head.setHeader("If-Modified-Since", last_modified);
}
if (eTags != null) {
head.setHeader("If-None-Match", eTags);
}
CloseableHttpResponse response = null;
try {
response = httpclient.execute(head);
//返回200 才做操作
if(response.getStatusLine().getStatusCode()==200){
if (((response.getLastHeader("Last-Modified")!=null) && !response.getLastHeader("Last-Modified").getValue().equalsIgnoreCase(last_modified))
||((response.getLastHeader("ETag")!=null) && !response.getLastHeader("ETag").getValue().equalsIgnoreCase(eTags))) {
// 遠程詞庫有更新,需要重新加載詞典,並修改last_modified,eTags
Dictionary.getSingleton().reLoadMainDict();
last_modified = response.getLastHeader("Last-Modified")==null?null:response.getLastHeader("Last-Modified").getValue();
eTags = response.getLastHeader("ETag")==null?null:response.getLastHeader("ETag").getValue();
}
}else if (response.getStatusLine().getStatusCode()==304) {
//沒有修改,不做操作
//noop
}else{
logger.info("remote_ext_dict {} return bad code {}" , location , response.getStatusLine().getStatusCode() );
}
} catch (Exception e) {
logger.error("remote_ext_dict {} error!",e , location);
}finally{
try {
if (response != null) {
response.close();
}
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
}
TODO....