简介
分词器是es中的一个组件,通俗意义上理解,就是将一段文本按照一定的逻辑,分析成多个词语,同时对这些词语进行常规化的一种工具;ES会将text格式的字段按照分词器进行分词,并编排成倒排索引,正是因为如此,es的查询才如此之快。
一个analyzer即分析器,无论是内置的还是自定义的,只是一个包含character filters(字符过滤器)、 tokenizers(分词器)、token filters(令牌过滤器)三个细分模块的包。
看下这三个细分模块包的作用:
character filters(字符过滤器):分词之前的预处理,过滤无用字符
token filters(令牌过滤器):停用词、时态转换,大小写转换、同义词转换、语气词处理等。
tokenizers(分词器):切词
自定义分词器
先来看个自定义分词器,了解整个分析器analyzer的构造
PUT custom_analysis { "settings":{ "analysis":{ #分析配置,可以设置char_filter(字符过滤器)、filter(令牌过滤器)、tokenizer(分词器)、analyzer(分析器) "char_filter": { # 字符过滤器配置 "my_char_filter":{ #定义一个字符过滤器:my_char_filter "type":"mapping", # 字符过滤器类型:主要有三种:html_strip(标签过滤)、mapping(字符替换)、pattern_replace(正则匹配替换) "mappings":[ # mapping的参数:表示 '&' 会被替换成 'and' "& => and", "| => or" ] }, "html_strip_char_filter":{ "type":"html_strip", "escaped_tags":["a"] } }, "filter": { # 令牌过滤器配置 "my_stopword":{ # 定义一个令牌过滤器:my_stopword "type":"stop", # 令牌过滤器类型:stop(停用(删除)词) "stopwords":[ # stop的参数:表示这些词会被删除 "is", "in", "the", "a", "at", "for" ] } }, "tokenizer": { # 分词器配置 "my_tokenizer":{ # 定义一个分词器my_tokenizer "type":"pattern", # 分词器类型:pattern 正则匹配 "pattern":"[ ,.!?]" # pattern的参数:会根据这几个字符进行分割 } }, "analyzer": { # 分析器:可以理解成组合了字符过滤器、令牌过滤器、分词器的一个整体。 "my_analyzer":{ #定义一个分析器:my_analyzer "type":"custom", "char_filter":["my_char_filter","html_strip_char_filter"], # 使用的字符过滤器 "filter":["my_stopword"], # 使用的令牌过滤器 "tokenizer":"my_tokenizer" # 使用的分词器 } } } } }
字符过滤器(character filters)
字符过滤器是分词之前的预处理,过滤无用字符,主要有这三种:html_strip、mapping、pattern_replace
html_strip
html_strip用于过滤html标签,它有个参数escaped_tags可以设置保留的标签
看下面例子
PUT index_html_strip { "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": "<p>要的话就<a>点击</a></p>" }
结果:p标签过滤掉了,而a标签保留了
mapping
mapping是字符替换
看下面例子,可以设置一些敏感词替换成*
PUT index_mapping { "settings": { "analysis": { "char_filter": { "my_char_filter":{ "type":"mapping", "mappings":[ "滚 => *", "垃圾 => *", "手枪 => *", "你妈 => *" ] } }, "analyzer": { "my_analyzer":{ "tokenizer":"keyword", "char_filter":["my_char_filter"] } } } } } GET index_mapping/_analyze { "analyzer": "my_analyzer", "text": "你妈的,小垃圾,拿上你的手枪,滚远点!" }
结果:可以看到设置的敏感词被替换成*了
pattern_replace
pattern_replace是正则匹配替换
可以匹配手机号码,将中间四个数字加密处理
PUT index_pattern_replace { "settings": { "analysis": { "char_filter": { "my_char_filter":{ "type":"pattern_replace", "pattern":"(\\d{3})\\d{4}(\\d{4})", "replacement":"$1****$2" } }, "analyzer": { "my_analyzer":{ "tokenizer":"keyword", "char_filter":["my_char_filter"] } } } } } GET index_pattern_replace/_analyze { "analyzer": "my_analyzer", "text": "你的手机号是18814142694" }
结果:
令牌过滤器(token filters)
停用词(stop)、大小写转换(lowercase)、同义词转换(synonym)等。
stop-停用词
停用词有个参数可以设置删除的词语:stopwords
PUT /index_stop { "settings": { "analysis": { "analyzer": { "my_stop": { "tokenizer": "whitespace", "filter": [ "my_stop" ] } }, "filter": { "my_stop": { "type": "stop", "stopwords": [ "is", "in", "the", "a", "at", "for" ] } } } } } GET index_stop/_analyze { "analyzer": "my_stop", "text": ["What is a apple?"] }
结果:
synonym-同义词
同义词过滤器需要配置同义词的文件路径synonyms_path,需要放在项目目录下的config文件目录里
(本项目同义词文件完整路径:/app/elasticsearch-8.4.2/config/analysis/synonym.txt)
蒙丢丢 => 'DaB'
PUT /index_synonym { "settings": { "analysis": { "analyzer": { "synonym": { "tokenizer": "whitespace", "filter": [ "synonym" ] } }, "filter": { "synonym": { "type": "synonym", "synonyms_path": "analysis/synonym.txt" } } } } } GET index_synonym/_analyze { "analyzer": "synonym", "text": ["蒙丢丢"] }
结果:
分词器(tokenizer)
分词器的作用就是用来切词的。
常见的分词器有:
standard:默认分词器,中文支持的不理想,会逐字拆分
pattern:以正则匹配分隔符,把文本拆分成若干词项
simple pattern:以正则匹配词项,速度比pattern tokenizer快
whitespace:以空白符分割
GET _analyze { "analyzer": "whitespace", "text": ["What is a apple?"] }
结果
中文分词器
ES的中文分词器需要下载插件安装使用的。
安装&部署
ik下载地址:GitHub - medcl/elasticsearch-analysis-ik: The IK Analysis plugin integrates Lucene IK analyzer into elasticsearch, support customized dictionary.
点击Releases,选择版本下载
在根目录下的plugins文件夹下,创建ik文件目录,将下载的插件解压到ik目录下
ik配置文件说明
IKAnalyzer.cfg.xml:IK分词配置文件
main.dic:主词库:
stopword.dic:英文停用词,不会建立在倒排索引中
quantifier.dic:特殊词库:计量单位等
suffix.dic:特殊词库: 后级名
surname.dic: 特殊词库: 百家姓
preposition:特殊词库: 语气词
自定义词库:网络词汇、流行词、自造词等
重启ES
/app/elasticsearch-8.4.2/bin/elasticsearch -d /app/kibana-8.4.2/bin/kibana &
使用
GET _analyze { "analyzer": "ik_max_word", #中文分词器:ik_max_word "text": ["今天真是美好的一天"] }
结果
{ "tokens": [ { "token": "今天", "start_offset": 0, "end_offset": 2, "type": "CN_WORD", "position": 0 }, { "token": "天真", "start_offset": 1, "end_offset": 3, "type": "CN_WORD", "position": 1 }, { "token": "真是", "start_offset": 2, "end_offset": 4, "type": "CN_WORD", "position": 2 }, { "token": "美好", "start_offset": 4, "end_offset": 6, "type": "CN_WORD", "position": 3 }, { "token": "的", "start_offset": 6, "end_offset": 7, "type": "CN_CHAR", "position": 4 }, { "token": "一天", "start_offset": 7, "end_offset": 9, "type": "CN_WORD", "position": 5 }, { "token": "一", "start_offset": 7, "end_offset": 8, "type": "TYPE_CNUM", "position": 6 }, { "token": "天", "start_offset": 8, "end_offset": 9, "type": "COUNT", "position": 7 } ] }