ik 远程连接 postgres 数据库进行分词热更新

453 阅读3分钟
  1. github.com/medcl/elast… 下载源码,然后解压后倒入 idea ,等待下载相关包,可能需要耗时若干分钟。可能在 pom.xml 文件中有爆红,不用管,不影响编译即可。

  2. 在 org.wltea.analyzer.dic.Dictionary 中的 initial 方法直接用以下代码覆盖

     public static synchronized Dictionary initial(Configuration cfg) {
         if (singleton == null) {
             synchronized (Dictionary.class) {
                 if (singleton == null) {
    
                     singleton = new Dictionary(cfg);
                     singleton.loadMainDict();
                     singleton.loadSurnameDict();
                     singleton.loadQuantifierDict();
                     singleton.loadSuffixDict();
                     singleton.loadPrepDict();
                     singleton.loadStopWordDict();
    
                     pool.scheduleAtFixedRate(new MysqlHotWordMonitor(), 10, 60, TimeUnit.SECONDS);
    
                     if(cfg.isEnableRemoteDict()){
                         // 建立监控线程
                         for (String location : singleton.getRemoteExtDictionarys()) {
                             // 10 秒是初始延迟可以修改的 60是间隔时间 单位秒
                             pool.scheduleAtFixedRate(new Monitor(location), 10, 60, TimeUnit.SECONDS);
    
                         }
                         for (String location : singleton.getRemoteExtStopWordDictionarys()) {
                             pool.scheduleAtFixedRate(new Monitor(location), 10, 60, TimeUnit.SECONDS);
                         }
                     }
                     return singleton;
    
                 }
             }
         }
         return singleton;
     }
    
  3. 同目录下创建 MysqlHotWordMonitor 类,直接复制以下代码,这里连接的是 postgres 数据库,我提前在库里创建了一张 tokens 表,里面有一个 key 字段用来保存分词,代码会将该表中的分词都加载到一个 strings 列表中并返回,应该很好理解。同理这里代码可以改用 mysql 等其他数据库。

    public class MysqlHotWordMonitor implements Runnable{

     private static final Logger logger = ESPluginLoggerFactory.getLogger(Monitor.class.getName());
     private static final String DATABASE_CONF = "database_conf.txt";
    
     public static Map loadConf(){
         Map map = new HashMap<String,String>();
         Path file = PathUtils.get(org.wltea.analyzer.dic.Dictionary.getSingleton().conf_dir.toAbsolutePath().toString(), DATABASE_CONF);
         try (InputStream is = new FileInputStream(file.toFile())) {
             BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"), 512);
             String line = br.readLine();
             while (line!= null && !line.equals("")) {
                String [] words = line.split(": ");
                map.put(words[0], words[1]);
                line = br.readLine();
             }
         } catch (FileNotFoundException e) {
             logger.error("ik-analyzer: not found", e);
         } catch (IOException e) {
             logger.error("ik-analyzer: loading failed", e);
         }
         return map;
     }
    
     static List<String> loadMysqlDict(){
         Statement statement;
         Connection conn;
         List<String> strings  = new ArrayList<>();
         Map<String,String> map = loadConf();
         try {
             Class.forName("org.postgresql.Driver");
             System.out.println("准备!");
             conn = DriverManager.getConnection(String.format("jdbc:postgresql://%s:%s/%s", map.get("host"), map.get("port"),   map.get("database")), map.get("user"), map.get("password"));
             System.out.println("连接 " + map.get("host") + " 服务器中的 " +map.get("database") +" 数据库成功!");
             String sql = "select distinct(key) FROM "+map.get("tableName");
             statement = conn.createStatement();
             ResultSet rs = statement.executeQuery(sql);
             System.out.println("加载 "+map.get("tableName")+" 表中分词");
             while (rs.next()){
                 String word = rs.getString("key");
                 if (word != null && !"".equals(word.trim())) {
                     // 加载扩展词典数据到主内存词典中
                     strings.add(word);
                 }
             }
         }catch (Exception e){
             e.printStackTrace();
             System.out.println("loadMysqlDict 异常");
         }
         return strings;
     }
    
     @Override
     public void run() {
         Statement statement = null;
         Connection conn = null;
         try {
             Dictionary.getSingleton().reLoadMainDict();
         } catch (Exception e) {
             e.printStackTrace();
             System.out.println("run 异常");
         }finally {
             try {
                 if(statement!=null&&!statement.isClosed()){
                     statement.close();
                 }
                 if(conn!=null&&!conn.isClosed()){
                     conn.close();
                 }
             } catch (SQLException e) {
                 e.printStackTrace();
             }
         }
     }
    

    } 4.返回 Dictionary 中,找到 loadMainDict 方法,改为如下代码

     private void loadMainDict() {
     		// 建立一个主词典实例
     		_MainDict = new DictSegment((char) 0);
     
     		// 读取主词典文件
     		Path file = PathUtils.get(getDictRoot(), Dictionary.PATH_DIC_MAIN);
     		loadDictFile(_MainDict, file, false, "Main Dict");
     		// 加载扩展词典
     		this.loadExtDict();
     		// 加载远程自定义词库
     		this.loadRemoteExtDict();
     		// 修改添加加载mysql词库
     		this.loadMysqlDict();
     }
    
  4. 创建一个新的方法 loadMysqlDict ,代码如下

     private void loadMysqlDict() {
     	try {
     		List<String> words = MysqlHotWordMonitor.loadMysqlDict();
     		for (String word : words){
     			_MainDict.fillSegment(word.trim().toLowerCase().toCharArray());
     		}
     	}catch (Exception e){
    
     		e.printStackTrace();
     		System.out.println("loadMysqlDict 异常");
     	}
     }
    
  5. 在 pom.xml 中加入依赖,用到什么数据库就加什么依赖,我这里是 postgres

     <dependency>
         <groupId>org.postgresql</groupId>
         <artifactId>postgresql</artifactId>
         <version>42.2.14</version>
     </dependency>
     
    
  6. 将 plugin.xml 中的

     <includes>
         <include>org.apache.httpcomponents:httpclient</include>
     </includes>
    

    改为

     <includes>
         <include>org.apache.httpcomponents:httpclient</include>
         <include>org.postgresql:postgresql</include>
     </includes>
    
  7. 在 config 下面创建一个文件 database_conf.txt ,内容如下,表示要进行读取的数据库信息。

     host: 数据库 ip
     port: 数据库 端口
     user: 账号
     password: 密码
     database: 数据库名
     tableName: 表名
    
  8. 进行 maven package

  9. 将 releases 目录下面新生成的 的 zip 包解压后生成的文件夹改名为 ik ,放入 /elasticsearch主目录/plugins 下

  10. 将 ik 目录下面的 plugin-descriptor.properties 中最后的 elasticsearch.version 改为自己所使用的 elasticsearch 版本号,要完全一致

  11. (此步骤可选)如果爆 java.security.AccessControlException: access denied ,可以使用该方法进行解决,在 elasticsearch 主目录/jdk/lib/security/default.policy 中的 grant 中加入如下代码

    // 连接数据库
    permission java.net.SocketPermission "*", "connect,resolve";
    

如果不能,则有可能系统使用的是其他路径的 java ,去 %JAVA_HOME%/jre/lib/security/java.policy 中进行相同的操作,重启 es ,如果能够显示代码中需要打印的信息,表示可以正常读取。