文章目录

  • 问题背景
    • 1.需求
    • 2. 使用tomcat提供一个接口
    • 3. 使用nginx代理文件
      • 3.1 nginx 配置
      • 3.2 ES配置
      • 3.3 增加词汇不生效
      • 3.4 修改nginx配置进行验证
    • 4.spring boot tomcat的设置

问题背景

1.需求

最近有一些需求导致我们需要扩充IK的词库,按照IK的官方走了一遍,这里是官方的一些介绍
IK热更新配置方式
我们的ES版本为7.1.1

2. 使用tomcat提供一个接口

按照文档在tomcat服务中提供一个接口,来将自定义的热词数据写出去,结果在es中不能成功加载这些数据。
项目是一个springboot项目,接口的代码如下

@RequestMapping(value = "/remoteExtDict/select", method = RequestMethod.GET)public void select(HttpServletResponse response) {List<String> resultList = remoteExtDictMapper.selectRemoteExtDict();StringBuilder result = new StringBuilder();for (String value : resultList){result.append(value+"\n");}result.delete(result.length()-1,result.length());try {Long time = remoteExtDictMapper.getMaxTime();response.setHeader("Last-Modified", time.toString());response.setHeader("ETag",time.toString());response.setContentType("text/plain; charset=utf-8");String test = "上海堡垒\n陈默涵\n天际漫谈\n大西瓜\n人生如梦\n快手";PrintWriter writer = response.getWriter();writer.write(test);writer.flush();} catch (IOException e) {log.error("自定义词典更新报错" , e);}}

在浏览器端和crul请求中返回的结果都比较正常,编码等都是正确设置了的。所以很是疑惑,如果使用es本地文件的方式添加热词是可以的。所以感觉应该是哪个环节有问题。
因为官方建议是使用nginx代理文件的方式,所以决定先用nginx来搞一下看看能不能正确使用,然后再进行对比。

3. 使用nginx代理文件

3.1 nginx 配置

cat server.confserver {listen 88;charset utf-8;location /analize/ {alias /home/deploy/search/log-search/analize_word/;access_log /data/nginx/log/analize_word.log api;}
}

对应的文件为 /home/deploy/search/log-search/analize_word/test.txt

cat /home/deploy/search/log-search/analize_word/test.txt
钟丽
陈港生

3.2 ES配置

cat elasticsearch-7.1.1/config/analysis-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"></entry><!--用户可以在这里配置自己的扩展停止词字典--><entry key="ext_stopwords"></entry><!--用户可以在这里配置远程扩展字典 --><entry key="remote_ext_dict">http://10.26.5.18:8090/search/manager/es/remoteExtDict/select</entry><!--用户可以在这里配置远程扩展停止词字典--><!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>

重启ES
在修改完后等了一会儿可以在es的日志中看到

[2019-08-15T17:57:51,001][INFO ][o.w.a.d.Monitor          ] [ES01] 重新加载词典...
[2019-08-15T17:57:51,002][INFO ][o.w.a.d.Monitor          ] [ES01] try load config from /home/deploy/search/log-search/elasticsearch-7.1.1/config/analysis-ik/IKAnalyzer.cfg.xml
[2019-08-15T17:29:51,083][INFO ][o.w.a.d.Monitor          ] [ES01] [Dict Loading] http://10.76.7.49:88/analize/test.txt
[2019-08-15T17:29:51,086][INFO ][o.w.a.d.Monitor          ] [ES01] 钟丽
[2019-08-15T17:29:51,086][INFO ][o.w.a.d.Monitor          ] [ES01] 陈港生
[2019-08-15T17:29:51,086][INFO ][o.w.a.d.Monitor          ] [ES01] 重新加载词典完毕...

说明确实成功了。

3.3 增加词汇不生效

接下来出现了比较诡异的东西。
当我再在文件中添加一个词的时候更新就无法成功了。

cat /home/deploy/search/log-search/analize_word/test.txt
钟丽
陈港生
陈默涵

对应的es的日志

[2019-08-15T17:57:51,001][INFO ][o.w.a.d.Monitor          ] [ES01] 重新加载词典...
[2019-08-15T17:57:51,002][INFO ][o.w.a.d.Monitor          ] [ES01] try load config from /home/deploy/search/log-search/elasticsearch-7.1.1/config/analysis-ik/IKAnalyzer.cfg.xml
[2019-08-15T17:57:51,092][INFO ][o.w.a.d.Monitor          ] [ES01] [Dict Loading] http://10.76.7.49:88/analize/test.txt
[2019-08-15T17:57:51,095][INFO ][o.w.a.d.Monitor          ] [ES01] 重新加载词典完毕...

反复试了几次都是这样,感觉很奇怪。冷静下来分析,应该是对数据长度的识别有问题。又去翻了翻IK上的issue。最后找到了这条
顿时觉得和我现在的状态十分的吻合。
简单描述一下,就是nginx默认会对响应进行压缩gzip和分片chuncked

