文章目录

  • 概述
  • 热更新方案
  • IK Github 下载Source Code
  • 导入maven工程
  • 修改源码
    • Dictionary#initial方法中开启扫描线程
    • HotDictReloadThread
    • 配置文件 jdbc-reload.properties
    • Dictionary#iloadMainDict 自定义从mysql加载主词典
    • Dictionary#loadStopWordDict自定义从mysql加载停止词词典
  • 编译
  • 将zip解压到 es ik插件目录下
  • 添加mysql依赖包
  • mysql建表语句
  • 重启ES
  • 验证热加载
    • 热加载主词典
    • 热加载停用词词典
  • 遇到的问题 及解决办法
    • 问题:java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "setContextClassLoader")
    • 解决办法
  • 编译后的资源


概述

继续跟中华石杉老师学习ES,第30篇

课程地址: https://www.roncoo.com/view/55

白话Elasticsearch28-IK中文分词器的安装和使用
白话Elasticsearch29-IK分词器配置文件+自定义词库

上面两篇学习了如何安装IK以及基本的使用,当我们使用自定义词库的时候,是不是每次都得重启,而且得逐个节点依次修改,是不是有点不方便呢?

主要缺点:

  • 每次添加完,都要重启es才能生效,非常麻烦
  • es是分布式的,如果有数百个节点…

热更新方案

常用的有两种方式

  • 修改ik分词器源码,然后手动支持从mysql中每隔一定时间,自动加载新的词库
  • 基于ik分词器原生支持的热更新方案,部署一个web服务器,提供一个http接口,通过modified和tag两个http响应头,来提供词语的热更新

推荐第一种方案修改ik分词器源码, 第二种方案ik git社区官方都不建议采用,不太稳定。

既然说到了要修改源码,那接着来吧,到ik的GitHub上下载源码


IK Github 下载Source Code

https://github.com/medcl/elasticsearch-analysis-ik/releases/tag/v6.4.1

找到对应ES版本的IK,下载源码 ,这里我是用的是6.4.1版本的ES 。


导入maven工程

导入maven,这里就不细说了,很简单。 导入完成后,一个标准的maven工程就呈现在你的面前了。


修改源码

简单说下整体思路: 开启一个后台线程,扫描mysql中定义的表,加载数据。

Dictionary#initial方法中开启扫描线程

// Step1.开启新的线程重新加载词典
new Thread(new HotDictReloadThread()).start();


HotDictReloadThread

死循环,调用Dictionary.getSingleton().reLoadMainDict(),重新加载词典

package org.wltea.analyzer.dic;import org.apache.logging.log4j.Logger;
import org.elasticsearch.common.logging.ESLoggerFactory;public class HotDictReloadThread implements Runnable {private static final Logger logger = ESLoggerFactory.getLogger(HotDictReloadThread.class.getName());@Overridepublic void run() {while(true) {logger.info("[==========]reload hot dict from mysql......");   Dictionary.getSingleton().reLoadMainDict();}}}

那看下 reLoadMainDict 干了啥吧

两件事儿,加载主词库 和 停用词词库 ,那我们就把自定义的mysql部分分别放到这两个方法里就OK了。


配置文件 jdbc-reload.properties

配置文件 jdbc-reload.properties

jdbc-reload.properties

jdbc.url=jdbc:mysql://localhost:3306/ik?serverTimezone=GMT
jdbc.user=root
jdbc.password=root
jdbc.reload.sql=select word from hot_words
jdbc.reload.stopword.sql=select stopword as word from hot_stopwords
jdbc.reload.interval=1000

reload间隔,1秒轮训一次 。


Dictionary#iloadMainDict 自定义从mysql加载主词典

 // Step2 从mysql加载词典this.loadMySQLExtDict();

