IK分词器升级,MySQL热更新助一臂之力

ik分词器采用MySQL热更新

​ 官方所给的IK分词器只支持远程文本文件热更新,不支持采用MySQL热更新,没关系,这难不倒伟大的博主,给哈哈哈。今天就来和大家讲一下如何采用MySQL做热更新IK分词器的词库。

一、建立数据库表

CREATE TABLE `es_extra_main`
(
    `id`          int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
    `word`        varchar(255) CHARACTER SET utf8mb4 NOT NULL COMMENT '词',
    `is_deleted`  tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否已删除',
    `update_time` timestamp(6)                       NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP (6) COMMENT '更新时间',
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;


CREATE TABLE `es_extra_stopword`
(
    `id`          int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
    `word`        varchar(255) CHARACTER SET utf8mb4 NOT NULL COMMENT '词',
    `is_deleted`  tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否已删除',
    `update_time` timestamp(6)                       NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP (6) COMMENT '更新时间',
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

二、修改IK分词器插件源码

2. 1修改pom文件

<!--mysql驱动-->
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>8.0.29</version>
</dependency>

2.2 新增DatabaseMonitor类

这里新增一个关于MySQL的类,源码中有关于远程文本文件的热更新源码,我们这边仿照源码来写一就可以啦。

package org.wltea.analyzer.dic;

import org.apache.logging.log4j.Logger;
import org.elasticsearch.SpecialPermission;
import org.wltea.analyzer.help.ESPluginLoggerFactory;

import java.security.AccessController;
import java.security.PrivilegedAction;
import java.sql.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

public class DatabaseMonitor implements Runnable {

    private static final Logger logger = ESPluginLoggerFactory.getLogger(DatabaseMonitor.class.getName());
    public static final String PATH_JDBC_PROPERTIES = "jdbc.properties";

    private static final String JDBC_URL = "jdbc.url";
    private static final String JDBC_USERNAME = "jdbc.username";
    private static final String JDBC_PASSWORD = "jdbc.password";
    private static final String JDBC_DRIVER = "jdbc.driver";
    private static final String SQL_UPDATE_MAIN_DIC = "jdbc.update.main.dic.sql";
    private static final String SQL_UPDATE_STOPWORD = "jdbc.update.stopword.sql";

    /**
     * 更新间隔
     */
    public final static String JDBC_UPDATE_INTERVAL = "jdbc.update.interval";

    private static final Timestamp DEFAULT_LAST_UPDATE = Timestamp.valueOf(LocalDateTime.of(LocalDate.of(2020, 1, 1), LocalTime.MIN));

    private static Timestamp lastUpdateTimeOfMainDic = null;

    private static Timestamp lastUpdateTimeOfStopword = null;

    public String getUrl() {
        return Dictionary.getSingleton().getProperty(JDBC_URL);
    }

    public String getUsername() {
        return Dictionary.getSingleton().getProperty(JDBC_USERNAME);
    }

    public String getPassword() {
        return Dictionary.getSingleton().getProperty(JDBC_PASSWORD);
    }

    public String getDriver() {
        return Dictionary.getSingleton().getProperty(JDBC_DRIVER);
    }

    public String getUpdateMainDicSql() {
        return Dictionary.getSingleton().getProperty(SQL_UPDATE_MAIN_DIC);
    }

    public String getUpdateStopwordSql() {
        return Dictionary.getSingleton().getProperty(SQL_UPDATE_STOPWORD);
    }

    /**
     * 加载MySQL驱动
     */
    public DatabaseMonitor() {
        SpecialPermission.check();
        AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
            try {
                Class.forName(getDriver());
            } catch (ClassNotFoundException e) {
                logger.error("mysql jdbc driver not found", e);
            }
            return null;
        });


    }

    @Override
    public void run() {
        SpecialPermission.check();
        AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
            Connection conn = getConnection();

            // 更新主词典
            updateMainDic(conn);
            // 更新停用词
            updateStopword(conn);
            closeConnection(conn);

            return null;
        });

    }

    public Connection getConnection() {
        Connection connection = null;
        try {
            connection = DriverManager.getConnection(getUrl(), getUsername(), getPassword());
        } catch (SQLException e) {
            logger.error("failed to get connection", e);
        }
        return connection;
    }

    public void closeConnection(Connection conn) {
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                logger.error("failed to close Connection", e);
            }
        }
    }

    public void closeRsAndPs(ResultSet rs, PreparedStatement ps) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                logger.error("failed to close ResultSet", e);
            }
        }

        if (ps != null) {
            try {
                ps.close();
            } catch (SQLException e) {
                logger.error("failed to close PreparedStatement", e);
            }
        }

    }

    /**
     * 主词典
     */
    public synchronized void updateMainDic(Connection conn) {

        logger.info("start update main dic");
        int numberOfAddWords = 0;
        int numberOfDisableWords = 0;
        PreparedStatement ps = null;
        ResultSet rs = null;

        try {
            String sql = getUpdateMainDicSql();

            Timestamp param = lastUpdateTimeOfMainDic == null ? DEFAULT_LAST_UPDATE : lastUpdateTimeOfMainDic;

            logger.info("param: " + param);

            ps = conn.prepareStatement(sql);
            ps.setTimestamp(1, param);

            rs = ps.executeQuery();

            while (rs.next()) {
                String word = rs.getString("word");
                word = word.trim();

                if (word.isEmpty()) {
                    continue;
                }

                lastUpdateTimeOfMainDic = rs.getTimestamp("update_time");

                if (rs.getBoolean("is_deleted")) {
                    logger.info("[main dic] disable word: {}", word);
                    // 删除
                    Dictionary.disableWord(word);
                    numberOfDisableWords++;
                } else {
                    logger.info("[main dic] add word: {}", word);
                    // 添加
                    Dictionary.addWord(word);
                    numberOfAddWords++;
                }
            }

            logger.info("end update main dic -> addWord: {}, disableWord: {}", numberOfAddWords, numberOfDisableWords);

        } catch (SQLException e) {
            logger.error("failed to update main_dic", e);
            // 关闭 ResultSet、PreparedStatement
            closeRsAndPs(rs, ps);
        }
    }

    /**
     * 停用词
     */
    public synchronized void updateStopword(Connection conn) {

        logger.info("start update stopword");

        int numberOfAddWords = 0;
        int numberOfDisableWords = 0;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            String sql = getUpdateStopwordSql();

            Timestamp param = lastUpdateTimeOfStopword == null ? DEFAULT_LAST_UPDATE : lastUpdateTimeOfStopword;

            logger.info("param: " + param);

            ps = conn.prepareStatement(sql);
            ps.setTimestamp(1, param);

            rs = ps.executeQuery();

            while (rs.next()) {
                String word = rs.getString("word");
                word = word.trim();


                if (word.isEmpty()) {
                    continue;
                }

                lastUpdateTimeOfStopword = rs.getTimestamp("update_time");

                if (rs.getBoolean("is_deleted")) {
                    logger.info("[stopword] disable word: {}", word);

                    // 删除
                    Dictionary.disableStopword(word);
                    numberOfDisableWords++;
                } else {
                    logger.info("[stopword] add word: {}", word);
                    // 添加
                    Dictionary.addStopword(word);
                    numberOfAddWords++;
                }
            }

            logger.info("end update stopword -> addWord: {}, disableWord: {}", numberOfAddWords, numberOfDisableWords);

        } catch (SQLException e) {
            logger.error("failed to update main_dic", e);
        } finally {
            // 关闭 ResultSet、PreparedStatement
            closeRsAndPs(rs, ps);
        }
    }
}



