分析是将文本,如任何电子邮件的正文转换成附加到反向索引的tokens(标记)或terms(条件)的过程。分析由分析器执行,它可以是内置的分析器,也可以是每个索引定义的自定义分析器。
索引时分析
在索引时,内置的english analyzer(英文分析器)将会转换这个句子:
"The QUICK brown foxes jumped over the lazy dog!"
这些条件将被添加到反向索引中。
[ quick, brown, fox, jump, over, lazi, dog ]
Elastic Search内置了好几种分析器,我们可以指定字段使用的分析器,在mapping的时候设置analyzer字段即可。
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "standard"
}
}
}
}
在索引时,如果没有指定分析器,则会在索引设置中查找名为default的分析器。未找到则默认使用standard analyzer(标准分析器)。
搜索时分析
例如,用户可能搜索:
"a quick fox"
这将由类似英语分析器分析为以下的条件:
[ quick, fox ]
通常在索引时和搜索时应该使用相同的分析器,而像match query(匹配查询)那样的全文检索将使用映射来查找用于每个字段的分析器。
搜索时字段分析器可以有多种途径指定:
-
在查询中指定分析器。
-
search_analyzer映射参数。
-
analyzer映射参数。
搜索的时候会按照上述优先级使用分析器。
常用分词器
标准分词器
在默认情况下,Elasticsearch使用标注分词器进行分词,它根据 Unicode 联盟 定义的 单词边界 划分文本。删除绝大部分标点。最后,将词条小写。例如,对于如下文本:
"Set the shape to semi-transparent by calling set_trans(5)"
它会产生set, the, shape, to, semi, transparent, by, calling, set_trans, 5这些分词。对于英文语言来说使用还是非常实用的。
IK分词器
标准分词器对于英文还是非常方便的,但是对于中文却不行,会将中文拆成一个个的单字,搜索效率和精度都不行,这是就需要用一些第三方中文分词器,常见的是IK分词器。
使用IK分词器,首先需要安装IK分词器插件:
$ ./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.2.0/elasticsearch-analysis-ik-7.2.0.zip
需要注意的时,必须选择和ElasticSearch一致的版本。
然后在映射中指定索引分析器和搜索分析器即可:
"properties": {
"user": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_max_word"
}
}
NGram分词器
前面的分词器主要应用场景是全文搜索,但对于模糊搜索的场景就不行了,虽然ElasticSearch也提供wildcard查询和正则表达式查询能实现模糊搜索。但是他们的性能是非常低下的,如果对性能有要求基本上可以抛弃他们了。
一个简单的解决方案是使用ngram分词器,然后使用match_phrase来匹配,
具体原理我就不介绍了,可以参考如下几篇文章:
自定义分词
除了标准的分词器外,我们有事还要用到自定义分词器,或者设置分词器的一些参数,这个时候就需要一些高级设置了,一个简单的示例如下:
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"type": "custom",
"tokenizer": "standard",
"filter": [
"lowercase"
]
}
}
},
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "my_analyzer"
}
}
}
}
}
简单的来讲,就是在setting中设置分词器参数,然后在mapping中使用分词器,具体用法可以参看官方文档:Create a custom analyzer
测试分词器
有些时候很难理解分词的过程和实际被存储到索引中的词条,特别是你刚接触Elasticsearch。为了理解发生了什么,你可以使用 analyze API 来看文本是如何被分析的。在消息体里,指定分析器和要分析的文本:
GET /_analyze
{
"analyzer": "standard",
"text": "Text to analyze"
}
对于索引里面的自定义分词器,可以带上索引名称:
POST /my_index/_analyze
{
"analyzer": "my_analyzer",
"text": "2 Quick Foxes."
}