ES IK分词字典热更新

前言

在使用IK分词器的时候,发现官方默认的分词不满足我们的需求,那么有没有方法可以自定义字典呢?

官方提供了三种方式

一、ik本地文件读取方式

k插件本来已为用户提供自定义词典扩展功能,只要修改配给文件即可:

1、添加自定义词典文件

在es/plugins/ik/config目录下创建mydict.dic文件;
mydict.dic文件中添加自定义热词;

2、修改IKAnalyzer.cfg.xml配置文件

在es/plugins/ik/config目录下修改IKAnalyzer.cfg.xml,修改内容如下:

/custom/mydict.dic

注意:mydict.dic文件格式为UTF-8

二、ik远程词库调用

1、ik官方文档说明

目前该插件支持热更新 IK 分词,通过上文在 IK 配置文件中提到的如下配置

location

location

其中 location 是指一个 url,比如 http://yoursite.com/getCustomDict,该请求只需满足以下两点即可完成分词热更新。
1.该 http 请求需要返回两个头部(header),一个是 Last-Modified,一个是 ETag,这两者都是字符串类型,只要有一个发生变化,该插件就会去抓取新的分词进而更新词库。
2.该 http 请求返回的内容格式是一行一个分词,换行符用 \n 即可。

2、http接口编写

@GetMapping("/keyWord/hot")
    public void getHotWordByOracle(HttpServletResponse response, Integer type) throws IOException {
        //查询分词字典
        if (type == null) {
            type = 0;
        }
        List<String> keyWords = keyWordDictService.getKeyWord(type);

        StringBuilder result = new StringBuilder();
        for (String value : keyWords){
            result.append(value+"\n");
        }

        result.delete(result.length()-1,result.length());

        try {
            String time = new Date().toString();
            response.setHeader("Last-Modified", time);
            response.setHeader("ETag",time);
            response.setContentType("text/plain; charset=utf-8");
            response.setBufferSize(500000);

            PrintWriter writer = response.getWriter();
            writer.write(result.toString());
        } catch (IOException e) {
            log.error("自定义词典更新报错" , e);
        }
    }

接口注意点:需要设置ContentType,根据业务需要BufferSize设置要大,并且不能使用flush

研究一下tomcat的相关特性。

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

三、MYSQL实现热更新词库

1、下载源码

下载地址:https://github.com/medcl/elasticsearch-analysis-ik/tree/v7.8.0
IK分词器版本要和ES版本一样

2、修改源码

添加 jdbc-reload.properties 配置文件

jdbc.url=jdbc:mysql://127.0.0.1:3307/test?serverTimezone=GMT
jdbc.user=root
jdbc.password=abc123456
jdbc.reload.sql=select word from hot_words
jdbc.reload.stopword.sql=select stopword as word from hot_stopwords
jdbc.reload.interval=1000

添加热更新线程类 HotDictReloadThread,就是一个死循环,不断调用Dictionary.getSingleton().reLoadMainDict(),去重新加载词典

public class HotDictReloadThread implements Runnable{

    private static final Logger LOGGER = ESPluginLoggerFactory.getLogger(HotDictReloadThread.class.getName());

    @Override
    public void run() {
        while (true){
            LOGGER.info("reload hot dict from mysql");
            Dictionary.getSingleton().reLoadMainDict();
        }
    }
}

修改 Dictionary类initial 初始化方法,创建一个我们自定义的线程,并且启动它

new Thread(new  HotDictReloadThread()).start();

在这里插入图片描述
增加从mysql加载扩展词典方法