2.3 修改代码

初始化方法中新增加载JDBC的方法和将getProperty改为public

1691978293978

并且在Dictionary类后面新增下面的方法

	/**
	 * 加载新词条
	 */
	public static void addWord(String word) {
		singleton._MainDict.fillSegment(word.trim().toLowerCase().toCharArray());
	}

	/**
	 * 移除(屏蔽)词条
	 */
	public static void disableWord(String word) {
		singleton._MainDict.disableSegment(word.trim().toLowerCase().toCharArray());
	}

	/**
	 * 加载新停用词
	 */
	public static void addStopword(String word) {
		singleton._StopWords.fillSegment(word.trim().toLowerCase().toCharArray());
	}

	/**
	 * 移除(屏蔽)停用词
	 */
	public static void disableStopword(String word) {
		singleton._StopWords.disableSegment(word.trim().toLowerCase().toCharArray());
	}

	/**
	 * 加载 jdbc.properties
	 */
	public void loadJdbcProperties() {
		Path file = PathUtils.get(getDictRoot(), DatabaseMonitor.PATH_JDBC_PROPERTIES);
		try {
			props.load(new FileInputStream(file.toFile()));
			logger.info("====================================properties====================================");
			for (Map.Entry<Object, Object> entry : props.entrySet()) {
				logger.info("{}: {}", entry.getKey(), entry.getValue());
			}
			logger.info("====================================properties====================================");
		} catch (IOException e) {
			logger.error("failed to read file: " + DatabaseMonitor.PATH_JDBC_PROPERTIES, e);
		}
	}



