所谓分词就是将一段文本按照语义规则切分成多个词语,当有一篇文章标题是 “马云说996是福报”时,我们需要把这段文本切分成多个词语: 996、马云、福报 等。因为用户搜索的时候可能只会输入一个词语。
之所以要这样做是为了提高搜索的准确度,如果用户搜索的时候输入的关键字是 “996”,刚好能匹配到分词短语 996,就能命中该文本。ES 的搜索不象 MySQL 那样使用 like 语句执行模糊搜索。
搜索的质量取决于分词的好坏。例如 996 如果拆分成9和6,用户输入996又匹配不到,输入9或者6 可能又会搜到很多无关紧要的东西。
分析器
分析器的作用对文本进行分词处理。首先将文本拆分,构建倒排索引,然后对分词进行处理提高分词的搜索准确率。分析器包含3部分
- 字符过滤器 character filter:将文本中的特殊字符过滤,例如html标签,标点符号. analyzer中可包含0个或多个字符过滤器,多个按配置顺序依次进行处理。
- 分词器 tokenizer:将文本拆分成单个词条,一个analyzer必需且只可包含一个tokenizer
- 词项过滤器 token filter:对词条进一步优化,单词小写化,删除无用词(的、得、地)等操作。一个analyzer可包含0个或多个词项过滤器,按配置顺序进行过滤
内建字符过滤器
- html_strip: 过滤html标签
- mapping: 用指定的字符串替换文档中的字符串
- pattern_replace :用正则表达式替换
将文档加入索引或者用户搜索的时候都会用到分析器。
3部分分开指定时这样写
POST _analyze
{
"char_filter": [ "html_strip" ],
"tokenizer":"standard",
"filter": ["lowercase", "asciifolding"],
"text": "<p>I'm so <b>happy</b>!</p>"
}
系统内置了很多分析器,下面将对常用的分析器介绍
空格分析器
空格分析器只适用于英文文本,它按照单词的空格进行切分。因为中文句子是连续的,所以空格分析器不使用。
POST _analyze
{
"analyzer": "whitespace",
"text": "The quick brown fox."
}
# 输出
{
"tokens": [
{
"token": "The",
"start_offset": 0,
"end_offset": 3,
"type": "word",
"position": 0
},
{
"token": "quick",
"start_offset": 4,
"end_offset": 9,
"type": "word",
"position": 1
},
...
]
}
标准分析器
标准分析器是 Elasticsearch 默认使用的分析器,根据 Unicode 联盟定义的单词边界划分文本,英文按照空格拆分,中文按照单汉字拆分,删除绝大部分标点。
POST _analyze
{
"analyzer": "standard",
"text": "所有的光鲜,都有加班的味道"
}
# 输出
{
"tokens": [
{
"token": "所",
"start_offset": 0,
"end_offset": 1,
"type": "<IDEOGRAPHIC>",
"position": 0
},
{
"token": "有",
"start_offset": 1,
"end_offset": 2,
"type": "<IDEOGRAPHIC>",
"position": 1
},
{
"token": "的",
"start_offset": 2,
"end_offset": 3,
"type": "<IDEOGRAPHIC>",
"position": 2
},
...
]
}
给索引指定分析器
创建索引时可指定分析器,加入的文档就会按照这个分词器进行分词保存。
PUT /account
{
"settings": {
"analysis": {
"analyzer": {
"my_english_analyzer": {
"type": "standard",
"max_token_length": 5,
"stopwords": "_english_"
}
}
}
}
}
对于已经存在的索引,如何给索引加分析器呢?
https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-standard-analyzer.html
IK分析器
标准分析器不适用于中文分词,因为中文只有一个个词语组织在一起才有意义,单个汉字没什么意义,所有就有了专业的中文分析器。
IK 分析器是一款结合了词典和文法分析算法的中文分词组件,基于字符串匹配,支持用户词典扩展定义,支持细粒度和智能切分。
安装插件
使用插件命令安装中文分词IK插件,注意选择ES对应的版本,我这里选择的是7.0
sudo ./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.0.0/elasticsearch-analysis-ik-7.0.0.zip
IK分析器的两种分析器分别叫:ik_smart (智能切分), ik_max_word(细粒度)
测试分词
POST /_analyze
{
"analyzer": "ik_smart",
"text": "996都有加班的味道"
}
# 返回
{
"tokens": [
{
"token": "996",
"start_offset": 0,
"end_offset": 3,
"type": "ARABIC",
"position": 0
},
{
"token": "都有",
"start_offset": 3,
"end_offset": 5,
"type": "CN_WORD",
"position": 1
},
{
"token": "加班",
"start_offset": 5,
"end_offset": 7,
"type": "CN_WORD",
"position": 2
},
...
]
}
索引中设置自定义分析器
PUT /articles
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"char_filter": [ "html_strip" ],
"tokenizer": "ik_max_word",
}}
}},
}
my_analyzer 就是我们的自定义分析器,可以用在定义的字段中
"mappings": {
"properties": {
"body":{
"type":"text",
"analyzer": "my_analyzer",
"search_analyzer": "ik_smart" # 搜索时使用另一种分析器
}
}
}
IK 指定用户字典
有时IK分词并不完全准确,比如专有名词,这时需要使用自定义字典来分词。IK支持热更新IK分词
IK的配置文件目录
./elasticsearch-7.5.0/plugins/ik/config
# 有如下文件
extra_main.dic
extra_single_word.dic
extra_single_word_full.dic
extra_single_word_low_freq.dic
extra_stopword.dic
IKAnalyzer.cfg.xml
main.dic
preposition.dic
quantifier.dic
stopword.dic
suffix.dic
surname.dic
https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis.html
插件地址:https://github.com/medcl/elasticsearch-analysis-ik/releases
https://github.com/medcl/elasticsearch-analysis-ik/blob/master/README.md
关注公众号「Python之禅」,回复「1024」免费获取Python资源