1. 概述
ES中“分析”是指转换文本的处理过程(比如一个邮件的正文),将这些文本转换为标记或者术语(即tokens
和terms
),并将这些标记或术语添加到用于搜索的反向索引。分析这个动作在ES中是由分析器(analyzer
)完成的,分析器可以是ES内置的,也可以是我们人为根据具体业务为具体的索引定制不同的分析器。
索引分析(查询字符串中的术语与倒排索引中的文本中的术语完全匹配)
文档中说的是“index time analysis”,“索引时分析”可能更明确一点。例如,下面的一个句子:
"The QUICK brown foxes jumped over the lazy dog!"
在索引时,内置英语分析器将首先把句子转换为不同的标记tokens
,将每个token
转成小写,删除频繁的停用词(比如the
),将术语term
缩减为词干(即:foxes–>fox、jumped–>jump、lazy–>lazi),最后,下面的术语将会添加到逆向索引中:
[ quick, brown, fox, jump, over, lazi, dog ]
指定一个索引分析器
在结构化数据中(即mapping
)的每个text
字段都可以指定自己的分析器analyzer
,如创建:
curl -X PUT "localhost:9200/my_index" -H 'Content-Type: application/json' -d'
{
// 定义索引的结构化数据
"mappings": {
"_doc": {
"properties": {
"title": {
"type": "text",
"analyzer": "standard"
}
}
}
}
}
'
索引时,如果没有特别指定分析器analyzer
,它将会在索引设置中查找名为default
的分析器,如果失败,就默认使用standard
分析器。
搜索分析(Search time analysis)
在匹配查询的全文查询full text queries
中,在搜索时将相同的分析过程应用于查询字符串,将查询字符串中的文本转换为与存储在倒排索引中的形式相同的形式。比如,用户想要搜索a quick fox
这个字符串,这个字符串将由同样的英语分析器(english
analyzer)分析为以下术语(term
):[ quick, fox ]
,即使精确的单词(使用在查询字符串中)没有出现在原始的文本中(即查询字符串中的词干quick
和fox
没有出现在原始文本中,原始文本中出现的QUICK
和foxes
),因为我们将相同的分析器应用到了文本分析和查询字符串分析过程中,查询字符串中的术语与倒排索引中的文本中的术语完全匹配,那就意味着这些查询字符串将会匹配到我们举例的文档。
指定搜索分析器
通常情况下,索引和搜索都应该使用同一个分析器,全文查询full text queries
就像匹配查询match query
使用结构化mapping
的形式去查找运用于每个字段的分析器。用于搜索特定字段的分析器通过查找确定:
- 在查询中指定的分析器
analyzer
; - 结构化数据中
search_analyzer
参数指定的; - 结构化数据中
analyzer
参数指定的; - 索引设置中的分析器
default_search
; - 索引设置中的分析器
default
; standard
标准分析器;
2. 分析器的本质
无论是ES内置的分析器还是定制的分析器,都只是一个包含三个低级构建块的包:字符过滤器(character filters
)、标记生成器(tokenizers
)和标记过滤器(token filters
),这里面也要注意他们三者的工作顺序为:字符过滤器(数据预处理)–>标记生成器(处理数据,生成token
)–>标记过滤器(过滤token
以返回)。ES内置的分析器已经事先将适合不同语言和文本类型的构建块打包到这些内置的分析器中,Elasticsearch也公开了各个构建块,以便用户可以使用它们组合得到新的自定义分析器。三个构建块简单情况如下:
character filters
:字符过滤器将原始文本作为字符流接收,并可以通过添加、删除或更改字符来转换流。比如,一个字符过滤器可以用来将印度-阿拉伯数字(٠١٢٣٤٥٦٧٨٩
)转成等价的阿拉伯语-拉丁语中数字(0123456789
),或从流中删除<b>
等HTML元素。一个分析器中可能存在0个或多个字符过滤器,这些字符过滤器将按序工作;tokenizer
:标记生成器tokenizer
接收一个字符流,将其分解为单个标记(通常是单个单词),并输出标记(tokens
)流。例如,只要看到任何空格,空格标记器(whitespace
)就会将文本分成标记,比如他将会把文本Quick brown fox!
转换为这些术语:[Quick, brown, fox!]
。标记生成器也负责记录每个术语的顺序和位置,也记录该术语所代表的原始单词的开始和结束字符偏移量。每个分析器有且仅有一个标记生成器tokenizer
;token filter
:标记过滤器接受标记流,可以添加、移除或更改标记。比如,一个小写标记过滤器(lowercase
)将所有的标记转换为小写,一个段词过滤器(stop
)移除标记流中的常用段词(比如the
,其实就是常用的冠词、定冠词这类单词),还有一个同义词标记过滤器(synonym
)将同义词引入标记流。标记过滤器是不被允许改变每个标记的位置或者字符偏移量的。一个分析器可以有0个或多个标记过滤器,这些标记过滤器按序工作;
所以最终的ES的分析器可以简单定义为tokenizer
(有且仅有一个,需要特别指定)、character filters
(0或多个,直接在filter
中指定,就是过滤器)和token filter
(0或多个,直接在filter
中指定,就是过滤器)的组合。
3. 分析器简易实操
analyze
API 是查看分析器生成的术语(term
)的宝贵工具,内置的分析器可以在请求行中指定,比如:
// 栗子1:指定分析器(只有空格标记生成器)和文本进行分析
curl -X POST "localhost:9200/_analyze" -H 'Content-Type: application/json' -d'
{
"analyzer": "whitespace",
"text": "The quick brown fox."
}
'
// 栗子1:分析结果
{
"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
},
{
"token": "brown",
"start_offset": 10,
"end_offset": 15,
"type": "word",
"position": 2
},
{
"token": "fox.",
"start_offset": 16,
"end_offset": 20,
"type": "word",
"position": 3
}
]
}
// 栗子2:指定分析器(包含1个标准标记生成器和2个标记过滤器)和文本进行分析
curl -X POST "localhost:9200/_analyze" -H 'Content-Type: application/json' -d'
{
"tokenizer": "standard",
// asciifolding过滤器是用于去除特殊字符
"filter": [ "lowercase", "asciifolding" ],
"text": "Is this déja vu?"
}
'
// 栗子2:分析结果
{
"tokens": [
{
"token": "is",
"start_offset": 0,
"end_offset": 2,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "this",
"start_offset": 3,
"end_offset": 7,
"type": "<ALPHANUM>",
"position": 1
},
{
"token": "deja",
"start_offset": 8,
"end_offset": 12,
"type": "<ALPHANUM>",
"position": 2
},
{
"token": "vu",
"start_offset": 13,
"end_offset"