private static Properties prop = new Properties();

	static {
		try {
			Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e){
			logger.error("error",e);
		}
	}

	/**
	 * 从mysql加载扩展词典
	 */
	private void loadMySqlExtDict(){
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;

		try {
			Path file = PathUtils.get(getDictRoot(),"jdbc-reload.properties");
			prop.load(new FileInputStream(file.toFile()));

			logger.info("jdbc-reload.properties");
			for (Object key : prop.keySet()) {
				logger.info(key + "=" + prop.getProperty(String.valueOf(key)));
			}

			logger.info("query hot dict from mysql," + prop.getProperty("jdbc.reload.sql"));

			conn = DriverManager.getConnection(
					prop.getProperty("jdbc.url"),
					prop.getProperty("jdbc.user"),
					prop.getProperty("jdbc.password")
			);
			stmt = conn.createStatement();
			rs = stmt.executeQuery(prop.getProperty("jdbc.reload.sql"));

			while (rs.next()){
				String word = rs.getString("word");
				logger.info("hot word from mysql:" + word);
				_MainDict.fillSegment(word.trim().toCharArray());
			}
			Thread.sleep(Integer.valueOf(String.valueOf(prop.get("jdbc.reload.interval"))));
		} catch (Exception e){
			logger.error("error",e);
		} finally {
			if (rs != null) {
				try {
					rs.close();
				} catch (SQLException e){
					logger.error("error",e);
				}
			}

			if (stmt != null) {
				try {
					stmt.close();
				} catch (SQLException e){
					logger.error("error",e);
				}
			}

			if (conn != null) {
				try {
					conn.close();
				} catch (SQLException e) {
					logger.error("error",e);
				}
			}
		}
	}

并在加载主词典及扩展词典方法 loadMainDict 中调用
在这里插入图片描述
增加从mysql加载停用词方法 loadMySQLStopwordDict

/**
	 * 从mysql加载停用词
	 */
	private void loadMySQLStopwordDict() {
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;

		try {
			Path file = PathUtils.get(getDictRoot(), "jdbc-reload.properties");
			prop.load(new FileInputStream(file.toFile()));

			logger.info("[==========]jdbc-reload.properties");
			for(Object key : prop.keySet()) {
				logger.info("[==========]" + key + "=" + prop.getProperty(String.valueOf(key)));
			}

			logger.info("[==========]query hot stopword dict from mysql, " + prop.getProperty("jdbc.reload.stopword.sql") + "......");

			conn = DriverManager.getConnection(
					prop.getProperty("jdbc.url"),
					prop.getProperty("jdbc.user"),
					prop.getProperty("jdbc.password"));
			stmt = conn.createStatement();
			rs = stmt.executeQuery(prop.getProperty("jdbc.reload.stopword.sql"));

			while(rs.next()) {
				String theWord = rs.getString("word");
				logger.info("[==========]hot stopword from mysql: " + theWord);
				_StopWords.fillSegment(theWord.trim().toCharArray());
			}

			Thread.sleep(Integer.valueOf(String.valueOf(prop.get("jdbc.reload.interval"))));
		} catch (Exception e) {
			logger.error("erorr", e);
		} finally {
			if(rs != null) {
				try {
					rs.close();
				} catch (SQLException e) {
					logger.error("error", e);
				}
			}
			if(stmt != null) {
				try {
					stmt.close();
				} catch (SQLException e) {
					logger.error("error", e);
				}
			}
			if(conn != null) {
				try {
					conn.close();
				} catch (SQLException e) {
					logger.error("error", e);
				}
			}
		}
	}

并在加载用户扩展的停止词词典方法 loadStopWordDict 中调用
在这里插入图片描述

3、打包

mvn package打包代码
把文件target\releases\elasticsearch-analysis-ik-7.8.0.zip放到es的plugins中

4、解压缩

将zip包解压,并把mysql驱动放到ik目录下

5、重启es

之后通过数据库添加分词或者停用词即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/946881.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于Spring Boot的电影网站系统

一、技术架构 后端框架&#xff1a;Spring Boot&#xff0c;它提供了自动配置、简化依赖管理、内嵌式容器等特性&#xff0c;使得开发者可以快速搭建起一个功能完备的Web应用。 前端技术&#xff1a;可能采用Vue.js、JS、jQuery、Ajax等技术&#xff0c;结合Element UI等组件库…

C#运动控制系统:雷赛控制卡实用完整例子 C#雷赛开发快速入门 C#雷赛运动控制系统实战例子 C#快速开发雷赛控制卡

