在前面写过为IK分词器配置远程词库,不过词库没有做成可动态维护的,没有维护到数据库中;在这一期,一起探索一下IK分词器从数据库获取动态词库;

在github上的IK源码描述文件中对远程扩展词库是这样描述的

通过描述可以看到可以通过url的形式请求文件或者是接口,从而实现热更新分词,不需要重启ES实例;

不过在网上看到好像大家都不是很推荐这种方式,说不是很稳定,所以采用网上大家所推荐的方式,修改IK分词器源码轮询查库实现词库热更新;

本案例以ES7.8.0和MySql数据库5.7为例进行配置;

修改源码步骤

1、修改maven依赖es版本号

使用工具打开IK源码后,打开pom.xml文件,修改elasticsearch版本号为7.8.0

7.8.0

2、引入MySql驱动到项目中

mysql

mysql-connector-java

5.1.38

3、开始修改源码

在项目中找到Dictionary类,找到Dictionary单例类的初始化方法initial方法,在初始化方法中我们起一个线程,用来执行远程词库的热更新,再修改之前,我们在Dictionary类同目录下新建一个类HotDictReloadThread,代码如下:

public class HotDictReloadThread {

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

public void initial(){

while (true) {

log.info("正在调用HotDictReloadThread...");

Dictionary.getSingleton().reLoadMainDict();

}

}

}

上述代码的含义为: 获取词典单子实例,并执行它的reLoadMainDict方法;

完成上述操作后,我们就来开始修改initial方法,改动如下图,创建上面新建的类并调用它的initial方法,从而执行Dictionary类的reLoadMainDict方法;改动代码如下,在字典实例初始化完成后新起一个线程来执行字典的热更新操作;

pool.execute(() -> new HotDictReloadThread().initial());

跟着程序一步步走下去,找到Dictionary类的reLoadMainDict方法,可以看到在方面里面,有2个方法tmpDict.loadMainDict()和tmpDict.loadStopWordDict(),分别维护的是扩展词库和停用词库,一块先看一下对扩展词库的维护;

在方法tmpDict.loadMainDict()中,我们在最后一行加载远程自定义词库后面新增一个方法this.loadMySQLExtDict(),用于加载MySql词库,在加载MySql词库之前,我们需先准备一下MySql相关的配置以及sql语句;在数据库中新建一张表,用户维护扩展词和停用词,表结构如下

