欢迎光临
我们一直在努力

Elasticsearch IK 分词器 热更新方案

ES默认的IK词典加载机制有个硬伤:修改词典必须重启整个ES集群,这在生产环境是不可接受的。热更新的目的就是让IK每隔一段时间自动从外部拉取新词,零停机生效。

方案一:基于远程HTTP文件(最推荐,官方原生支持)

这是IK官方提供的方案,利用ik-analyzer的remote_ext_dict配置项,让IK定时轮询一个远程URL。

1. 修改IK配置文件

找到ES的plugins/ik/config/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">custom/mydict.dic</entry>

<!– 停用词词典 –>
<entry key="ext_stopwords">custom/mystopword.dic</entry>

<!– ========== 重点:热更新远程词典 ========== –>
<entry key="remote_ext_dict">http://your-server.com/ik/dict.txt</entry>

<!– 远程停用词热更新 –>
<entry key="remote_ext_stopwords">http://your-server.com/ik/stopword.txt</entry>
</properties>

2. 搭建HTTP文件服务

在http://your-server.com/ik/dict.txt地址上部署一个纯文本文件,每行一个词:

内卷
YYDS
区块链
元宇宙
碳中和
李子柒

关键要求:

  • HTTP响应头必须包含Last-Modified或ETag。

  • IK每隔60秒会发一次HEAD请求检查文件是否修改。如果没变化,不会重新加载;只有Last-Modified变了,才会GET拉取新内容。

3. 验证生效

写入新文档测试:

POST /test/_doc/1
{
"content": "今天你内卷了吗"
}

POST /test/_search
{
"query": {
"term": {
"content": "内卷"
}
}
}

能命中说明热更新成功。


方案二:基于数据库(MySQL/Redis)- 适合运维管控

如果你想把词典管理放到后台系统中,让运营人员通过界面增删词,可以自己写一个同步程序。

架构思路

运营后台(增删词) -> MySQL/Redis(存储词典) -> 同步程序(定时拉取) -> 写入本地文件 -> IK 重新加载

IK本身不支持直接读数据库,所以需要拐个弯:

  • 在IKAnalyzer.cfg.xml中配置ext_dict为本地路径(如/data/ik/dynamic.dic)。

  • 写一个后台定时任务(Java/Python),每隔1分钟从MySQL拉取最新词表,覆盖写入dynamic.dic。

  • 关键步骤:修改文件的mtime(修改时间戳),因为IK只通过文件的最后修改时间判断是否变更。

    • Linux命令:touch -t 202501011200 dynamic.dic

    • Java代码:File.setLastModified(System.currentTimeMillis())

  • 缺点

    需要额外维护同步程序,且ES集群每个节点都要有本地文件,操作较繁琐。


    方案三:基于Nacos / Apollo(配置中心)

    如果你公司已经在用配置中心,可以把词典作为配置项管理:

  • 将词典内容存入Nacos的配置项(String类型,换行分隔)。

  • 写一个监听器,当Nacos配置变更时,触发回调:

    • 将新词表写入ES节点的本地文件。

    • 调用touch修改文件时间戳。

  • IK到60秒检查周期时发现文件变了,自动Reload。


  • 避坑指南(必看)

    1. IK的缓存机制

    即使热更新拉到了新词,已存在的倒排索引不会重建。

    • 新词只对更新后新写入的文档生效。

    • 想让历史文档也带新词?必须Reindex(重建索引)。

    2. 文件编码必须是UTF-8(无BOM)

    如果文件是GBK或带BOM的UTF-8,IK会解析乱码,导致分词异常。用Notepad++或VS Code保存时选UTF-8 without BOM。

    3. 远程文件响应要快

    如果remote_ext_dict指向的HTTP服务响应超时(默认5秒),IK会跳过本次更新,继续用旧词表。确保你的文件服务高可用。

    4. 各节点独立拉取

    每个ES数据节点都会独立向HTTP服务器请求词典,如果集群有10个节点,每秒会有10个请求,注意服务器压力。


    完整配置示例(包含同义词热更新)

    如果你想连同义词也热更新,可以结合synonym过滤器:

    <!– IKAnalyzer.cfg.xml –>
    <entry key="remote_ext_dict">http://your-server.com/ik/main.dic</entry>
    <entry key="remote_ext_stopwords">http://your-server.com/ik/stop.dic</entry>

    然后在索引的settings中配置同义词文件指向远程路径(同义词不支持remote方式,需配合Nginx动态生成):

    {
    "settings": {
    "analysis": {
    "filter": {
    "my_synonym": {
    "type": "synonym",
    "synonyms_path": "analysis/synonym.txt" // 这个文件需要放在ES的config目录下,无法热更新
    }
    }
    }
    }
    }

    同义词热更新较复杂,一般是配合Nginx反向代理+动态文件生成来实现,如需我可以单独给你方案。


    一句话总结

    用remote_ext_dict指向一个HTTP文本文件,IK每60秒自动检查更新,这是最简单、最稳妥的热更新方案。记住:新词只影响新数据,历史数据需要Reindex。

    赞(0)
    未经允许不得转载:171主机测评 » Elasticsearch IK 分词器 热更新方案
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址