ik分词热更新失败的问题

原创
2021/11/23 14:25
阅读数 1.4K

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

展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部