三、修改插件的权限

1691978533490

grant {
  // needed because of the hot reload functionality
  permission java.net.SocketPermission "*", "connect,resolve";
  permission java.lang.RuntimePermission "setContextClassLoader";
};

四、打包

4.1 加入依赖

将MySQL的jar包依赖加入进来,否则打包会缺少jar包保持错。

1691978585532

<include>mysql:mysql-connector-java</include>

4.2 package

打包成zip文件,然后加压成文件夹

1691978891388

五、安装

将解压的文件夹放到ES的plugins目录下,然后配置一下config目录下的数据库配置信息,最后再重启一下ES即可完成安装。

1691982824263

六、测试验证

在数据库表中中新增下面自己的想要的关键词,然后去Kibana中做测试验证,可以发现已经可以啦。

关键词

1691983160572

停止词

image-20230814142403389

POST _analyze
{
  "text": ["俺是熊二呗"], 
  "analyzer": "ik_max_word"
}

运行结果

1691983228927

运行结果

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

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

相关文章

Vue-4.编译器VsCode

准备 Vue-1.零基础学习Vue Vue-2.nodejs的介绍和安装 Vue-3.vue简介 为什么用VsCode VsCode 是Vue官网首推的编译器它是完全免费的 下载安装VsCode 下载地址 安装的时候不停地下一步直到完成即可 安装插件 安装汉化插件 要将 Visual Studio Code&#xff08;VSCode&am…

回归预测 | MATLAB实现基于LSSVM-Adaboost最小二乘支持向量机结合AdaBoost多输入单输出回归预测

回归预测 | MATLAB实现基于LSSVM-Adaboost最小二乘支持向量机结合AdaBoost多输入单输出回归预测 目录 回归预测 | MATLAB实现基于LSSVM-Adaboost最小二乘支持向量机结合AdaBoost多输入单输出回归预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.Matlab实现L…

elasticsearch-head 插件

1、elastic 插件说明 **Head** 是第三方提供的一款很优秀的插件&#xff0c;集监控、查询、配置一体的web功能系统&#xff0c;可以在系统中进行创建、删除索引 、文档。以及查询、配置索引等功能&#xff0c;深受广大开发者的喜爱 **Kopf** 是另一个第三方提供的一款很优秀…

云原生k8s---资源限制、探针

目录 一&#xff1a;资源限制 1、资源限制原因 2、Pod 和 容器 的资源请求和限制 3、CPU 资源单位 4、内存 资源单位 5、事例 &#xff08;1&#xff09;事例一 &#xff08;2&#xff09;事例二 二&#xff1a;重启策略 1、重启策略模式 2、事例 三&#xff1a;探针…

微信小程序实现左滑删除

一、效果 二、代码 实现思路使用的是官方提供的 movable-area&#xff1a;注意点&#xff0c;需要设置其高度&#xff0c;否则会出现列表内容重叠的现象。由于movable-view需要向右移动&#xff0c;左滑的时候给删除控件展示的空间&#xff0c;故 movable-area 需要左移 left:…

视觉学习(七)---Flask 框架下接口调用及python requests 实现json字符串传输

在项目实施过程中需要与其他系统进行接口联调&#xff0c;将图像检测的结果传递给其他系统接口&#xff0c;进行逻辑调用。这中间的过程可以通过requests库进行实现。 1.安装requests库 pip install requests2.postman 接口测试 我们先通过postman 了解下接口调用&#xff0…

linux系统服务学习(二)linux下yum源配置实战

文章目录 Linux下yum源配置实战一、Linux下软件包的管理1、软件安装方式2、源码安装的配置过程3、详解源码安装的配置过程&#xff08;定制&#xff09;4、详解编译过程5、安装过程6、axel多线程下载软件源码安装7、使用软链接解决command not found8、使用环境变量解决command…

springcloud3 hystrix实现服务降级,熔断,限流以及案例配置

一 hystrix的作用 1.1 降级&#xff0c;熔断&#xff0c;限流 1.服务降级&#xff1a; A方案出现问题&#xff0c;切换到兜底方案B&#xff1b; 2.服务熔断&#xff1a;触发规则&#xff0c;出现断电限闸&#xff0c;服务降级 3.服务限流&#xff1a;限制请求数量。 二 案例…

【机器学习5】数据处理(二)Pandas:表格处理

Pandas:表格处理 &#x1f31f;&#x1f31f;Pandas三种数据类型✨✨Series数据结构✨✨ DataFrame数据结构&#x1f319;&#x1f319;DataFrame数据的选取&#x1f315;&#x1f315;DataFrame的构建&#x1f315;&#x1f315;选取多行&#x1f315;&#x1f315;选取某一列…

