自定义ik分词加载无效的问题分析
文章目錄
- 問題背景
- 1.需求
- 2. 使用tomcat提供一個(gè)接口
- 3. 使用nginx代理文件
- 3.1 nginx 配置
- 3.2 ES配置
- 3.3 增加詞匯不生效
- 3.4 修改nginx配置進(jìn)行驗(yàn)證
- 4.spring boot tomcat的設(shè)置
問題背景
1.需求
最近有一些需求導(dǎo)致我們需要擴(kuò)充IK的詞庫(kù),按照IK的官方走了一遍,這里是官方的一些介紹
IK熱更新配置方式
我們的ES版本為7.1.1
2. 使用tomcat提供一個(gè)接口
按照文檔在tomcat服務(wù)中提供一個(gè)接口,來將自定義的熱詞數(shù)據(jù)寫出去,結(jié)果在es中不能成功加載這些數(shù)據(jù)。
項(xiàng)目是一個(gè)springboot項(xiàng)目,接口的代碼如下
在瀏覽器端和crul請(qǐng)求中返回的結(jié)果都比較正常,編碼等都是正確設(shè)置了的。所以很是疑惑,如果使用es本地文件的方式添加熱詞是可以的。所以感覺應(yīng)該是哪個(gè)環(huán)節(jié)有問題。
因?yàn)楣俜浇ㄗh是使用nginx代理文件的方式,所以決定先用nginx來搞一下看看能不能正確使用,然后再進(jìn)行對(duì)比。
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;} }對(duì)應(yīng)的文件為 /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 擴(kuò)展配置</comment><!--用戶可以在這里配置自己的擴(kuò)展字典 --><entry key="ext_dict"></entry><!--用戶可以在這里配置自己的擴(kuò)展停止詞字典--><entry key="ext_stopwords"></entry><!--用戶可以在這里配置遠(yuǎn)程擴(kuò)展字典 --><entry key="remote_ext_dict">http://10.26.5.18:8090/search/manager/es/remoteExtDict/select</entry><!--用戶可以在這里配置遠(yuǎn)程擴(kuò)展停止詞字典--><!-- <entry key="remote_ext_stopwords">words_location</entry> --> </properties>重啟ES
在修改完后等了一會(huì)兒可以在es的日志中看到
說明確實(shí)成功了。
3.3 增加詞匯不生效
接下來出現(xiàn)了比較詭異的東西。
當(dāng)我再在文件中添加一個(gè)詞的時(shí)候更新就無法成功了。
對(duì)應(yīng)的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] 重新加載詞典完畢...反復(fù)試了幾次都是這樣,感覺很奇怪。冷靜下來分析,應(yīng)該是對(duì)數(shù)據(jù)長(zhǎng)度的識(shí)別有問題。又去翻了翻IK上的issue。最后找到了這條
頓時(shí)覺得和我現(xiàn)在的狀態(tài)十分的吻合。
簡(jiǎn)單描述一下,就是nginx默認(rèn)會(huì)對(duì)響應(yīng)進(jìn)行壓縮gzip和分片chuncked
進(jìn)行驗(yàn)證,當(dāng)文件中只有兩個(gè)詞,返回的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 這個(gè)header
當(dāng)編程三個(gè)詞的時(shí)候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 這個(gè)header,
有了一個(gè)Transfer-Encoding:chunked 和一個(gè)Content-Encoding:gzip
這兩個(gè)header是為了提升傳輸?shù)男屎蛯?duì)內(nèi)容進(jìn)行壓縮的。
IK插件可能是因?yàn)槟撤N原因未對(duì)這中情況做支持,只有有Content-Length的時(shí)候才能正確的識(shí)別。
3.4 修改nginx配置進(jìn)行驗(yàn)證
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;} }這個(gè)時(shí)候再?gòu)臑g覽器請(qǐng)求,觀察返回的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這個(gè)時(shí)候有了Conten-Length,當(dāng)然,如果想要ES加載必須編輯一下這個(gè)文件,再增加一些東西。
修改文件
在ES的日志中等待一會(huì)兒,便可以看到
[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的基于文件的熱詞更新設(shè)置完成。
4.spring boot tomcat的設(shè)置
上面把nginx的調(diào)通也就找到了原因,知道原因了問題就好解決了。再調(diào)試原有的springboot代碼,發(fā)現(xiàn)返回的header中果然沒有Content-Length
研究一下tomcat的相關(guān)特性。
在tomcat當(dāng)中,是使用一個(gè)respone buffer的緩存來存儲(chǔ)即將發(fā)回的數(shù)據(jù),如果這個(gè)buffer沒有使用完,默認(rèn)的情況下,tomcat使用的就是常規(guī)的方式,就是一次性返回,這個(gè)時(shí)候在response header當(dāng)中是有Content-Length。如果這個(gè)buffer寫滿了而你還有數(shù)據(jù)要歇的時(shí)候,這個(gè)時(shí)候就先要進(jìn)行一次會(huì)寫,這個(gè)時(shí)候tomcat的響應(yīng)就變成了chuncked的模式了。還有一種情況,如果顯示的進(jìn)行flush操作,就是response.gerWriter wirter.flush也會(huì)導(dǎo)致變成chuncked響應(yīng)。
因此,在springboot tomcat項(xiàng)目中,需要將buffer size設(shè)置的更大(具體看自己的業(yè)務(wù)需求),同時(shí)不能顯式的去調(diào)用flush操作。 這樣就ok了。
對(duì)應(yīng)的代碼
@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人生如夢(mèng)\n快手";PrintWriter writer = response.getWriter();writer.write(test);} catch (IOException e) {log.error("自定義詞典更新報(bào)錯(cuò)" , e);}}至此,問題解決
這個(gè)其實(shí)算是IK插件的一個(gè)小小bug,估計(jì)后面就該修復(fù)了。
參考
https://imququ.com/post/transfer-encoding-header-in-http.html
總結(jié)
以上是生活随笔為你收集整理的自定义ik分词加载无效的问题分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 算法训练营12-动态规划
- 下一篇: 内存模型杂论