elasticsearch-ik分词器安装及源码修改记录总结

##################ik分词器一些配置解释########################
注:常规安装只需要将打好的包解压到plugins/ik 目录里,然后重启es就好了,无需进行下面的操作
1、ik配置文件

    ik配置文件地址:es/plugins/ik/config目录

    IKAnalyzer.cfg.xml:用来配置自定义词库
    main.dic:ik原生内置的中文词库,总共有27万多条,只要是这些单词,都会被分在一起
    quantifier.dic:放了一些单位相关的词
    suffix.dic:放了一些后缀
    surname.dic:中国的姓氏
    stopword.dic:英文停用词

    ik原生最重要的两个配置文件

    main.dic:包含了原生的中文词语,会按照这个里面的词语去分词
    stopword.dic:包含了英文的停用词

2、自定义词库

(1)自己建立词库:每年都会涌现一些特殊的流行词,网红,蓝瘦香菇,喊麦,鬼畜,一般不会在ik的原生词典里

    自己补充自己的最新的词语,到ik的词库里面去

    IKAnalyzer.cfg.xml:ext_dict,custom/mydict.dic

    补充自己的词语,然后需要重启es,才能生效

(2)自己建立停用词库:比如了,的,啥,么,我们可能并不想去建立索引,让人家搜索

custom/ext_stopword.dic,已经有了常用的中文停用词,可以补充自己的停用词,然后重启es

#################################调整及修改ik分词器############################################
热更新

每次都是在es的扩展词典中,手动添加新词语,很坑
(1)每次添加完,都要重启es才能生效,非常麻烦
(2)es是分布式的,可能有数百个节点,你不能每次都一个一个节点上面去修改

es不停机,直接我们在外部某个地方添加新的词语,es中立即热加载到这些新词语

热更新的方案
(1)修改ik分词器源码,然后手动支持从mysql中每隔一定时间,自动加载新的词库
(2)基于ik分词器原生支持的热更新方案,部署一个web服务器,提供一个http接口,通过modified和tag两个http响应头,来提供词语的热更新
用第一种方案,第二种,ik git社区官方都不建议采用

1、下载源码

https://github.com/medcl/elasticsearch-analysis-ik/tree/v5.2.0

ik分词器,是个标准的java maven工程,直接导入eclipse就可以看到源码

2、修改源码

3、mvn package打包代码

target\releases\elasticsearch-analysis-ik-5.2.0.zip

4、解压缩ik压缩包,并将mysql驱动jar,放入ik的目录下

5、修改jdbc相关配置

6、重启es

7、在mysql中添加词库与停用词

8、分词实验,验证热更新生效


############################ik分词器源码修改过程##############################

1、定义jdbc连接配置:jdbc-reload.properties
jdbc.url=jdbc:mysql://localhost:3306/test?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

2、在 org.wltea.analyzer.dic 路径中定义热加载线程类
public class HotDictReloadThread implements Runnable {

    private static final Logger logger = ESLoggerFactory.getLogger(HotDictReloadThread.class.getName());
    
    @Override
    public void run() {
        while(true) {
            logger.info("==========>>reload hot dict from mysql......");
            Dictionary.getSingleton().reLoadMainDict();
            try {
                Thread.sleep(100000);
            } catch (InterruptedException e) {
                logger.warn(e.fillInStackTrace());
                e.printStackTrace();
            }
        }
    }

3、在 org.wltea.analyzer.dic.Dictionary中的 initial 方法中启动线程

    singleton = new Dictionary(cfg);
    singleton.loadMainDict();
    singleton.loadSurnameDict();
    singleton.loadQuantifierDict();
    singleton.loadSuffixDict();
    singleton.loadPrepDict();
    singleton.loadStopWordDict();
    #开启位置
    new Thread(new HotDictReloadThread()).start(); //线程启动
    
4、在 org.wltea.analyzer.dic.Dictionary中的 loadMainDict 最下方添加:
    // 从mysql加载词典
    this.loadMySQLExtDict();
    
5、在 loadMainDict 方法下添加如下方法(读取MySQL数据):
    private static Properties prop = new Properties();
    
    static {
        try {
            Class.forName("com.mysql.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);
                }
            }
        }
    }

6、在loadStopWordDict方法中添加(停用词加载方法):
    this.loadMySQLStopwordDict();
7、紧随其后添加MySQL读取停用词的方法:

        /**
     * 从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);
                }
            }
        }
   

你可能感兴趣的:(技术文档)