进行验证,当文件中只有两个词,返回的response header是

HTTP/1.1 200 OK
Server: openresty
Date: Thu, 15 Aug 2019 09:49:11 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 17
Last-Modified: Thu, 15 Aug 2019 09:29:05 GMT
Connection: keep-alive
ETag: "5d5525e1-11"
Accept-Ranges: bytes

这里可以看到有Content-Length 这个header

当编程三个词的时候response header变成了这样

HTTP/1.1 200 OK
Server: openresty
Date: Thu, 15 Aug 2019 10:53:39 GMT
Content-Type: text/plain; charset=utf-8
Last-Modified: Thu, 15 Aug 2019 09:57:15 GMT
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
ETag: W/"5d552c7b-1b"
Content-Encoding: gzip

这里没有了Content-Length 这个header,
有了一个Transfer-Encoding:chunked 和一个Content-Encoding:gzip
这两个header是为了提升传输的效率和对内容进行压缩的。
IK插件可能是因为某种原因未对这中情况做支持,只有有Content-Length的时候才能正确的识别。

3.4 修改nginx配置进行验证

server {listen 88;charset utf-8;location /analize/ {alias /home/deploy/search/log-search/analize_word/;access_log /data/nginx/log/analize_word.log api;chunked_transfer_encoding       off;gzip off;}
}

这个时候再从浏览器请求,观察返回的header

HTTP/1.1 200 OK
Server: openresty
Date: Fri, 16 Aug 2019 03:26:59 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 27
Last-Modified: Thu, 15 Aug 2019 09:57:15 GMT
Connection: keep-alive
ETag: "5d552c7b-1b"
Accept-Ranges: bytes

这个时候有了Conten-Length,当然,如果想要ES加载必须编辑一下这个文件,再增加一些东西。
修改文件

cat /home/deploy/search/log-search/analize_word/test.txt
钟丽
陈港生
陈默涵
流水人间

在ES的日志中等待一会儿,便可以看到


[2019-08-16T11:37:51,001][INFO ][o.w.a.d.Monitor          ] [ES01] 重新加载词典...
[2019-08-16T11:37:51,020][INFO ][o.w.a.d.Monitor          ] [ES01] try load config from /home/deploy/search/log-search/elasticsearch-7.1.1/config/analysis-ik/IKAnalyzer.cfg.xml
[2019-08-16T11:37:51,105][INFO ][o.w.a.d.Monitor          ] [ES01] [Dict Loading] http://10.76.7.49:88/analize/test.txt
[2019-08-16T11:37:51,108][INFO ][o.w.a.d.Monitor          ] [ES01] 钟丽
[2019-08-16T11:37:51,108][INFO ][o.w.a.d.Monitor          ] [ES01] 陈港生
[2019-08-16T11:37:51,108][INFO ][o.w.a.d.Monitor          ] [ES01] 陈默涵
[2019-08-16T11:37:51,108][INFO ][o.w.a.d.Monitor          ] [ES01] 流水人间
[2019-08-16T11:37:51,108][INFO ][o.w.a.d.Monitor          ] [ES01] 重新加载词典完毕...

ok至此,nginx的基于文件的热词更新设置完成。

4.spring boot tomcat的设置

上面把nginx的调通也就找到了原因,知道原因了问题就好解决了。再调试原有的springboot代码,发现返回的header中果然没有Content-Length
研究一下tomcat的相关特性。

在tomcat当中,是使用一个respone buffer的缓存来存储即将发回的数据,如果这个buffer没有使用完,默认的情况下,tomcat使用的就是常规的方式,就是一次性返回,这个时候在response header当中是有Content-Length。如果这个buffer写满了而你还有数据要歇的时候,这个时候就先要进行一次会写,这个时候tomcat的响应就变成了chuncked的模式了。还有一种情况,如果显示的进行flush操作,就是response.gerWriter wirter.flush也会导致变成chuncked响应。
因此,在springboot tomcat项目中,需要将buffer size设置的更大(具体看自己的业务需求),同时不能显式的去调用flush操作。 这样就ok了。

对应的代码

@RequestMapping(value = "/remoteExtDict/select", method = RequestMethod.GET)public void select(HttpServletResponse response) {List<String> resultList = remoteExtDictMapper.selectRemoteExtDict();StringBuilder result = new StringBuilder();for (String value : resultList){result.append(value+"\n");}result.delete(result.length()-1,result.length());try {Long time = remoteExtDictMapper.getMaxTime();response.setHeader("Last-Modified", time.toString());response.setHeader("ETag",time.toString());response.setContentType("text/plain; charset=utf-8");response.setBufferSize(500000);String test = "上海堡垒\n陈默涵\n天际漫谈\n大西瓜\n人生如梦\n快手";PrintWriter writer = response.getWriter();writer.write(test);} catch (IOException e) {log.error("自定义词典更新报错" , e);}}

至此,问题解决

这个其实算是IK插件的一个小小bug,估计后面就该修复了。

