Elasticsearch7.10.0集成IK相关性同义词改源 码实现MySql5.7.2实现远程动态同义词词库实 时更新□

    在前⾯章节中有实践过将ElasticSearch集成Ik分词器,并通过修改IK分词器源码的⽅式,从⽽实
    现MySql远程词库的更新;并在实际使⽤过程中,在集群中的问题进⾏改进,增加版本号的⽅式解决 集群环境IK分词器词库⽣效问题;请参考□

    Elasticsearch7.8.0集成IK分词器改源码实现MySql5.7.2实现动态词库实时更新
    在前⾯写过为IK分词器配置远程词库,不过词库没有做成可动态维护的,没有维护到数据库中;在这⼀期,⼀ 起探索⼀下IK分词器从数据库获取动态词库;□在github上的IK源码描述⽂件中对远程扩展词库是这样描述的□…
    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图1https://zhuanlan.zhihu.com/p/268169068

    在实际搜索场景中,常常会感觉搜索引擎似乎不是很懂我们;⽐如我想搜”苹果”,我期待也可以
    搜索出”iphone”相关的内容,搜索”理想”还可以给我召回”理想汽⻋”相关的内容;□

    在ES中我们可以通过⾃定义分词器来实现这样的效果,并且在ES中有很多种⽅式可以来维护这个
    同义词;(请先在ES中安装好IK分词器插件)□

    ⽅式⼀:创建mapping时指定同义词□
    顾名思义,即在创建ES的Mapping结构的时候,将同义词维护到Mapping中,如下□

    JSON
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    PUT synonyms_index
    {
    “settings”: {
    “number_of_shards”: 1,
    “number_of_replicas”: 0,
    “index”: {
    “analysis”: {
    “filter”: {
    “doc_synonym”: {
    “type”: “synonym”,
    “synonyms”: [“苹果,iphone,ipad”,”理想,理想汽⻋”]
    }
    },
    “analyzer”: {
    “my_doc_syno”: {
    “type”: “custom”,
    “tokenizer”: “ik_smart”,
    “filter”: [
    “doc_synonym”
    ]
    }
    }
    }
    }
    },
    “mappings”: {
    “properties”: {
    “name”: {
    “type”: “text”,
    “analyzer”: “my_doc_syno”
    }
    }
    }
    }

    如上所述,在上述DSL语句中在创建Mapping的时候在settings中⼿动创建⼀个过滤器,在过滤器
    中定义同义词组,然后再定义⼀个分词器,名字可以⾃⼰⾃定义,指定⼀个编译器,然后指定采⽤上 ⾯创建的过滤器;

    然后再在mappings中定义字段,指定字段的分词器为我们⾃⼰创建的分词器;□

    完成上述步骤后,可以开始测试上述添加的同义词是否⽣效

    VBScript
    GET synonyms_index/_analyze
    {
    “field”: “name”,
    “text”: “苹果,理想”
    }

    执⾏效果如下,和预期的效果是⼀致的;

    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图2

    ⽅式⼆:创建同义词⽂本维护同义词□
    在上⾯的这种⽅式中,由于同义词需要在Mapping创建的时候进⾏维护,所以维护成本极⾼,每
    次维护基本上都需要重新定义Mapping结构,不具备扩展性;□
    所以需要进⾏改造⼀下,我们可以在服务器上定义⼀个⽂本⽂件,将同义词维护在⽂本⽂件中,
    这样每次需要增删改同义词时,只需要将⽂本中的内容修改⼀下即可;
    ⾸先,在ES的安装⽬录下的config⽬录下新建⽂件□synonyms.txt,然后在⽂本中加⼊同义词如下□
    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图3ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图4

    JSON
    1
    2
    苹果,iphone,ipad 理想,理想汽⻋

    完成上述步骤后,我们再来重新定义Mapping结构,如下□

    Prolog
    PUT synonyms_index
    {
    “settings”: {
    “number_of_shards”: 1,
    “number_of_replicas”: 0,
    “analysis”: {
    “filter”: {
    “local_doc_filter”: {
    “type”: “synonym”,
    “synonyms_path”: “synonyms.txt”
    }
    },
    “analyzer”: {
    “ik_syno”: {
    “type”: “custom”,
    “tokenizer”: “ik_smart”,
    “filter”: [
    “local_doc_filter”
    ]
    }
    }
    }
    },
    “mappings”: {
    “properties”: {
    “name”: {
    “type”: “text”,
    “analyzer”: “ik_syno”
    }
    }
    }
    }

    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图5ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图6在上述DSL语句中,通过⾃定义过滤器指定同义词⽂件地址;⼀样的,通过DSL语句验证⼀下当
    前配置是否⽣效;
    可以看到,这种⽅式⽅式和前⾯的⽅式获得的效果是⼀样的。相⽐较上⼀种⽅式,可扩展性好了
    很多。不过这种⽅式还是有很明显的缺陷,那就是当⽂件⾥⾯的内容发⽣变化时,ES不会主动触发去 加载新的数据,每次需要重启ES或者是重新创建Mapping结构才会触发效果;

    ⽅式三:采⽤analysis-dynamic-synonym插件□
    同IK分词器⼀样,有⽹友基于elasticsearch-analysis-ik插件源码的基础上写了⼀个ES同义词的插
    件;和IK分词器⼀样,扩展了本地⽂件词库和远程⽂件词库以及远程rest动态接⼝词库;源码地址为□

    bells/elasticsearch-analysis-dynamic-synonym
    The□dynamic□synonym□plugin□adds□a□synonym□token□filter□that□reloads□the□synonym□file(local□file□or remote□file)□at□given□intervals□(default□60s).□-□bells/elasticsearch-analysis-dynamic-synonym
    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图7https://github.com/bells/elasticsearch-analysis-dynamic-synonym

    ⾥⾯有很多代码和IK分词器源码⾥的代码是⼀样的;通过github上可以看到,只需要将源码下载
    下来编码后拷⻉到ES安装⽬录下的plugins/dynamic-synonym⽬录下解压即可;□

    不同的是,使⽤dynamic-synonym插件的情况下,如果采⽤服务器⽂件的⽅式,当服务器⽂件的
    内容发⽣变化时,则会触发⾃动更新;插件会读取⽂件的更新时间来判断是否需要进⾏同义词更新;
    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图8ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图9ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图10

    远程动态同义词调⽤接⼝代码可参考
    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图11ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图12

    TypeScript
    @GetMapping(“/synonym”)
    public String synonym (HttpServletRequest request, HttpServletResponse response)
    {
    String result = “”;
    String eTag = request.getHeader(“If-None-Match”);
    Long eTagVersion = request.getHeader(“If-Modified-Since”) == null ? -1L :
    Long.parseLong(request.getHeader(“If-Modified-Since”));
    // 读取数据库,获取数据库中当前同义词版本号 (在数据库中维护⼀个版本号,当同义词变更
    时,变更它)
    Long dbVersion = synonymVersionMapper.queryVersion();
    if (dbVersion > eTagVersion){
    List docList = synonymListMapper.querySynonymList();
    StringBuilder words = new StringBuilder();
    for (String doc : docList) {
    words.append(doc);
    words.append(System.getProperty(“line.separator”));
    }
    eTagVersion = dbVersion;
    result = words.toString();
    }
    //更新时间
    response.setHeader(“ETag”, eTag);
    response.setHeader(“Last-Modified”, eTagVersion + “”);
    response.setHeader(“Content-Type”, “text/plain”);
    return result;
    }

    这样,我们再定义Mapping结构如下所⽰□
    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图13ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图14

    Prolog
    PUT synonyms_index
    {
    “settings”: {
    “number_of_shards”: 1,
    “number_of_replicas”: 0,
    “index”: {
    “analysis”: {
    “filter”: {
    “local_synonym”: {
    “type”: “dynamic_synonym”,
    “synonyms_path”: “synonyms.txt”,
    “interval”: 30
    },
    “synonym_graph”: {
    “type”: “dynamic_synonym_graph”,
    “synonyms_path”: “http://127.0.0.1:8080/synonym“,
    “interval”: 30
    }
    },
    “analyzer”: {
    “synonym”: {
    “tokenizer”: “ik_smart”,
    “filter”: [
    “synonym_graph”
    ]
    }
    }
    }
    }
    }
    }

    通过上述⽅式的定义,当服务器上的⽂件synonyms.txt发⽣变化时,插件每30秒去查询⼀次,当
    发现⽂件有变化时,则进⾏重新同步同义词;我这边在本地已测试且已⽣效。

    远程接⼝的⽅式也是⼀样的;这种⽅式我在本地还没有经过测试,只是写了上述的伪代码;

    由于远程动态同义词词库需要依赖应⽤程序,所以在考虑是否有更优雅的⽅式,可以让插件⾃⼰
    去访问数据库,从⽽实现⾃主更新;于是可以参考⼀下第四种⽅式。
    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图15ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图16

    ⽅式四:改造analysis-dynamic-synonym源码访问远程数据库□
    接下来我们⼀起对dynamic-synonym插件源码改造,使其⽀持⾃⼰访问数据库,读取数据库中的
    同义词,从⽽实现词库实时⽣效;
    ⾸先,先从github上下载dynamic-synonym源码到本地,使⽤编译器打开;□

    通过pom⽂件可以看到,当前最新的master分⽀的代码⽀持的ES版本是7.7.0,理论上应该也是
    ⽀持ES7.10.0版本的;不过咱们可以修改⼀下,将其修改为7.10.0版本;□

    修改完成后重新编译,此时会发现在代码DynamicSynonymTokenFilterFactory类中有开始报
    错,是⽇志相关的;可以把报错的两⾏代码注释掉,不影响代码逻辑;

    PHP
    1
    2

    3
    4
    5

    6
    // private static final DeprecationLogger DEPRECATION_LOGGER
    // = new
    DeprecationLogger(LogManager.getLogger(DynamicSynonymTokenFilterFactory.class)); 和
    // DEPRECATION_LOGGER.deprecated(
    // “The ignore_case option on the synonym_graph filter is
    deprecated. “ +
    // “Instead, insert a lowercase filter in the filter chain
    before the synonym_graph filter.”);

    ⼤概看了⼀下代码,发现和ik分词器插件中的代码很多都⽐较相似,特别是RemoteSynonymFile
    类和□ik源码中的Dictionary类尤为相似;□

    在dynamic-synonym插件代码中有⼀个接⼝是□SynonymFile,这个接⼝为我们提供了扩展性,
    ⾥⾯有两个实现,分别是LocalSynonymFile类和RemoteSynonymFile类,其作⽤分别是读取本地⽂
    件获取同义词数据□和□请求远程同义词数据的;□
    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图17ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图18基于这⼀特性,我们可以新增⼀个类MySqlRemoteSynonymFile实现SynonymFile接⼝并重新其
    ⽅法;代码结构如下

    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图19

    读取远程数据库资源,我们在项⽬的跟⽬录下新建⼀个⽂件夹config,新建数据库配置⽂件jdbc-
    reload.properties,配置如下□

    SQL
    1


    2
    3
    4
    5

    6
    7
    jdbc.url=jdbc:mysql://127.0.0.1:13306/test?
    serverTimezone=GMT&autoReconnect=true&useUnicode=true&characterEncoding=utf8&zer oDateTimeBehavior=convertToNull&useAffectedRows=true&useSSL=false
    jdbc.user=root
    jdbc.password=123456
    # 查询同义词信息
    jdbc.reload.synonym.sql=select synonym_docs as words from gw_es_lexicon_synonym where del_flag = 0;
    # 查询数据库同义词在数据库版本号
    jdbc.reload.swith.synonym.version=SELECT swith_state FROM gw_swith where
    swith_code = ‘synonym_doc’

    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图20ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图21ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图22

    然后我们再来完善MySqlRemoteSynonymFile类中的代码,完整代码如下□

    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图23TypeScript
    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图24package com.bellszhu.elasticsearch.plugin.synonym.analysis;

    import com.bellszhu.elasticsearch.plugin.DynamicSynonymPlugin; import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    import org.apache.lucene.analysis.Analyzer;
    import org.apache.lucene.analysis.synonym.SynonymMap;
    import org.elasticsearch.common.io.PathUtils;
    import org.elasticsearch.env.Environment;

    import java.io.;
    import java.nio.file.Path;
    import java.sql.
    ;
    import java.util.ArrayList; import java.util.Properties;

    /*
    加载MySql远程同义词
    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图25 @author huangjiayao
    /
    public class MySqlRemoteSynonymFile implements SynonymFile{

    1. /** <br /> * 数据库配置⽂件名 <br /> */ <br /> private final static String DB_PROPERTIES = "jdbc-reload.properties"; <br /> private static Logger logger = LogManager.getLogger("dynamic-synonym"); <br />![](https://cdn.nlark.com/yuque/0/2022/png/2915105/1649812368210-54335ce5-4082-4721-9d91-2b506f6e132b.png#crop=0&crop=0&crop=1&crop=1&id=u5C0l&originHeight=984&originWidth=745&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)![](https://cdn.nlark.com/yuque/0/2022/png/2915105/1649812368686-90636abf-e0dd-4154-87ef-25c0f6459542.png#crop=0&crop=0&crop=1&crop=1&id=EclhE&originHeight=984&originWidth=745&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)29 <br />30 <br />31 <br />32 <br />33 <br />34 <br />35 <br />36 <br />37 <br />38 <br />39 <br />40 <br />41 <br />42 <br />43 <br />44 <br />45 <br />46 <br />47 <br />48 <br />49 <br />50 <br />51 <br />52 <br />53 <br />54 <br />55 <br />56 <br />57 <br />58 <br />59 <br />60 <br />61 <br />62 <br />63

    64
    65
    66
    67
    68
    69
    70
    71
    72
    private String format;

    1. private boolean expand;
    2. private boolean lenient;
    3. private Analyzer analyzer;
    4. private Environment env;
    5. // 数据库配置 <br /> private String location;
    6. // 数据库地址 <br /> private static final String jdbcUrl = "jdbc.url"; <br /> // 数据库⽤⼾名 <br /> private static final String jdbcUser = "jdbc.user"; <br /> // 数据库密码 <br /> private static final String jdbcPassword = "jdbc.password";
    7. /** <br /> * 当前节点的同义词版本号 <br /> */ <br /> private long thisSynonymVersion = -1L;
    8. private Connection connection = null;
    9. private Statement statement = null;
    10. private Properties props;
    11. private Path conf_dir;
    12. MySqlRemoteSynonymFile(Environment env, Analyzer analyzer, <br /> boolean expand, boolean lenient, String format, String location) { <br /> this.analyzer = analyzer; <br /> this.expand = expand; <br /> this.format = format; <br /> this.lenient = lenient; <br /> this.env = env; <br /> this.location = location; <br /> this.props = new Properties();

    //读取当前jar包存放的路径
    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图26ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图2772
    73

    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91

    92
    93
    94
    95
    96
    97
    98
    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图2899
    100 101 102 103 104 105 106

    107 108 109 110 111
    //读取当前 jar 包存放的路径
    Path filePath = PathUtils.get(new
    File(DynamicSynonymPlugin.class.getProtectionDomain().getCodeSource() .getLocation().getPath())
    .getParent(), “config”)
    .toAbsolutePath();
    this.conf_dir = filePath.resolve(DB_PROPERTIES);

        //判断⽂件是否存在  <br />        File configFile = conf_dir.toFile(); <br />        InputStream input = null; <br />        try { <br />            input = new FileInputStream(configFile); <br />        } catch (FileNotFoundException e) { <br />            [logger.info](http://logger.info/)("jdbc-reload.properties 数据库配置⽂件没有找到, " + e);  <br />        } <br />        if (input != null) { <br />            try { <br />                props.load(input); <br />            } catch (IOException e) { <br />                logger.error("数据库配置⽂件 jdbc-reload.properties 加载失败," +  e); <br />            } <br />        } <br />        isNeedReloadSynonymMap(); <br />    } 
    
    /** <br />     * 加载同义词词典⾄SynonymMap中  <br />     * @return SynonymMap <br />     */ <br />    @Override <br />    public SynonymMap reloadSynonymMap() { <br />        try { <br />            [logger.info](http://logger.info/)("start reload local synonym from {}.", location); <br />            Reader rulesReader = getReader(); <br />            SynonymMap.Builder parser =  <br />RemoteSynonymFile.getSynonymParser(rulesReader, format, expand, lenient,  <br />analyzer); <br />            return parser.build(); <br />        } catch (Exception e) { <br />            logger.error("reload local synonym {} error!", e, location); <br />            throw new IllegalArgumentException( <br />                    "could not reload local synonyms file to build synonyms",  e); <br />![](https://cdn.nlark.com/yuque/0/2022/png/2915105/1649812370459-5265a0a6-2be9-4790-be7c-3af367c8c78f.png#crop=0&crop=0&crop=1&crop=1&id=j4T1J&originHeight=984&originWidth=745&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)![](https://cdn.nlark.com/yuque/0/2022/png/2915105/1649812370814-f463e21f-8a53-4cc4-9ead-ea5e3643a982.png#crop=0&crop=0&crop=1&crop=1&id=vzUXU&originHeight=984&originWidth=745&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)![](https://cdn.nlark.com/yuque/0/2022/png/2915105/1649812371356-f9731eaf-6076-4d99-a8b0-46757631ed14.png#crop=0&crop=0&crop=1&crop=1&id=mGMnD&originHeight=14&originWidth=57&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)![](https://cdn.nlark.com/yuque/0/2022/png/2915105/1649812371812-ba947e23-e3f4-4f95-adb9-b9c115b577f6.png#crop=0&crop=0&crop=1&crop=1&id=ybVyz&originHeight=13&originWidth=57&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 
    

    148 149 150

    151 152 153 154
    } }

    /** <br />     * 判断是否需要进⾏重新加载  <br />     * @return true or false <br />     */ <br />    @Override <br />    public boolean isNeedReloadSynonymMap() { <br />        try { <br />            Long mysqlVersion = getMySqlSynonymVersion();             if (thisSynonymVersion < mysqlVersion) { <br />                thisSynonymVersion = mysqlVersion; <br />                return true; <br />            } <br />        } catch (Exception e) { <br />            logger.error(e); <br />        } <br />        return false; <br />    } 
    
    /** <br />     * 获取MySql中同义词版本号信息  <br />     * ⽤于判断同义词是否需要进⾏重新加载  <br />     * <br />     * @return getLastModify <br />     */ <br />    public Long getMySqlSynonymVersion() { <br />        ResultSet resultSet = null; <br />        Long mysqlSynonymVersion = 0L; <br />        try { <br />            if (connection == null || statement == null) { <br />//                Class.forName(props.getProperty("jdbc.driver")); <br />                statement = getConnection(props, connection); <br />            } <br />            resultSet =  <br />statement.executeQuery(props.getProperty("jdbc.reload.swith.synonym.version"));             while (resultSet.next()) { <br />                mysqlSynonymVersion = resultSet.getLong("swith_state"); <br />                [logger.info](http://logger.info/)("当前MySql同义词版本号为:{}, 当前节点同义词库版本号为: <br />{}", mysqlSynonymVersion, thisSynonymVersion); <br />            } <br />        } catch (SQLException e) { <br />            e.printStackTrace(); <br />        } finally { <br />![](https://cdn.nlark.com/yuque/0/2022/png/2915105/1649812372058-121a28d7-9c4e-41d0-a42e-8bb0a0cd013f.png#crop=0&crop=0&crop=1&crop=1&id=JJg0v&originHeight=984&originWidth=745&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)![](https://cdn.nlark.com/yuque/0/2022/png/2915105/1649812372368-b7531b0c-e8e7-4f39-9dfb-59ea34d6905f.png#crop=0&crop=0&crop=1&crop=1&id=ZTSrJ&originHeight=984&originWidth=745&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)<br />![](https://cdn.nlark.com/yuque/0/2022/png/2915105/1649812372855-487ab0eb-5375-4de0-9d7e-37d9f9da86f9.png#crop=0&crop=0&crop=1&crop=1&id=ec2PV&originHeight=15&originWidth=57&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 
    

    179

    180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
    } y{
    try {
    if (resultSet != null) { resultSet.close();
    }
    } catch (SQLException e) {
    e.printStackTrace();
    }
    }
    return mysqlSynonymVersion;
    }

    /** <br />     * 查询数据库中的同义词  <br />     * @return DBData <br />     */ <br />    public ArrayList<String> getDBData() { <br />        ArrayList<String> arrayList = new ArrayList<>(); <br />        ResultSet resultSet = null; <br />        try { <br />            if (connection == null || statement == null) { <br />//                Class.forName(props.getProperty("jdbc.driver")); <br />                statement = getConnection(props, connection); <br />            } <br />            [logger.info](http://logger.info/)("正在执⾏SQL查询同义词列表,SQL:{}",  <br />props.getProperty("jdbc.reload.synonym.sql")); <br />            resultSet =  <br />statement.executeQuery(props.getProperty("jdbc.reload.synonym.sql"));             while (resultSet.next()) { <br />                String theWord = resultSet.getString("words"); <br />                arrayList.add(theWord); <br />            } <br />        } catch (SQLException e) { <br />            logger.error(e); <br />        } finally { <br />            try { <br />                if (resultSet != null) { <br />                    resultSet.close(); <br />                } <br />            } catch (SQLException e) { <br />                e.printStackTrace(); <br />            } 
    
        } <br />        return arrayList; <br />} <br />![](https://cdn.nlark.com/yuque/0/2022/png/2915105/1649812373116-584ed4f8-4ad8-474c-9485-5c3ca4272bdb.png#crop=0&crop=0&crop=1&crop=1&id=MB5Tx&originHeight=984&originWidth=745&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)![](https://cdn.nlark.com/yuque/0/2022/png/2915105/1649812373355-1c5c3fe1-2471-407b-963f-2288ddf7450f.png#crop=0&crop=0&crop=1&crop=1&id=p5Cnt&originHeight=984&originWidth=745&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)![](https://cdn.nlark.com/yuque/0/2022/png/2915105/1649812373607-06558907-b735-4df5-88cc-e1c3b08fbaf9.png#crop=0&crop=0&crop=1&crop=1&id=b3RgH&originHeight=15&originWidth=57&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 
    

    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图29ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图30ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图31212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227

    228 229 230 231 232 233 234
    }

    /** <br />     * 同义词库的加载  <br />     * @return Reader <br />     */ <br />    @Override <br />    public Reader getReader() { 
    
        StringBuffer sb = new StringBuffer(); <br />        try { <br />            ArrayList<String> dbData = getDBData(); <br />            for (int i = 0; i < dbData.size(); i++) { <br />                [logger.info](http://logger.info/)("正在加载同义词:{}", dbData.get(i));  <br />                // 获取⼀⾏⼀⾏的记录,每⼀条记录都包含多个词,形成⼀个词组,词与词之间 使⽤英⽂逗号分割  <br />                sb.append(dbData.get(i)) <br />                        .append(System.getProperty("line.separator")); <br />            } <br />        } catch (Exception e) { <br />            logger.error("同义词加载失败");  <br />        } <br />        return new StringReader(sb.toString()); <br />    } 
    
    /** <br />     * 获取数据库可执⾏连接  <br />     * @param props <br />     * @param conn <br />     * @throws SQLException <br />     */ <br />    private static Statement getConnection(Properties props, Connection conn)  throws SQLException { <br />        conn = DriverManager.getConnection( <br />                props.getProperty(jdbcUrl), <br />                props.getProperty(jdbcUser), <br />                props.getProperty(jdbcPassword)); <br />        return conn.createStatement(); <br />    } <br />} <br />![](https://cdn.nlark.com/yuque/0/2022/png/2915105/1649812375574-5145c5f3-1dd8-440c-a3ed-22d6a755f4d7.png#crop=0&crop=0&crop=1&crop=1&id=wqUCq&originHeight=984&originWidth=745&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)![](https://cdn.nlark.com/yuque/0/2022/png/2915105/1649812376087-dc23ac06-1a95-4275-92a9-b0cddf4f2ec6.png#crop=0&crop=0&crop=1&crop=1&id=q7dZJ&originHeight=984&originWidth=745&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)完成这些后,找到DynamicSynonymTokenFilterFactory类的getSynonymFile(Analyzer□ <br />analyzer)⽅法,对其稍加改动,⾃定义⼀个类型,触发调⽤MySql数据库的查询□ 
    
    JavaScript
    SynonymFile getSynonymFile(Analyzer analyzer) {
    try {
    SynonymFile synonymFile;
    if (“fromMySql”.equals(location)) {
    synonymFile = new MySqlRemoteSynonymFile(environment, analyzer,
    expand, lenient, format, location);
    }else if (location.startsWith(“http://“) ||
    location.startsWith(“https://“)) {
    synonymFile = new RemoteSynonymFile(
    environment, analyzer, expand, lenient, format, location);
    } else {
    synonymFile = new LocalSynonymFile(
    environment, analyzer, expand, lenient, format, location);
    }
    if (scheduledFuture == null) {
    scheduledFuture = pool.scheduleAtFixedRate(new Monitor(synonymFile),
    interval, interval, TimeUnit.SECONDS);
    }
    return synonymFile;
    } catch (Exception e) {
    logger.error(“failed to get synonyms: “ + location, e);
    throw new IllegalArgumentException(“failed to get synonyms : “ +
    location, e);
    }
    }

    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图32ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图33ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图34ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图35
    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图36ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图37ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图38
    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图39
    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图40ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图41

    然后在pom⽂件中引⼊jdbc驱动的依赖包□

    HTML
    1
    2
    3
    4
    5

    mysql
    mysql-connector-java 5.1.38

    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图42ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图43到这⾥,基本上已经接近尾声了;我们需要对源码进⾏重新编译,不过在编译之前,需要调整⼀
    下assemblies⽬录下的plugin.xml⽂件,改动后的⽂件如下□

    HTML
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图44ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图45ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图46ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图47ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图48ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图49ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图50ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图51ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图52ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图53ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图54ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图55ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图56ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图57ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图58ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图59ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图60ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图61ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图62ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图63ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图64ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图65ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图66ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图67ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图68ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图69ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图70ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图71ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图72ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图73ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图74ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图75
    19
    20
    21
    22
    23
    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图76ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图77ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图78ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图79ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图80ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图81ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图82ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图83
    24
    25
    26
    27
    28
    29
    <?xml version=”1.0”?>

    -

    zip

    false



    ${project.basedir}/config config





    ${project.basedir}/src/main/resources/plugin- descriptor.properties
    /
    true


    ${project.basedir}/src/main/resources/plugin- security.policy
    /
    true


    …略…

    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图84ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图85ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图86ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图87ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图88ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图89ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图90ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图91

    完成上述步骤后,开始进⾏源码编译,使⽤maven依次执⾏□clean、compile、package,然后在
    编译后的targer/releases⽬录下找到编译后的插件安装包⽂件.zip;□
    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图92ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图93将其拷⻉到ES的安装⽬录下的\plugins\dynamic-synonym⽬录下并解压后删除压缩包;然后将
    jdbc驱动拷⻉到当前⽬录下,如下所⽰□

    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图94

    在数据库同义词表中新增数据,并修改同义词词库版本号

    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图95

    然后在bin⽬录下启动ES后,新建Mapping使其触发调⽤数据库逻辑□

    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图96Prolog
    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图97PUT synonyms_index
    {
    “settings”: {
    “number_of_shards”: 1,
    “number_of_replicas”: 0,
    “index”: {
    “analysis”: {
    “filter”: {
    “mysql_synonym”: {
    “type”: “dynamic_synonym”,
    “synonyms_path”: “fromMySql”,
    “interval”: 30
    }
    },
    “analyzer”: {
    “ik_syno”: {
    “type”:”custom”,
    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图98ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图9917
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    type: custom,
    “tokenizer”: “ik_smart”,
    “filter”: [
    “mysql_synonym”
    ]
    },
    “ik_syno_max”: {
    “type”: “custom”,
    “tokenizer”: “ik_max_word”, “filter”: [
    “mysql_synonym”
    ]
    }
    }
    }
    }
    },
    “mappings”: {
    “properties”: {
    “name”: {
    “type”: “text”,
    “analyzer”: “ik_syno_max”,
    “search_analyzer”: “ik_syno”
    },
    “title”: {
    “type”: “text”,
    “analyzer”: “ik_max_word”,
    “search_analyzer”: “ik_smart”
    }
    }
    }
    }

    在ES的⽇志中可以看到如下输出□ ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图100
    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图101ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图102通过⽇志可以看到,已成功触发数据库同义词词库;因为我本地还有ik分词器访问数据库,所以
    ⽇志⽅⾯有⼀点⼲扰;

    通过DSL语句验证⼀下是否有⽣效□

    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图103

    并且,当数据库中的词库版本号发⽣变更时,则会触发同步同义词操作;在实际⽣产环境的应⽤
    场景中ES通常是集群搭建,所以采⽤版本号可以很好的适应集群环境;从⽽保证每个集群都可以同步 ⽣效;

    常⻅问题□
    常⻅问题可以参考IK分词器的改源码遇到的问题,基本上问题都是⼀模⼀样的;⽆⾮以下⼏种□ 1、需要在ES的插件⽬录下,导⼊MySql的驱动包□
    2、需要在JDK的安装⽬录下的指定⽂件夹下导⼊MySql的驱动包□
    3、需要在JDK的安装⽬录下的指定⽂件添加⼀⾏配置□
    ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图104ElasticSearch 7.X系列之:集成IK相关性同义词改源码实现MySql5.7.2实现远程动态同义词词库实时更新 - 图1054、所修改的JDK,需要配置到系统环境变量中,不然ES会采⽤⾃带的JDK□

    ik分词器的采坑地址https://zhuanlan.zhihu.com/p/268169068