ik分詞熱更新失敗的問題

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....

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章