【广州华锐视点】VR燃气轮机故障判断模拟演练系统

VR燃气轮机故障判断模拟演练系统由广州华锐视点开发&#xff0c;是一款基于虚拟现实技术的教育工具&#xff0c;旨在为学生提供一个安全、高效、互动的学习环境&#xff0c;帮助他们更好地掌握燃气轮机的故障诊断技能。 这款VR实训软件能够模拟真实的燃气轮机故障诊断场景&…

JVM---理解jvm之对象已死怎么判断?

目录 引用计数算法 什么是引用 可达性分析算法&#xff08;用的最多的&#xff09; 引用计数算法 定义&#xff1a;在对象中添加一个引用计数器&#xff0c;每当有一个地方引用它时&#xff0c;计数器值就加一&#xff1b;当引用失效时&#xff0c;计数器值就减一&#xff1…

利用python实现批量登录网络设备进行日常巡检

利用python实现批量登录网络设备 实现ensp与物理机互通ensp 配置配置网络设备远程登录 用python实现批量登录常见问题 通过阅读本文可以学习自动化运维相关知识&#xff0c;本文章代码可以直接使用&#xff0c;通过批量登录功能后&#xff0c;可以按照自己意愿进行功能更改与完…

CentOS7最小化安装使用KVM虚拟化

说明&#xff1a;本文初衷在于记录一次实战经验&#xff0c;以便后续参考&#xff0c;不具有任何权威作用&#xff0c;如若对你有帮助深感荣幸&#xff01; 一、环境安装 CentOS Linux release 7.9.2009 (Core)【不带GUI】Xshell 6Xmanager 6 # 执行 export DISPLAY客户端机器…

MongoDB数据库

目录 一、概述 二、安装 三、目录结构 四、MongoDB数据库操作 五、MongoDB数据库备份 一、概述 mongodb是一个nosql数据库&#xff0c;它有高性能、无模式、文档型的特点。是nosql数据库中功能最丰富&#xff0c;最像关系数据库的。数据库格式为BSON 相关概念 实例&…

计算机网络-物理层(二)- 传输方式

计算机网络-物理层&#xff08;二&#xff09;- 传输方式 串型传输与并行传输 串行传输:是指数据是一个比特一个比特依次发送的&#xff0c;因此在发送端和接收端之间&#xff0c;只需要一条数据传输线路即可 并行传输:是指一次发送n个比特而不是一个比特&#xff0c;因此发送…

电脑ip地址怎么改 ip地址怎么改到别的城市

一、ip地址怎么改到别的城市 1.ip地址怎么改到别的城市&#xff0c;1、重启WIFI路由设备 一般手机或电脑在家或公司上网时都是接入到路由器的WIFI网络,再由路由器分配上网IP地址,如果要更换上网IP那么重启路由器设备后,路由器会向网络运营商进行宽带的重新拨号,此时手机或电脑设…

Gin安装解决国内go 与 热加载

get 方式安装超时问题&#xff0c;国内直接用官网推荐的下面这个命令大概率是安装不成功的 go get -u github.com/gin-gonic/gin 可以在你的项目目录下执行下面几个命令&#xff1a; 比如我的项目在E:\Oproject\zl cmd E:\Oproject\zl>就在目录下执行 go env -w GO111…

推断统计(配对样本t检验)

根据题目我们也可以看出配对样本 t 检验是用来检验两配对正态总体的均值是否存在显著差异的一种假设检验方法&#xff0c;虽然是两组数据但是其来自同一部分个体在两个时间段内的测试数据&#xff0c;是同一部份个体&#xff01; 进行配对样本 t 检验之后也是分别做出原假设和备…

i18n 配置vue项目中英文语言包(中英文转化)

一、实现效果 二、下载插件创建文件夹 2.1 下载cookie来存储 npm install --save js-cookienpm i vue-i18n -S 2.2 封装组件多页面应用 2.3 创建配置语言包字段 三、示例代码 3.1 main.js 引用 i18n.js import i18n from ./lang// 实现语言切换:i18n处理element&#xff0c…

【计算机视觉|生成对抗】改进的生成对抗网络(GANs)训练技术

本系列博文为深度学习/计算机视觉论文笔记&#xff0c;转载请注明出处 标题&#xff1a;Improved Techniques for Training GANs 链接&#xff1a;[1606.03498v1] Improved Techniques for Training GANs (arxiv.org) 摘要 本文介绍了一系列应用于生成对抗网络&#xff08;G…