分词器是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" # 使用的分词器}}}} }
字符过滤器是分词之前的预处理,过滤无用字符,主要有这三种:html_strip、mapping、pattern_replace
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标签保留了
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是正则匹配替换
可以匹配手机号码,将中间四个数字加密处理
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" }
结果:
停用词(stop)、大小写转换(lowercase)、同义词转换(synonym)等。
停用词有个参数可以设置删除的词语: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?"] }
结果:
同义词过滤器需要配置同义词的文件路径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": ["蒙丢丢"] }
结果:
分词器的作用就是用来切词的。
常见的分词器有:
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目录下
IKAnalyzer.cfg.xml:IK分词配置文件
main.dic:主词库:
stopword.dic:英文停用词,不会建立在倒排索引中
quantifier.dic:特殊词库:计量单位等
suffix.dic:特殊词库: 后级名
surname.dic: 特殊词库: 百家姓
preposition:特殊词库: 语气词
自定义词库:网络词汇、流行词、自造词等
/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}] }