距离上一次更新该文章已经过了 714 天,文章所描述的內容可能已经发生变化,请留意。
目前该插件支持热更新 IK 分词,通过上文在 IK 配置文件中提到的如下配置
1 2 3 4
| <entry key="remote_ext_dict">location</entry> <entry key="remote_ext_stopwords">location</entry>
|
其中 location
是指一个 url,比如 http://yoursite.com/getCustomDict
,该请求只需满足以下两点即可完成分词热更新。
- 该 http 请求需要返回两个头部(header),一个是
Last-Modified
,一个是 ETag
,这两者都是字符串类型,只要有一个发生变化,该插件就会去抓取新的分词进而更新词库。 - 该 http 请求返回的内容格式是一行一个分词,换行符用
\n
即可。
满足上面两点要求就可以实现热更新分词了,不需要重启 ES 实例。
可以将需自动更新的热词放在一个 UTF-8 编码的 .txt 文件里,放在 nginx 或其他简易 http server 下,当 .txt 文件修改时,http server 会在客户端请求该文件时自动返回相应的 Last-Modified 和 ETag。可以另外做一个工具来从业务系统提取相关词汇,并更新这个 .txt 文件。
ES自定义字典表配置
cat elasticsearch-7.1.1/config/analysis-ik/IKAnalyzer.cfg.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?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">xxx.dic</entry> <entry key="ext_stopwords"></entry> <entry key="remote_ext_dict">http://10.26.5.18/analize/xxx.dic</entry> </properties>
|
nginx实现热更新
nginx配置
1 2 3 4 5 6 7 8 9 10
| server { listen 80; 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; } }
|
重启ES
在修改完后等了一会儿可以在es的日志中看到
1 2 3 4 5 6
| [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] 重新加载词典完毕...
|
说明确实成功了。
ES重新加载字典表
修改文件
cat /home/deploy/search/log-search/analize_word/test.txt
在ES的日志中等待一会儿,便可以看到
1 2 3 4 5 6 7 8
| [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的基于文件的热词更新设置完成。
结合spring代码实现热更新
在tomcat当中,是使用一个respone buffer的缓存来存储即将发回的数据,如果这个buffer没有使用完,默认的情况下,tomcat使用的就是常规的方式,就是一次性返回,这个时候在response header当中是有Content-Length。如果这个buffer写满了而你还有数据要歇的时候,这个时候就先要进行一次会写,这个时候tomcat的响应就变成了chuncked的模式了。还有一种情况,如果显示的进行flush操作,就是response.gerWriter wirter.flush也会导致变成chuncked响应。
因此,在springboot tomcat项目中,需要将buffer size设置的更大(具体看自己的业务需求),同时不能显式的去调用flush操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @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); } }
|