IK分词器源码改造总结

(注意: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词库相关的日志输出;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值