CREATE TABLE `es_lexicon` (

`lexicon_id` bigint(8) NOT NULL AUTO_INCREMENT COMMENT '词库id',

`lexicon_text` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '词条关键词',

`lexicon_type` int(1) NOT NULL DEFAULT 0 COMMENT '0扩展词库 1停用词库',

`lexicon_status` int(1) NOT NULL DEFAULT 0 COMMENT '词条状态 0正常 1暂停使用',

`del_flag` int(1) NOT NULL DEFAULT 0 COMMENT '作废标志 0正常 1作废',

`create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',

PRIMARY KEY (`lexicon_id`) USING BTREE

) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'ES远程扩展词库表' ROW_FORMAT = Dynamic;

然后我们在项目的根路径的config目录下新建配置文件jdbc-reload.properties,内容如下

# 数据库地址

jdbc.url=jdbc:mysql://127.0.0.1:3306/test?serverTimezone=GMT&autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useAffectedRows=true&useSSL=false

# 数据库用户名

jdbc.user=root

# 数据库密码

jdbc.password=123456

# 数据库查询扩展词库sql语句

jdbc.reload.sql=select gel.lexicon_text as word from es_lexicon gel where gel.lexicon_type = 0 and gel.lexicon_status = 0 and gel.del_flag = 0 order by gel.lexicon_id desc

# 数据库查询停用词sql语句

jdbc.reload.stopword.sql=select gel.lexicon_text as word from ges_lexicon gel where gel.lexicon_type = 1 and gel.lexicon_status = 0 and gel.del_flag = 0 order by gel.lexicon_id desc

# 数据库查询间隔时间 每隔10秒请求一次

jdbc.reload.interval=10

完成了这些基础配置之后,我们再一同看看关于同步MySql词库的方法loadMySQLExtDict();代码较长,粘贴如下

/**

* 从MySql中加载动态词库

*/

private void loadMySQLExtDict() {

Connection conn = null;

Statement stmt = null;

ResultSet rs = null;

try {

Path file = PathUtils.get(getDictRoot(), "jdbc-reload.properties");

props.load(new FileInputStream(file.toFile()));

logger.info("[==========]jdbc-reload.properties");

for(Object key : props.keySet()) {

logger.info("[==========]" + key + "=" + props.getProperty(String.valueOf(key)));

}

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

// Class.forName(props.getProperty("jdbc.className"));

conn = DriverManager.getConnection(

props.getProperty("jdbc.url"),

props.getProperty("jdbc.user"),

props.getProperty("jdbc.password"));

stmt = conn.createStatement();

rs = stmt.executeQuery(props.getProperty("jdbc.reload.sql"));

while(rs.next()) {

String theWord = rs.getString("word");

logger.info("[==========]正在加载Mysql自定义IK扩展词库词条: " + theWord);

_MainDict.fillSegment(theWord.trim().toCharArray());

}

Thread.sleep(Integer.valueOf(String.valueOf(props.get("jdbc.reload.interval"))) * 1000);

} 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);

}

}

}

}

在上述代码中,通过加载配置文件,获取数据库连接,执行扩展词sql,将结果集添加到扩展词库中;

同理,同步MySql停用词的逻辑也是一样的,这里我直接把代码粘贴过来;停用词方法调用顺序为tmpDict.loadStopWordDict(),在方法后面,新增一个方法调用this.loadMySQLStopwordDict(),新方法中处理通用词逻辑,代码如下

/**

* 从MySql中加载远程停用词库

*/

private void loadMySQLStopwordDict() {

Connection conn = null;

Statement stmt = null;

ResultSet rs = null;

try {

Path file = PathUtils.get(getDictRoot(), "jdbc-reload.properties");

props.load(new FileInputStream(file.toFile()));

logger.info("[==========]jdbc-reload.properties");

for(Object key : props.keySet()) {

logger.info("[==========]" + key + "=" + props.getProperty(String.valueOf(key)));

}

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

// Class.forName(props.getProperty("jdbc.className"));

conn = DriverManager.getConnection(

props.getProperty("jdbc.url"),

props.getProperty("jdbc.user"),

props.getProperty("jdbc.password"));

stmt = conn.createStatement();

rs = stmt.executeQuery(props.getProperty("jdbc.reload.stopword.sql"));

while(rs.next()) {

String theWord = rs.getString("word");

logger.info("[==========]正在加载Mysql自定义IK停用词库词条: " + theWord);

_StopWords.fillSegment(theWord.trim().toCharArray());

}

Thread.sleep(Integer.valueOf(String.valueOf(props.get("jdbc.reload.interval"))) * 1000);

} 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);

}

}

}

}

完成这些,整体代码改造完毕;在上述代码中,有很多的地方是可以进一步优化的,比如扩展词和停用词的大量重复代码,以及读取本地配置文件项可以做到只读取一次等,这个大家可以自行优化;

完成了这些之后,我们就可以开始打包插件了;直接使用maven package命令进行打包,在target/releases/elasticsearch-analysis-ik-7.8.0.zip文件,我们将Mysql驱动mysql-connector-java.jar也放到这个压缩包里面;

安装插件

完成上述步骤后,拿到elasticsearch-analysis-ik-7.8.0.zip插件,我们将其放在ES安装目录下的plugins目录下,新建一个ik文件夹,将其解压到ik文件夹下;目录结构大概如下,记得要有MySql驱动mysql-connector-java.jar

完成上述步骤后,我们就可以启动ES了,在启动过程中,可以看到关于IK热更新MySql词库相关的日志输出;在实际过程中,可能会报很多的异常,下面是我所遇到的一些问题以及解决方案;

常见问题

1、异常1:java.sql.SQLException: Column 'word' not found.

此异常是因为编写sql时,查询的数据库字段需要起别名为 word,修改一下sql即可解决这个问题;

2、异常2:Could not create connection to database server

此异常通常是因为引用的mysql驱动和mysql版本号不一致导致的,只需要替换成对应的版本号即可解决,另外,数据库连接我们不需要再额外的去配置显示加载,即不需要写 Class.forName(props.getProperty("jdbc.className"));

3、异常3:no suitable driver found for jdbc:mysql://...

此异常我们需要在环境的JDK安装目录的jre\lib\ext目录下添加mysql驱动mysql-connector-java.jar;比如我本地的是C:\Java\jdk_8u_231\jre\lib\ext 目录,服务器上是/data/jdk1.8.0_181/jre/lib/ext

4、异常4:AccessControlException: access denied ("java.net.SocketPermission" "127.0.0.1:3306" "connect,resolve")

这个异常,我们修改jdk安装路径下的C:\Java\jdk_8u_231\jre\lib\security目录下的文件java.policy,在下面新增一行即可解决

permission java.net.SocketPermission "*", "connect,resolve";

ik分词 动态增加词库 mysql_Elasticsearch7.8.0集成IK分词器改源码实现MySql5.7.2实现动态词库实时更新...相关推荐

  1. 【C 语言】动态库封装与设计 ( 动态库调用环境搭建 | 创建应用 | 拷贝动态库相关文件到源码路径 | 导入头文件 | 配置动态库引用 | 调用动态库中的函数 )

    文章目录 一.在 Visual Studio 2019 中创建 " 控制台应用 " 程序 二.拷贝 xxx.lib.xxx.dll.xxx.h 到源码路径 三.导入 xxx.h 头 ...

  2. GDB 源码分析系列文章五:动态库延迟断点实现机制

    系列文章: GDB 源码分析系列文章一:ptrace 系统调用和事件循环(Event Loop) GDB 源码分析系列文章二:gdb 主流程 Event Loop 事件处理逻辑详解 GDB 源码分析系 ...

  3. chosen.jquery.js 、chosen-select 源码修改控制 chosen:updated 方法动态更新下拉框选项不更新搜索框值 ,chosen 实现远程搜索加载下拉选项

    chosen.jquery.js .chosen-select 源码修改控制 chosen:updated 方法动态更新下拉框选项不更新搜索框值,chosen 实现远程搜索加载下拉选项 chosen. ...

  4. 精仿《问答库》题库问答学习平台网站源码整站源码,帝国CMSv7.5内核,知识付费考试题库

    源码介绍 非常不错的适合做问答和知道类型的网站的源码,帝国cms的内核,优势无需多说了,拿去耍起!! 学历考试等各类题库以及一些常见的普通练习的题目题库供大家查询 特色功能: 1.同步生成 WAP 2 ...

  5. php图片动画源码,JavaScript_jQuery插件ImageDrawer.js实现动态绘制图片动画(附源码下载),ImageDrawer.js是一款可以实现动 - phpStudy...

    jQuery插件ImageDrawer.js实现动态绘制图片动画(附源码下载) ImageDrawer.js是一款可以实现动态绘制图片动画的jQuery插件.通过ImageDrawer.js插件,你可 ...

  6. c# 工业OPC server服务器源码。 该项目是纯源码实现,不依赖于任何第三方opc dll库。 有应用实例。

    c# 工业OPC server服务器源码. 该项目是纯源码实现,不依赖于任何第三方opc dll库. 有应用实例. :73199662231825207FaxNetApi

  7. Elasticsearch 7.X Ik源码解读,及自定义远程动态词库

    一.ik 远程词库 上篇文章对ik进行了整体的讲解,包括远程动态词库的讲解,但是上篇文章中是基于nginx+静态txt文件实现的,利用nginx 对文件修改后自动添加Last-Modified 的属性 ...

  8. Redis源码初探(1)简单动态字符串SDS

    前言 现在面试可太卷了,Redis基本是必问的知识点,为了在秋招中卷过其他人(虽然我未必参加秋招),本菜鸡决定从源码层面再次学习Redis,不过鉴于本菜鸡水平有限,且没有c语言基础,本文不会对源码过于 ...

  9. python生成中文词云的代码_[python] 基于词云的关键词提取:wordcloud的使用、源码分析、中文词云生成和代码重写...

    1. 词云简介 词云,又称文字云.标签云,是对文本数据中出现频率较高的"关键词"在视觉上的突出呈现,形成关键词的渲染形成类似云一样的彩色图片,从而一眼就可以领略文本数据的主要表达意 ...

  10. apollo源码分析 感知_Kitty中的动态线程池支持Nacos,Apollo多配置中心了

    目录 回顾昨日 nacos 集成 Spring Cloud Alibaba 方式 Nacos Spring Boot 方式 Apollo 集成 自研配置中心对接 无配置中心对接 实现源码分析 兼容 A ...

最新文章

  1. 飞书携手生态伙伴法大大 齐心守护健康
  2. vue.js学习系列-第二篇
  3. 【 MATLAB 】DFS 与 z 变换之间的关系
  4. react router 级联路由_前端路由原理解析和实现
  5. Arduino 各种模块篇 步进电机 step motor( 不用库,不用shield, 纯)
  6. 华为2014校园招聘的机试题目
  7. 模板库 | 销售管理类报表,邀您提反馈
  8. boost库在ubuntu下的安装
  9. 计算机管理中添加用户属性,如何在计算机右键菜单栏中添加属性选项
  10. 【LeetCode笔记】剑指 Offer 56 . 数组中数字出现的次数(Java、位运算)
  11. 我的春Phone之行
  12. 创建ros的程序包--3
  13. linux java mysql 乱码_Linux下MySQL的字符集乱码问题总结
  14. 洛谷P2258 子矩阵——题解
  15. Eclipse环境搭建-scala
  16. 数分统计学基础知识框架。
  17. 爬虫练习--爬取CNNVD相关漏洞
  18. 小白 白嫖7天百度云网盘会员,高速下载
  19. opencv3学习笔记(九)--------直方图与匹配
  20. 笔记本硬盘调研 更换及启动盘设置

热门文章

  1. 洛谷P3456 [POI2007]GRZ-Ridges and Valleys
  2. 陆奇如何解构一家企业?
  3. PJzhang:今天才搞清身份证、银行卡……的编码规则
  4. CSS Flexbox布局
  5. 【周六福利来了~】优才安卓公开课:程序员到架构师之路
  6. Windows XP IIS 500错误
  7. deepin 作为日常办公系统
  8. ps把图抠到html里,ps抠图教程:手把手教你如何用ps抠头发丝
  9. itest英语考试bug_iTEST爱考试PC版-iTEST爱考试电脑版下载 v1.2.0--PC6电脑版
  10. Android系统开启蓝牙源码分析(上)