加载自定义的db配置文件,通过JDBC查询mysql ,就是这么简单

 private static Properties prop = new Properties();static {try {//Class.forName("com.mysql.jdbc.Driver");Class.forName("com.mysql.cj.jdbc.Driver");} catch (ClassNotFoundException e) {logger.error("error", e);}}/*** 从mysql加载热更新词典*/private void loadMySQLExtDict() {Connection conn = null;Statement stmt = null;ResultSet rs = null;try {Path file = PathUtils.get(getDictRoot(), "jdbc-reload.properties");   prop.load(new FileInputStream(file.toFile()));logger.info("[==========]jdbc-reload.properties");for(Object key : prop.keySet()) {logger.info("[==========]" + key + "=" + prop.getProperty(String.valueOf(key)));      }logger.info("[==========]query hot dict from mysql, " + prop.getProperty("jdbc.reload.sql") + "......");  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 theWord = rs.getString("word"); logger.info("[==========]hot word from mysql: " + theWord); _MainDict.fillSegment(theWord.trim().toCharArray());}Thread.sleep(Integer.valueOf(String.valueOf(prop.get("jdbc.reload.interval"))));   } 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); }}}}

Dictionary#loadStopWordDict自定义从mysql加载停止词词典

// Step3  从mysql加载停用词
this.loadMySQLStopwordDict();

/*** 从mysql加载停用词*/private void loadMySQLStopwordDict() {Connection conn = null;Statement stmt = null;ResultSet rs = null;try {Path file = PathUtils.get(getDictRoot(), "jdbc-reload.properties");   prop.load(new FileInputStream(file.toFile()));logger.info("[==========]jdbc-reload.properties");for(Object key : prop.keySet()) {logger.info("[==========]" + key + "=" + prop.getProperty(String.valueOf(key)));      }logger.info("[==========]query hot stopword dict from mysql, " + prop.getProperty("jdbc.reload.stopword.sql") + "......");  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.stopword.sql"));  while(rs.next()) {String theWord = rs.getString("word"); logger.info("[==========]hot stopword from mysql: " + theWord); _StopWords.fillSegment(theWord.trim().toCharArray());}Thread.sleep(Integer.valueOf(String.valueOf(prop.get("jdbc.reload.interval"))));   } 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); }}}}

编译

项目右键–Run As --Maven Build —> clean package

编译成功后,去获取zip文件


将zip解压到 es ik插件目录下


添加mysql依赖包

我本地的mysql是 8.0.11版本的

放到ik目录下


mysql建表语句

/*
Navicat MySQL Data TransferSource Server         : localhost_root
Source Server Version : 80011
Source Host           : localhost:3306
Source Database       : ikTarget Server Type    : MYSQL
Target Server Version : 80011
File Encoding         : 65001Date: 2019-08-20 23:35:18
*/SET FOREIGN_KEY_CHECKS=0;-- ----------------------------
-- Table structure for `hot_stopwords`
-- ----------------------------
DROP TABLE IF EXISTS `hot_stopwords`;
CREATE TABLE `hot_stopwords` (`id` int(11) NOT NULL AUTO_INCREMENT,`stopword` longtext COLLATE utf8mb4_general_ci,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;-- ----------------------------
-- Records of hot_stopwords
-- ------------------------------ ----------------------------
-- Table structure for `hot_words`
-- ----------------------------
DROP TABLE IF EXISTS `hot_words`;
CREATE TABLE `hot_words` (`id` int(11) NOT NULL AUTO_INCREMENT,`word` longtext COLLATE utf8mb4_general_ci,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

重启ES

启动日志


成功


验证热加载

热加载主词典

我们先看下IK默认的配置文件 ,我们并没有修改过。

使用 ik_max_word 来看下 IK的 对 “盘他”的分词

插入一条数据

INSERT INTO `hot_words` VALUES ('1', '盘他');

查看es elasticsearch.log的日志

可以看到加载成功,那重新来查看下分词


不会被IK分词了,成功。


热加载停用词词典

我们把“啥”作为停用词,添加到mysql的停用词表中

INSERT INTO `hot_stopwords` VALUES ('1', '啥');

查看es elasticsearch.log日志

重新执行分词测试

可以看到“啥”已经不会被IK当做分词了,成功。


遇到的问题 及解决办法

问题:java.security.AccessControlException: access denied (“java.lang.RuntimePermission” “setContextClassLoader”)

[2019-08-20T22:32:43,444][INFO ][o.e.n.Node               ] [aQ19O09] starting ...
[2019-08-20T22:32:46,133][INFO ][o.e.t.TransportService   ] [aQ19O09] publish_address {127.0.0.1:9300}, bound_addresses {127.0.0.1:9300}, {[::1]:9300}
[2019-08-20T22:32:49,435][INFO ][o.e.c.s.MasterService    ] [aQ19O09] zen-disco-elected-as-master ([0] nodes joined)[, ], reason: new_master {aQ19O09}{aQ19O095TZmH9VHKNHC1qw}{PjHRPar4TV2JQ-iy-bWIoA}{127.0.0.1}{127.0.0.1:9300}{ml.machine_memory=10614976512, xpack.installed=true, ml.max_open_jobs=20, ml.enabled=true}
[2019-08-20T22:32:49,442][INFO ][o.e.c.s.ClusterApplierService] [aQ19O09] new_master {aQ19O09}{aQ19O095TZmH9VHKNHC1qw}{PjHRPar4TV2JQ-iy-bWIoA}{127.0.0.1}{127.0.0.1:9300}{ml.machine_memory=10614976512, xpack.installed=true, ml.max_open_jobs=20, ml.enabled=true}, reason: apply cluster state (from master [master {aQ19O09}{aQ19O095TZmH9VHKNHC1qw}{PjHRPar4TV2JQ-iy-bWIoA}{127.0.0.1}{127.0.0.1:9300}{ml.machine_memory=10614976512, xpack.installed=true, ml.max_open_jobs=20, ml.enabled=true} committed version [1] source [zen-disco-elected-as-master ([0] nodes joined)[, ]]])
[2019-08-20T22:32:49,685][ERROR][o.e.b.ElasticsearchUncaughtExceptionHandler] [] fatal error in thread [elasticsearch[aQ19O09][generic][T#4]], exiting
java.lang.ExceptionInInitializerError: nullat java.lang.Class.forName0(Native Method) ~[?:1.8.0_161]at java.lang.Class.forName(Class.java:264) ~[?:1.8.0_161]at com.mysql.cj.jdbc.NonRegisteringDriver.<clinit>(NonRegisteringDriver.java:106) ~[?:?]at java.lang.Class.forName0(Native Method) ~[?:1.8.0_161]at java.lang.Class.forName(Class.java:264) ~[?:1.8.0_161]at org.wltea.analyzer.dic.Dictionary.<clinit>(Dictionary.java:117) ~[?:?]at org.wltea.analyzer.cfg.Configuration.<init>(Configuration.java:40) ~[?:?]at org.elasticsearch.index.analysis.IkTokenizerFactory.<init>(IkTokenizerFactory.java:15) ~[?:?]at org.elasticsearch.index.analysis.IkTokenizerFactory.getIkSmartTokenizerFactory(IkTokenizerFactory.java:23) ~[?:?]at org.elasticsearch.index.analysis.AnalysisRegistry.buildMapping(AnalysisRegistry.java:377) ~[elasticsearch-6.4.1.jar:6.4.1]at org.elasticsearch.index.analysis.AnalysisRegistry.buildTokenizerFactories(AnalysisRegistry.java:191) ~[elasticsearch-6.4.1.jar:6.4.1]at org.elasticsearch.index.analysis.AnalysisRegistry.build(AnalysisRegistry.java:158) ~[elasticsearch-6.4.1.jar:6.4.1]at org.elasticsearch.index.IndexService.<init>(IndexService.java:162) ~[elasticsearch-6.4.1.jar:6.4.1]at org.elasticsearch.index.IndexModule.newIndexService(IndexModule.java:383) ~[elasticsearch-6.4.1.jar:6.4.1]at org.elasticsearch.indices.IndicesService.createIndexService(IndicesService.java:475) ~[elasticsearch-6.4.1.jar:6.4.1]at org.elasticsearch.indices.IndicesService.verifyIndexMetadata(IndicesService.java:547) ~[elasticsearch-6.4.1.jar:6.4.1]at org.elasticsearch.gateway.Gateway.performStateRecovery(Gateway.java:127) ~[elasticsearch-6.4.1.jar:6.4.1]at org.elasticsearch.gateway.GatewayService$1.doRun(GatewayService.java:223) ~[elasticsearch-6.4.1.jar:6.4.1]at org.elasticsearch.common.util.concurrent.ThreadContext$ContextPreservingAbstractRunnable.doRun(ThreadContext.java:723) ~[elasticsearch-6.4.1.jar:6.4.1]at org.elasticsearch.common.util.concurrent.AbstractRunnable.run(AbstractRunnable.java:37) ~[elasticsearch-6.4.1.jar:6.4.1]at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[?:1.8.0_161]at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[?:1.8.0_161]at java.lang.Thread.run(Thread.java:748) [?:1.8.0_161]
Caused by: java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "setContextClassLoader")at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472) ~[?:1.8.0_161]at java.security.AccessController.checkPermission(AccessController.java:884) ~[?:1.8.0_161]at java.lang.SecurityManager.checkPermission(SecurityManager.java:549) ~[?:1.8.0_161]at java.lang.Thread.setContextClassLoader(Thread.java:1474) ~[?:1.8.0_161]at com.mysql.cj.jdbc.AbandonedConnectionCleanupThread$1.newThread(AbandonedConnectionCleanupThread.java:56) ~[?:?]at java.util.concurrent.ThreadPoolExecutor$Worker.<init>(ThreadPoolExecutor.java:619) ~[?:1.8.0_161]at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:932) ~[?:1.8.0_161]at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1367) ~[?:1.8.0_161]at java.util.concurrent.Executors$DelegatedExecutorService.execute(Executors.java:668) ~[?:1.8.0_161]at com.mysql.cj.jdbc.AbandonedConnectionCleanupThread.<clinit>(AbandonedConnectionCleanupThread.java:60) ~[?:?]... 23 more

解决办法

Java 安全权限导致的异常。

找到ES使用的JDK,这里我使用的是 1.8.0_161

java version "1.8.0_161"
Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)

找到安装目录–>进入 jre\lib\security 目录

比如我本地的 E:\Program Files\Java\jdk1.8.0_161\jre\lib\security ,找到 java.policy ,在 grant最后一行加入 permission java.security.AllPermission; ,然后重启ES ,即可解决


编译后的资源

如果你的觉的麻烦,可以用我编译好的zip包 ,戳这里

白话Elasticsearch30-IK中文分词之热更新IK词库相关推荐

  1. Kafka:ZK+Kafka+Spark Streaming集群环境搭建(十九)ES6.2.2 安装Ik中文分词器

    注: elasticsearch 版本6.2.2 1)集群模式,则每个节点都需要安装ik分词,安装插件完毕后需要重启服务,创建mapping前如果有机器未安装分词,则可能该索引可能为RED,需要删除后 ...

  2. 玩转ES,一文教你掌握IK中文分词器

    前言 ES默认的分词器对中文分词并不友好,所以我们一般会安装中文分词插件,以便能更好的支持中文分词检索. 而ES的中文分词器中,最流行的必然是IK分词器. 一.IK分词器介绍 IK分词器在是一款基于词 ...

  3. python连接es_Elasticsearch --- 3. ik中文分词器, python操作es

    一.IK中文分词器 1.下载安装 2.测试 #显示结果 {"tokens": [ {"token" : "上海","start_o ...

  4. elasticsearch 5.6.x单机环境构建(集成head插件和IK中文分词)

    elasticsearch近几年版本更新迭代的速度之已经超出了我的想象,想着我2016,2017年还在用着2.4.x版本,最近几年直接5.x,6.x,7.x版本了,看了一下下更新迭代的小版本时间几乎几 ...

  5. Solr7.2.1环境搭建和配置ik中文分词器

    solr7.2.1环境搭建和配置ik中文分词器 安装环境:Jdk 1.8. windows 10 安装包准备: solr 各种版本集合下载:http://archive.apache.org/dist ...

  6. ES7 IK中文分词器

    IK中文分词器的安装 ES默认是没有IK中文分词器的,我们要将IK中文分词器作为一个插件安装到ES中,安装的步骤也很简单: 从GitHub上下载适合自己ES版本的IK中文分词器,地址如下:https: ...

  7. 分词器以及ik中文分词器

    文章目录 分词器以及ik中文分词器 概念 ik分词器的安装 环境准备 设置jdk环境变量 下载maven安装包并解压 设置path 验证maven是否安装成功 下载IK分词器并安装 使用IK分词器 查 ...

  8. 学习 ES 的笔记、全文检索、倒排索引、Lucene、ik中文分词器、Kibana使用Dev Tools

    文章目录 感悟 新接触的单词 知识点一:ES是什么? 知识点二:ES基本概念 知识点三:1.1 什么是全文检索和Lucene? 知识点四:1.2 什么是倒排索引,Lucene实现全文检索的流程是怎样? ...

  9. 使用Docker快速安装部署ES和Kibana并配置IK中文分词器以及自定义分词拓展词库

    使用Docker快速安装部署ES和Kibana的前提:首先需要确保已经安装了Docker环境 如果没有安装Docker的话,可以参考上一篇的内容:Linux上安装Docker 有了Docker环境后, ...

最新文章

  1. Java从入门到精通——数据库篇之JAVA中的对Oracle数据库操作
  2. Android EditText 修改提示字体的大小
  3. Java System.getProperty()
  4. [转] SQL Server中各个系统表的作用
  5. python中可迭代对象,迭代器,生成器的区别和联系
  6. Java之常用函数笔记
  7. python2中文乱码
  8. labview温度报警系统
  9. 【MM32F5270开发板试用】一、移植 TencentOS 到 PLUS-F5270
  10. CAD中PDF转DWG
  11. ai中如何插入签名_如何在PDF文档中插入文本框?
  12. Deepin 手动安装显卡驱动
  13. linux scp 输入密码,scp 在脚本中使用输入密码的解决方法
  14. python分时间段统计_Python Pandas:按日期分组并统计每个时段的新记录
  15. word文档找不到smartart_word2003SmartArt在哪里
  16. r语言c(1 6),R语言(1)
  17. 什么牌子的千兆网卡好用_不挑次的只挑好的 台式机千兆网卡应该买哪些?
  18. 从Internet说起
  19. HDU - 4540 威威猫系列故事——打地鼠
  20. 怎么让mysql支持全球语言_mysql 多语言编码

热门文章

  1. Linux下CMake简明教程(九) 添加控制选项
  2. sql sum嵌套查询+ group by
  3. sql select
  4. threadlocal内存泄露_ThreadLocal 简介
  5. 72. Leetcode 99. 恢复二叉搜索树 (二叉搜索树-中序遍历类)
  6. 文巾解题 283. 移动零
  7. GNN笔记:图信号处理(Graph Signal Processing)
  8. GNN笔记:傅里叶变换
  9. 深度学习应用实战案例-员工流失预测模型(Python源代码)
  10. ubuntu常见错误--could not get lock /var/lib/dpkg/lock -open