(注意:mysql 的驱动包放到ik目录下)
1、IK分词器源码下载:
本案例以ES7.9.1和MySql数据库5.1.38+为例进行配置;
修改源码步骤
1、修改maven依赖es版本号
使用工具打开IK源码后,打开pom.xml文件,修改elasticsearch版本号为7.9.1
<elasticsearch.version>7.9.1</elasticsearch.version>
2、引入MySql驱动到项目中
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
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.9.1.zip文件;
安装插件
完成上述步骤后,拿到elasticsearch-analysis-ik-7.9.1.zip插件,我们将其放在ES安装目录下的plugins目录下,新建一个elasticsearch-analysis-ik-7.9.1文件夹,将其解压到elasticsearch-analysis-ik-7.9.1文件夹下;如下
完成上述步骤后,我们就可以启动ES了,在启动过程中,可以看到关于IK热更新MySql词库相关的日志输出;