雷赛控制技术 DMC系列运动控制卡是一款新型的 PCI/PCIe 总线运动控制卡。可以控制多个步进电机或数字式伺服电机&#xff1b;适合于多轴点位运动、插补运动、轨迹规划、手轮控制、编码器位置检测、IO 控制、位置比较、位置锁存等功能的应用。 DMC3000 系列卡的运动控制函数库功…

android studio 写一个小计时器(版本二)

as版本&#xff1a;23.3.1patch2 例程&#xff1a;timer 在前一个版本的基本上改的&#xff0c;增加了继续的功能&#xff0c;实现方法稍微不同。 动画演示&#xff1a; activity_main.xml <?xml version"1.0" encoding"utf-8"?> <androidx…

python-leetcode-轮转数组

189. 轮转数组 - 力扣&#xff08;LeetCode&#xff09; class Solution:def rotate(self, nums: List[int], k: int) -> None:"""Do not return anything, modify nums in-place instead."""n len(nums)k % n # 如果 k 大于 n&#xff0c;…

亚马逊云科技 | Amazon Nova:智能技术新势力

在2024年亚马逊云科技re:invent大会上&#xff0c;Amazon Nova 系列自研生成式 AI 多模态模型重磅登场&#xff0c;新一代的AI产品-Amazon Nova&#xff0c;隶属于 Amazon Bedrock&#xff0c;一共发布6款大模型&#xff0c;精准切入不同领域&#xff0c;解锁多元业务可能&…

记录第一次跑YOLOV8做目标检测

今天是24年的最后一天&#xff0c;终于要向新世界开始破门了&#xff0c;开始深度学习&#xff0c;YOLO来敲门~ 最近做了一些皮肤检测的功能&#xff0c;在传统的处理中经历了反复挣扎&#xff0c;终于要上YOLO了。听过、看过&#xff0c;不如上手体会过~ 1、YOLO是什么&#x…

从授权校验看SpringBoot自动装配

背景 最近需要实现一个对于系统的授权检测功能&#xff0c;即当SpringBoot应用被启动时&#xff0c;需要当前设备是否具有有效的的授权许可信息&#xff0c;若无则直接退出应用。具体的实现方案请继续看下文。 环境 Ruoyi-Vue SpringBoot3 RuoYi-Vue: &#x1f389; 基于Spr…

【Unity】 HTFramework框架(五十七)通过Tag、Layer批量搜索物体

更新日期&#xff1a;2024年12月30日。 Github源码&#xff1a;[点我获取源码] Gitee源码&#xff1a;[点我获取源码] 索引 问题再现通过Tag搜索物体&#xff08;SearchByTag&#xff09;打开SearchByTag窗口搜索标记指定Tag的所有物体批量修改Tag搜索Undefined状态的所有物体 …

Unity2D无限地图的实现(简单好抄)

说明&#xff1a;本教程实现的是在2D游戏中玩家在游戏中上下左右移动的时候自动进行地图拼接的功能&#xff0c;如果你只想实现左右移动的无限地图&#xff0c;那么这篇博客也能起到一定参考作用。 思路 第一步&#xff1a; 创建一个10*10的2D游戏对象当做地图 第二步创建一个…

艾体宝方案丨全面提升API安全:AccuKnox 接口漏洞预防与修复

一、API 安全&#xff1a;现代企业的必修课 在现代技术生态中&#xff0c;应用程序编程接口&#xff08;API&#xff09;扮演着不可或缺的角色。从数据共享到跨平台集成&#xff0c;API 成为连接企业系统与外部服务的桥梁。然而&#xff0c;伴随云计算的普及与微服务架构的流行…

日期时间选择(设置禁用状态)

目录 1.element文档需要 2.禁用所有过去的时间 3.设置指定日期的禁用时间 <template><div class"block"><span class"demonstration">起始日期时刻为 12:00:00</span><el-date-pickerv-model"value1"type"dat…

SAP学习笔记 - 豆知识14 - Msg 番号 M7562 - 取引Type WL 对应的番号範囲中不存在2025年度 OMBT

