????????基于web地址的方式實現ik分詞熱更新。
操作系統:win 11
es version:8.6.2
ik version:8.6.2
1、創建web服務,并提供ik查詢詞庫接口
- 編寫分詞http url代碼,返回自定義分詞內容
- 分詞詞庫數據來自業務需求,存儲于業務DB,便于維護
- 多個分詞按行輸出,中文分詞編碼UTF-8
- http url接口返回內容編碼UTF-8
- 設置返回header頭信息 ETag 為自定義詞庫的hash值;
- 設置返回header頭信息 Last-Modified 為自定義詞庫最新更新的時間
ETag和Last-Modified任意一個變化就會ik就會更新詞庫。
package com.david.ikremotedict.controller;import com.david.ikremotedict.domain.IkExtDict;
import com.david.ikremotedict.domain.IkStopDict;
import com.david.ikremotedict.service.IkExtDictService;
import com.david.ikremotedict.service.IkStopDictService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.List;/*** @authar David* @Date 2025/4/1* @description*/
@Controller
@RequestMapping("/remoteDict")
public class RemoteDictController {//自定義分詞詞庫@Autowiredprivate IkExtDictService extDictService;@Autowiredprivate IkStopDictService stopDictService;private final String DEFAULT_LAST_MODIFIED = "1743492903";/*** 擴展分詞** @return * @throws IOException*/@GetMapping(value = "extDict")@ResponseBodypublic ResponseEntity<StreamingResponseBody> ikExtDict() throws IOException {System.out.println(LocalDateTime.now());// 獲取詞庫列表List<IkExtDict> list = extDictService.list();// 提前判斷 list 是否為空,避免不必要的流式處理if (list == null || list.isEmpty()) {return ResponseEntity.noContent().header("ETag", "eb5b427b4d494525a6595a215df46dab").header("Last-Modified", DEFAULT_LAST_MODIFIED).build();}// 獲取最新的創建時間戳IkExtDict latestDict = list.get(list.size() - 1);long timestamp = latestDict.getCreatedAt().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();// 創建流式響應體StreamingResponseBody responseBody = outputStream -> {try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8))) {for (IkExtDict dict : list) {writer.write(dict.getDict());writer.newLine(); // 寫入換行符}} catch (IOException exception) {exception.printStackTrace(); // 拋出異常以便上層處理}};// 返回響應實體return ResponseEntity.ok().contentType(MediaType.valueOf("text/plain;charset=UTF-8")).header("ETag", "eb5b427b4d494525a6595a215df46dab")// 這里應該返回操作dict的最后時間,先臨時返回最后一個數據的創建時間.header("Last-Modified", String.valueOf(timestamp)).body(responseBody);}/*** 擴展停止詞** @return * @throws IOException*/@GetMapping(value = "stopDict")@ResponseBodypublic ResponseEntity<StreamingResponseBody> ikStopDict() throws IOException {List<IkStopDict> list = stopDictService.list();// 提前判斷 list 是否為空,避免不必要的流式處理if (list == null || list.isEmpty()) {return ResponseEntity.noContent().header("ETag", "eb5b427b4d494525a6595a215df46dab").header("Last-Modified", DEFAULT_LAST_MODIFIED).build();}// 獲取最新的創建時間戳IkStopDict latestDict = list.get(list.size() - 1);long timestamp = latestDict.getCreatedAt().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();// 創建流式響應體StreamingResponseBody responseBody = outputStream -> {try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8))) {for (IkStopDict dict : list) {writer.write(dict.getDict());writer.newLine(); // 寫入換行符}} catch (IOException exception) {exception.printStackTrace(); // 拋出異常以便上層處理}};// 返回響應實體return ResponseEntity.ok().contentType(MediaType.valueOf("text/plain;charset=UTF-8")).header("ETag", "5a6595a2eb5b427b4d4945215df46dab")// 這里應該返回操作dict的最后時間,先臨時返回最后一個數據的創建時間.header("Last-Modified", String.valueOf(timestamp)).body(responseBody);}
}
? ? ????源碼地址 github:https://github.com/a66245753/ik-remote-dict.git
? ? ? ? 查詢擴展詞url:http://127.0.0.1:8080/remoteDict/extDict
? ? ? ? 查詢停用詞url:http://127.0.0.1:8080/remoteDict/stopDict?
? ? ?
2、ik 插件下載配置
? ? ? ? 2.1、下載ik分詞器地址:Index of:
? ? ? ? 2.2、進入analysis-ik
? ? ? ? 2.3、選擇es對應版本?8.6.2?
? ? ? ? 下載地址:https://release.infinilabs.com/analysis-ik/stable/elasticsearch-analysis-ik-8.6.2.zip
? ? ? ? ?2.4、在es插件目錄下新建ik目錄,{es-path}\plugins\ik
? ? ? ? ?2.5、將2.3下載的壓縮包解壓到ik目錄
?? ? ? ? ?2.6、在es的config下面創建analysis-ik目錄,{es-path}\config\analysis-ik
? ? ? ? ? 2.7、將ik目錄下config里面的文件拷貝到analysis-ik目錄中
?? ? ? ? ? 2.8、編輯 IKAnalyzer.cfg.xml,將web服務中的數據接口地址填進去
<?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://127.0.0.1:8080/remoteDict/extDict</entry><!-- 用戶可以在這里配置遠程擴展停止詞字典 --><entry key="remote_ext_stopwords">http://127.0.0.1:8080/remoteDict/stopDict</entry>
</properties>
3、啟動es和kibana
? ? ? ? 啟動es的時候會看到加載plugin的日志和詞庫內容。
4、驗證?
? ? ? ? 4.1、沒加“嚕咪啦”分詞前的解析
? ? ? ? 4.2、加“嚕咪啦”分詞后的解析?
?經過測試ik讀取web地址的頻率是每分鐘一次,暫時沒找到強制刷新的方法。
索引字段與屬性都屬于靜態設置,若后期變更歷史數據需要重建索引才可生效
對歷史數據無效!!!!一定要重建索引!!!!
重建索引:es 3期 第10節 如何正確使用Reindex重建索引_es reindex 原索更新正常使用-CSDN博客
配置文件含義:
IKAnalyzer.cfg.xml:配置自定義詞庫文件
main.dic:內置的中文詞庫
quantifier.dic:單位相關的詞
suffix.dic:后綴詞
surname.dic:中國姓氏
stopword.dic:英文停用詞
preposition.dic:介詞詞典