项目开发过程中需要在elasticsearch中使用ik分词器实现扩展词库的热更新,ik分词器本身支持将扩展词写入文件中进行读取,通过自己搭建服务器访问文件实现实时获取扩展词词库更新数据,但是由于扩展词数据多,文件读取的方式性能低,所以想通过在mysql中建立扩展词库的数据库表,ik分词器通过读取数据库获得扩展词库数据,并实现热更新。

        环境信息:elasticsearch 8.13.4,jdk17,mysql 8.0.16

        首先从github上下载ik分词器的源码,网址:https://github.com/infinilabs/analysis-ik

在idea中打开源码,更新好maven仓库,代码结构如下图所示。

打开core中java下的Dictionary类,路径如下

添加加载基于Mysql的远程词库的方法loadMySQLExtDict,如下:

private void loadMySQLExtDict(){
    Connection conn = null;
    Statement stmt = null;
    ResultSet rs = null;
    try{
       Path file = configuration.getPath(getDictRoot(), "jdbc-reload.properties");
       prop.load(new FileInputStream(file.toFile()));
       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");
          _MainDict.fillSegment(word.trim().toCharArray());
       }
       Thread.sleep(Long.getLong(prop.getProperty("jdbc.reload.internal")));
    }catch (Exception e){
       logger.error("error:",e);
    }finally {
       try{
          if(rs!=null){
             rs.close();
          }

          if(stmt!=null){
             stmt.close();
          }
       }catch (Exception e){
          logger.error("error in finally is : ",e);
       }

    }

}

在项目的config文件夹中添加数据库配置文件jdbc-reload.properties,目录位置如下:

jdbc-reload.properties内容包含数据库连接url,用户名,密码,查询词库的语句,以及实时访问数据库的时间间隔,具体内容如下:

jdbc.url=jdbc:mysql://localhost:3306/es_dict?serverTimezone=UTC&useSSL=false
jdbc.user=root
jdbc.password=root
jdbc.reload.sql=select word from es_extword
jdbc.reload.internal=1000

loadMySQLExtDict方法中的prop是在Dictionary类中定义的全局变量:

为了获取数据库连接需要加载数据库驱动,在Dictionary类中定义静态类获取:

static{
       try {
           Class.forName("com.mysql.cj.jdbc.Driver");
       } catch (ClassNotFoundException e) {
           throw new RuntimeException(e);
       }
   }

查看Monitor类中的runUnprivileged方法,该方法是ik分词器实时获取远程词库的热更新方法,其中远程词库有更新,需要重新加载词典时,调用了Dictionary.getSingleton().reLoadMainDict();如下:

我们按照这个方式,新建HotDic类,调用该方法,具体如下:

回到Dictionary类中,在loadMainDict方法最后添加调用loadMySQLExtDict方法:

同样在Dictionary类中找到initial方法,在其中添加代码启动HotDict线程:

代码修改完成后,点击项目的pom.xml文件,修改其中elasticsearch的版本号,为自己es的版本号

之后通过maven先clean再package,生成ik分词器jar包

将该压缩文件解压,解压后的文件内容移动至es安装目录下plugins中,替换原有ik文件,

打开文件夹,将mysql驱动器拷贝至该文件夹下

启动ES,此时遇到了各种坑。

问题1:Caused by: java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "setContextClassLoader")
启动后控制台报错,查看logs文件夹下的日志信息,报错如下:

在网上搜了一圈这个问题,是因为jdk有一个安全权限设置,提到的方法基本都是jdk8中jre->lib->security文件夹中有一个java.policy文件,在其中加上

permission java.security.AllPermission;

或者加上 

permission java.lang.RuntimePermission "setContextClassLoader";

参考文章:

https://blog.csdn.net/BLADCS/article/details/119600373

https://blog.51cto.com/u_15952602/6037786

但是我的jdk17中没有jre,我在jdk安装目录中找到lib 其中的security文件夹中没有java.policy,但是有一个default.policy,我在这个文件中添加权限的设置,不生效,我在该目录中新建java.policy文件,并按照文章中所说的添加权限也不生效,

default.policy:

java.policy

上述配置均不生效。

(⭐解决方法)后来在阅读源码时发现elasticsearch模块的resource中有一个plugin-security.policy,目录如下:

在这个文件中grant中添加,

permission java.lang.RuntimePermission "setContextClassLoader"; 再次运行该错误解决。

问题2:java.sql.SQLNonTransientConnectionException: Could not create connection to database server.
Caused by: java.security.AccessControlException: access denied ("java.net.SocketPermission" "127.0.0.1:3306" "connect,resolve")
启动后控制台报错,查看logs文件夹下的日志信息,报错如下:

网上找了一圈基本都是同样在jdk的安全权限文件中增加一条语句:

permission java.net.SocketPermission "127.0.0.1:3306", "connect,resolve";

但是配置之后不生效,包括在前面问题解决方法中提到的plugin-security.policy文件中修改也不生效,最后参考该文章:https://blog.csdn.net/MRzhenglea/article/details/118328651 以及https://blog.csdn.net/goodluck_mh/article/details/92845023

这篇文章中提到了3中解决方法,前两个都是我前面提到的权限配置,我这里都不生效,最后通过第三种方法,解决该问题,在文章的评论区中看到,这段代码意思应该在ik配置中绕过权限认证,(可能理解的不对)具体如下:

(⭐解决方法)在Dictionary类中找到loadMainDict()方法,在原有调用我们自己写的this.loadMySQLExtDict()方法的地方,对代码进行调整如下,

补充:

参考文章:https://blog.csdn.net/BLADCS/article/details/119600373

在elasticsearch模块的assemblies包中plugin.xml中添加如下内容:

错误问题没有记录,我记得是在ik插件中加入mysql的驱动但是没有生效。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