Loading... # Elasticsearch(七) ## 分词器 ### 用处 1. 分词 1. Index time analysis: 创建或者更新文档时,会对文档进行分词 2. Search time analysis: 查询时,对搜索关键词分词 2. normalization: 提升recall召回率,能搜索到更多的结果 ### 分析器 #### character filter 分词之前预处理,过滤无用字符、标签,字符转换等。 1、HTML Strip Character Filter: html_strip过滤html标签,可以通过`escaped_tags`设置需要保留的标签。 ``` PUT my_index { "settings": { "analysis": { "char_filter": { "my_char_filter": { "type": "html_strip", "escaped_tags": ["a"] } }, "analyzer": { "my_analyzer": { "tokenizer": "keyword", "char_filter": "my_char_filter" } } } } } ``` 测试: ``` GET my_index/_analyze { "analyzer": "my_analyzer", "text": "mafaf <a><b>asdjkaf</b></a>" } ``` 结果: ``` { "tokens" : [ { "token" : "mafaf <a>asdjkaf</a>", "start_offset" : 0, "end_offset" : 27, "type" : "word", "position" : 0 } ] } ``` 可以看到,关键词中的b标签被去掉了。 2、Mapping Character Filter: type mapping,字符转换。 ``` PUT my_index { "settings": { "analysis": { "char_filter": { "my_char_filter": { "type": "mapping", "mappings": [ "٠ => 0", "١ => 1", "٢ => 2", "٣ => 3", "٤ => 4", "٥ => 5", "٦ => 6", "٧ => 7", "٨ => 8", "٩ => 9" ] } }, "analyzer": { "my_analyzer": { "tokenizer": "keyword", "char_filter": [ "my_char_filter" ] } } } } } ``` 测试: ``` GET my_index/_analyze { "analyzer": "my_analyzer", "text": "٣ a b c ٥ def ٨" } ``` 结果: ``` { "tokens" : [ { "token" : "3 a b c 5 def 8", "start_offset" : 0, "end_offset" : 15, "type" : "word", "position" : 0 } ] } ``` 3、Pattern Replace Charactor Filter: type pattern_replace,根据正则替换。 ``` PUT my_index { "settings": { "analysis": { "char_filter": { "my_char_filter": { "type": "pattern_replace", "pattern": "(\\d)-(?=\\d)", "replacement": "$1_" } }, "analyzer": { "my_analyzer": { "tokenizer": "keyword", "char_filter": "my_char_filter" } } } } } ``` 测试: ``` GET my_index/_analyze { "analyzer": "my_analyzer", "text": "123-456-789" } ``` 结果: ``` { "tokens" : [ { "token" : "123_456_789", "start_offset" : 0, "end_offset" : 11, "type" : "word", "position" : 0 } ] } ``` #### token filter 停用词、时态转换、大小写转换、同义词转换、语气词处理等。比如:has=>have,消除the,a等。 #### tokenizer分词器 ES7.x内置15钟分词器 1、standard analyzer: 默认分词器,中文支持不理想,会逐字拆分。`max_token_lenth`最大令牌长度,如果超过此长度,将按照设置的值间隔分割,默认255。 ``` GET my_index/_analyze { "analyzer": "standard", "text": "江山如此多娇" } ``` 2、pattern tokenizer: 以正则匹配分隔符,把文本拆分成若干项。 ``` PUT my_index { "settings": { "analysis": { "analyzer": { "my_analyzer": { "tokenizer": "pattern", "pattern": "[&,<>《》]" } } } } } ``` 3、simple pattern tokenizer: 以正则匹配词项,与pattern tokenizer不同,pattern tokenizer是以正则切割,simple pattern tokenizer是以正则匹配,只会给满足正则的词建立索引,速度比pattern tokenizer快。 4、whitespace analyzer: 以空白符分隔。 #### 自定义分词器 - tokenizer: 内置或自定义分词器。 - char_filter: 内置或自定义字符过滤器。 - filter: 内置或自定义token filter。 ``` PUT my_index { "settings": { "analysis": { "char_filter": { "my_char_filter": { "type": "mapping", "mappings": [ "& => and" ] } }, "filter": { "test_filter": { "type": "stop", "stopword": [ "is", "a", "at", "the" ] } }, "analyzer": { "my_analyzer": { "type": "custom", "char_filter": [ "my_char_filter", "html_strip" ], "filter": [ "lowercase", "test_filter" ], "tokenizer": "standard" } } } } } ``` 测试: ``` GET my_index/_analyze { "analyzer": "my_analyzer", "text": "The F-35 of Lockheed&Martin is the best flighter" } ``` 结果: ``` { "tokens" : [ { "token" : "f", "start_offset" : 4, "end_offset" : 5, "type" : "<ALPHANUM>", "position" : 1 }, { "token" : "35", "start_offset" : 6, "end_offset" : 8, "type" : "<NUM>", "position" : 2 }, { "token" : "lockheedandmartin", "start_offset" : 12, "end_offset" : 27, "type" : "<ALPHANUM>", "position" : 4 }, { "token" : "best", "start_offset" : 35, "end_offset" : 39, "type" : "<ALPHANUM>", "position" : 7 }, { "token" : "flighter", "start_offset" : 40, "end_offset" : 48, "type" : "<ALPHANUM>", "position" : 8 } ] } ``` #### 中文分词器 1. ik分词: ES的中文分词器,需要自行安装,安装目录不要有中文和空格,否则会报错。 1. 下载地址: [https://github.com/medcl/elasticsearch-analysis-ik](https://github.com/medcl/elasticsearch-analysis-ik) 2. 创建插件文件夹,在ES目录下的plugins目录下创建ik文件夹。 3. 将插件解压缩到ik文件夹中。 4. 重新启动ES 2. 两种analyzer - ik_max_word: 细粒度 - ik_smart: 粗粒度 3. ik文件描述 - IKAnalyzer.cfg.xml: ik分词配置文件 - 主词库: main.dic - 英文停用词: stopword.dic,停用词即不会建立在倒排索引中的词。 - 特殊词库: - quantifier.dic: 特殊词库,计量单位等。 - suffix.dic: 特殊词库,后缀名。 - surname.dic: 特殊词库,百家姓。 - preposition.dic: 特殊词库,语气词。 ES会根据词库进行分词,但是许多网络流行词或者我们自定义的词是不会出现在词库中的,因此我们可以自定义词库,比如在主词库中插入时下网络流行词,在停用词库中插入中文停用词(默认英文,不满足需求)。自定义词库的做法一般是修改ik分词器源码。一般直接修改`org.wltea.analyzer.dic.Dictionary`类就可以了。 ``` singleton = new Dictionary(cfg); singleton.loadMainDict(); singleton.loadSurnameDict(); singleton.loadQuantifierDict(); singleton.loadSuffixDict(); singleton.loadPrepDict(); singleton.loadStopWordDict(); ``` 在这些加载词库的方法中进行修改,比如我们可以修改`loadMainDict()`,`loadStopWordDict()`方法,添加从mysql中读取的逻辑。修改之后需要将依赖的jar包放入ik目录下,启动ES可能会报: ``` java.security.AccessControlException: access denied (“java.lang.RuntimePermission” “setContextClassLoader”) ``` 错误。该错误修改需要修改java安全权限: - jdk8及以下修改jdk目录下jre/lib/security/java.policy - jdk8以上修改jdk目录下conf/security/java.policy 在grant项的最后添加: ``` permission java.lang.RuntimePermission "setContextClassLoader"; permission java.net.SocketPermission "*", "connect,resolve"; ``` 如果使用了连接池,还需添加: ``` permission java.util.PropertyPermission "*", "read,write"; permission javax.management.MBeanServerPermission "createMBeanServer"; permission java.lang.RuntimePermission "getClassLoader"; permission javax.management.MBeanPermission "*", "registerMBean"; permission javax.management.MBeanTrustPermission "register"; ``` **热更新** - 修改ik分词器源码。启动一个线程每隔一段时间去执行一次`Dictionary.getSingleton().reLoadMainDict();`方法,重新加载词库,这样我们修改了mysql表中的数据,就不需要重启ES了。 - 基于ik分词器原生支持的热更新方案,部署一个web服务器,提供一个http接口,通过modified和tag两个http响应头,来提供词语的热更新。 #### 动态更新同义词 > https://github.com/ginobefun/elasticsearch-dynamic-synonym ES7.6.2适配,修改pom.xml将elasticsearch.version标签修改为7.6.2。然后会出现编译错误,修改: ``` private static final Logger LOGGER = ESLoggerFactory.getLogger(Monitor.class.getName()); ``` 改为: ``` private static final Logger LOGGER = Loggers.getLogger(Monitor.class,"dynamic-synonym"); ``` 然后编译,插件是根据数据库中保存的version来更新数据的,启动时会加载version的最大值,当最大值发生改变时,会重新加载同义词表。默认60秒检查一次。`private static final int DB_CHECK_URL = 60;` Last modification:July 22nd, 2020 at 10:43 pm © 允许规范转载
如星火燎原,既有锋芒又不失温度。