参考
https://imququ.com/post/transfer-encoding-header-in-http.html

自定义ik分词加载无效的问题分析相关推荐

  1. mint-ui Infinite scroll 重复加载、加载无效的原因及解决方案

    mint-ui Infinite scroll 重复加载.加载无效的原因及解决方案 参考文章: (1)mint-ui Infinite scroll 重复加载.加载无效的原因及解决方案 (2)http ...

  2. 自定义类加载器加载冲突类(一)-ClassLoader

    使用场景:项目中遇到使用不同版本的类时候因为同路径同名类的冲突可以使用自定义类加载器进行加载规避这一问题 相关代码如下: 代码 1. 类加载器: import java.io.File; import ...

  3. android圆形点击效果,Android 三种方式实现自定义圆形页面加载中效果的进度条

    [实例简介] Android 三种方式实现自定义圆形页面加载中效果的进度条 [实例截图] [核心代码] ad376a86-a9aa-49bc-8cea-321bcff2c0c3 └── AnimRou ...

  4. 图片懒加载及Vue自定义图片懒加载指令

    文章目录 监听滚动的方式 IntersectionObserver方式 自定义图片懒加载vue指令1 自定义图片懒加载vue指令2 lazyLoadImage.js main.js中注册指令 组件中使 ...

  5. 仿百度壁纸客户端(四)——自定义上拉加载实现精选壁纸墙

    仿百度壁纸客户端(四)--自定义上拉加载实现精选壁纸墙 百度壁纸系列 仿百度壁纸客户端(一)--主框架搭建,自定义Tab + ViewPager + Fragment 仿百度壁纸客户端(二)--主页自 ...

  6. 记录--Vue自定义指令实现加载中效果v-load(不使用Vue.extend)

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 网站效果演示:ashuai.work:8888/#/myLoad GitHub仓库地址代码:github.com/shuirongshu- ...

  7. arcgis前端(2)----->基础篇--发布一个自定义地图及加载自定义地图/底图

    arcgis前端(2)----->基础篇–发布一个自定义地图及加载自定义地图/底图 文章目录 arcgis前端(2)----->基础篇--发布一个自定义地图及加载自定义地图/底图 前言 & ...

  8. vue自定义指令---处理加载图片失败时出现的碎图,onerror事件

    目录 一.自定义指令 1.局部注册和使用 2.全局注册和使用 二.自定义指令处理图片加载失败(碎图) 一.自定义指令 vue中除v-model.v-show等内置指令之外,还允许注册自定义指令,获取D ...

  9. 【ClassLoader】实现自定义类加载器加载指定路径下的Class文件和Jar包

    文章目录 前言 自定义类加载器加载.class文件 自定义类加载器加载jar包文件 前言 在web开发中,一般我们是不需要去自己实现类加载器的,常见的web容器已经帮我们实现了指定路径下的加载,比如我 ...

最新文章

  1. JDK8 Stream操作 collectingAndThen:根据对象的属性去重
  2. Android入门:实现一个File存储的辅助类
  3. Dapr 客户端 搭配 WebApiClientCore 玩耍服务调用
  4. 联通光纤限制连接数_从数百万个光纤(而不是数千个线程)中查询数据库
  5. python 生成pdf页面大小_(Python)更改使用xtopd生成的PDF文件的页面大小和格式
  6. C++继承详解:共有(public)继承,私有(private)继承,保护(protected)继承
  7. MFC串口通信设置及发送、中断接收程序
  8. warshall算法求传递闭包c++_【建模小课堂】图论算法
  9. gpio驱动蜂鸣器出现破音_五款蜂鸣器驱动电路原理图
  10. [实验手册]MPLS/×××分解:防止PE-CE的路由环路
  11. java test circle_java-使用Jacoco和Circle CI生成测试覆盖率失败
  12. aspnet网站开发实例_给自己开发一个网站,这是我的方法。
  13. 重载操作符解析(原)
  14. 循环神经网络 递归神经网络_递归神经网络-第3部分
  15. C语言程序设计(第五版)-谭浩强著-课后习题
  16. 河南中睿保险中介系统环境升级配置纪录
  17. Ubuntu之安装拼音输入法
  18. 研究B站个人收藏中已失效的视频
  19. [回炉计划]当输入xxxxhub的时候,居然是这样
  20. 在系统中集成淘宝扫码登录

热门文章

  1. 1.5 MFC封装思想
  2. 深入理解Golang 编程思维和工程实战
  3. 面试官问:ZooKeeper是强一致的吗?怎么实现的?
  4. RabbitMQ负载均衡(4)——LVS
  5. LVS+Keepalived实现负载均衡和双机热备
  6. 完成一个休闲网络游戏需要学习的知识
  7. 利用JPEG制作更快,更准确的神经网络
  8. 剑指offer之31-35题解
  9. 快速实现一个分布式定时器
  10. 上篇 | 如何设计一个多轮对话机器人