这种类似的以前也写过&#xff0c;原因就是自动採番的番号没弄。 比如跨年了&#xff0c;那该新年度的番号范围没弄啊&#xff0c;就会出这种错误。 把番号范围给加一下就可以了。 1&#xff0c;现象 比如点 VL02N 出荷传票变更 画面&#xff0c;点 出库确认 就会出如下错误…

SpringBoot 集成 Activiti 7 工作流引擎

一. 版本信息 IntelliJ IDEA 2023.3.6JDK 17Activiti 7 二. IDEA依赖插件安装 安装BPM流程图插件&#xff0c;如果IDEA的版本超过2020,则不支持actiBPM插件。我的IDEA是2023版本我装的是 Activiti BPMN visualizer 插件。 在Plugins 搜索 Activiti BPMN visualizer 安装 创…

分布式版本管理工具——Git关联远程仓库(github+gitee)

Git远程仓库&#xff08;Github&#xff09;的基本使用 一、前言二、Git远程仓库介绍三、演示1. 关联github远程仓库2. 关联gitee&#xff08;码云&#xff09;远程仓库3. 重命名远程仓库名4. 移除远程仓库 四、结束语 一、前言 古之立大事者&#xff0c;不惟有超世之才&#x…

python-leetcode-删除有序数组中的重复项 II

80. 删除有序数组中的重复项 II - 力扣&#xff08;LeetCode&#xff09; class Solution:def removeDuplicates(self, nums: List[int]) -> int:n len(nums)if n < 2:return n # 如果长度小于等于 2&#xff0c;直接返回长度k 2 # 指针 k 指向下一个有效位置&#x…

欧科云链OKLink:比特币与以太坊“双重启动”将如何撬动市场?

近日&#xff0c;OKLink 与 137Labs 联合举办 X Space&#xff0c;围绕宏观经济环境、政策及机构投资的影响等话题&#xff0c;分享如何把握 Web3 中的潜在机会与辨别风险。OKG Research 首席研究员 Hedy、BuilderRocket Accelerator 研究合伙人 Vivienna、VC 分析员 Bunny、BU…

【Linux】Socket编程-UDP构建自己的C++服务器

&#x1f308; 个人主页&#xff1a;Zfox_ &#x1f525; 系列专栏&#xff1a;Linux 目录 一&#xff1a;&#x1f525; UDP 网络编程 &#x1f98b; 接口讲解&#x1f98b; V1 版本 - echo server&#x1f98b; V2 版本 - DictServer&#x1f98b; V3 版本 - 简单聊天室 二&a…

创建型设计模式、结构型设计模式与行为型设计模式 上下文任务通用方案 设计模式 大全

设计模式&#xff08;Design Pattern&#xff09;是一种面向对象编程思想&#xff0c;分为创建型模式、结构型模式与行为型模式三大类&#xff0c;提供在特定上下文中解决常见任务通用方案&#xff0c;旨在让程序&#xff08;软件&#xff09;具有更好特点&#xff0c;如降低耦…

如何查看下载到本地的大模型的具体大小?占了多少存储空间:Llama-3.1-8B下载到本地大概15GB

这里介绍一下tree命令&#xff0c;可以方便的查看文件目录结构和文件大小。 命令行tree的具体使用&#xff0c;请参考笔者的另一篇博客&#xff1a;深入了解 Linux tree 命令及其常用选项&#xff1a;Linux如何显示目录结构和文件大小&#xff0c;一言以蔽之&#xff0c;sudo a…

MySQL线上事故:使用`WHERE`条件`!=xxx`无法查询到NULL数据

前言 在一次 MySQL 的线上查询操作中&#xff0c;因为 ! 的特性导致未能正确查询到为 NULL 的数据&#xff0c;险些引发严重后果。本文将详细解析 NULL 在 SQL 中的行为&#xff0c;如何避免类似问题&#xff0c;并提供实际操作建议。 1. 为什么NULL会查询不到&#xff1f; 在…