在全文搜索(Fulltext Search)中,词(Term)是一个搜索单元,表示文本中的一个词,标记(Token)表示在文本字段中出现的词,由词的文本、在原始文本中的开始和结束偏移量、以及数据类型等组成。ElasticSearch 把文档数据写到倒排索引(Inverted Index)的结构中,倒排索引建立词(Term)和文档之间的映射,索引中的数据是面向词,而不是面向文档的。分析器(Analyzer)的作用就是分析(Analyse),用于把传入Lucene的文档数据转化为倒排索引,把文本处理成可被搜索的词。
在ElasticSearch引擎中,分析器的任务是分析(Analyze)文本数据,分析是分词,规范化文本的意思,其工作流程是:
首先,字符过滤器对分析(analyzed)文本进行过滤和处理,例如从原始文本中移除HTML标记,根据字符映射替换文本等,
过滤之后的文本被分词器接收,分词器把文本分割成标记流,也就是一个接一个的标记,
然后,标记过滤器对标记流进行过滤处理,例如,移除停用词,把词转换成其词干形式,把词转换成其同义词等,
最终,过滤之后的标记流被存储在倒排索引中;
ElasticSearch引擎在收到用户的查询请求时,会使用分析器对查询条件进行分析,根据分析的结构,重新构造查询,以搜索倒排索引,完成全文搜索请求。
无论是内置的分析器(analyzer),还是自定义的分析器(analyzer),都由三种构件块组成的:**character filters ,tokenizers **和 token filters。
-
**character filters **
字符过滤器以字符流的形式接收原始文本,并可以通过添加、删除或更改字符来转换该流。
举例来说,一个字符过滤器可以用来把阿拉伯数字(٠١٢٣٤٥٦٧٨٩)转成成Arabic-Latin的等价物(0123456789)。
一个分析器可能有0个或多个字符过滤器,它们按顺序应用。
-
Tokenizer (分词器)
一个分词器接收一个字符流,并将其拆分成单个token (通常是单个单词),并输出一个token流。例如,一个whitespace分词器当它看到空白的时候就会将文本拆分成token。它会将文本“Quick brown fox!”转换为[Quick, brown, fox!]
(PS:Tokenizer 负责将文本拆分成单个token ,这里token就指的就是一个一个的单词。就是一段文本被分割成好几部分 )
分词器还负责记录每个term的顺序或位置,以及该term所表示的原单词的开始和结束字符偏移量。(PS:文本被分词后的输出是一个term数组)
一个分析器必须只能有一个分词器
-
Token filters (token过滤器)
token过滤器接收token流,并且可能会添加、删除或更改tokens。
例如,一个lowercase token filter可以将所有的token转成小写。stop token filter可以删除常用的单词,比如 the 。synonym token filter可以将同义词引入token流。
不允许token过滤器更改每个token的位置或字符偏移量。
一个分析器可能有0个或多个token过滤器,它们按顺序应用。
ES内置分词器(Tokenizer)
分词器在字符过滤器之后工作,用于把文本分割成多个标记(Token),一个标记基本上是词加上一些额外信息,分词器的处理结果是标记流,它是一个接一个的标记,准备被过滤器处理。
-
标准分析器(Standard)
分析器类型是standard,由标准分词器(Standard Tokenizer),标准标记过滤器(Standard Token Filter),小写标记过滤器(Lower Case Token Filter)和停用词标记过滤器(Stopwords Token Filter)组成。参数stopwords用于初始化停用词列表,默认是空的。
-
简单分析器(Simple)
分析器类型是simple,实际上是小写标记分词器(Lower Case Tokenizer),在非字母位置上分割文本,并把分词转换为小写形式,功能上是Letter Tokenizer和 Lower Case Token Filter的结合(Combination),但是性能更高,一次性完成两个任务。
-
空格分析器(Whitespace)
分析器类型是whitespace,实际上是空格分词器(Whitespace Tokenizer)。
-
停用词分析器(Stopwords)
分析器类型是stop,由小写分词器(Lower Case Tokenizer)和停用词标记过滤器(Stop Token Filter)构成,配置参数stopwords或 stopwords_path指定停用词列表。
-
雪球分析器(Snowball)
分析器类型是snowball,由标准分词器(Standard Tokenizer),标准过滤器(Standard Filter),小写过滤器(Lowercase Filter),停用词过滤器(Stop Filter)和雪球过滤器(Snowball Filter)构成。参数language用于指定语言。
-
自定义分析器
分析器类型是custom,允许用户定制分析器。参数tokenizer 用于指定分词器,filter用于指定过滤器,char_filter用于指定字符过滤器。
内置分析器实例
这里我们使用的工具是Kibana,我们在这里来操作一下Elasticsearch。如下的事例是ES默认的标准分析器,我们使用_analyze来调试实验一下。
POST _analyze
{
"analyzer": "standard",
"text": "I am Chinese."
}
输出如下结果:
{
"tokens" : [
{
"token" : "i",
"start_offset" : 0,
"end_offset" : 1,
"type" : "",
"position" : 0
},
{
"token" : "am",
"start_offset" : 2,
"end_offset" : 4,
"type" : "",
"position" : 1
},
{
"token" : "chinese",
"start_offset" : 5,
"end_offset" : 12,
"type" : "",
"position" : 2
}
]
}
而使用空格分析器的话,就会对每个空格进行分割,如下
POST _analyze
{
"analyzer": "whitespace",
"text": "I'm Chinese."
}
输出结果:
{
"tokens" : [
{
"token" : "I'm",
"start_offset" : 0,
"end_offset" : 3,
"type" : "word",
"position" : 0
},
{
"token" : "Chinese.",
"start_offset" : 4,
"end_offset" : 12,
"type" : "word",
"position" : 1
}
]
}
接下来我们创建一个自定义分析器:
# 创建一个自定义分词器
PUT test_index_1
{
"settings": {
"analysis": {
"analyzer": {
"my_custom_anaylzer" : {
"type" : "custom",
"tokenizer" : "standard",
"char_filter" : ["html_strip"],
"filter" : ["lowercase"]
}
}
}
}
}
以上代码是创建一个自定义分析器,其中使用分析器是标准分析器,字符串过滤使用的是html_strip(去除里面的html标签内容),token过滤器用的是lowercase,也就是把取出来的字符都转成小写。运行如下事例。
POST test_index_1/_analyze
{
"analyzer" : "my_custom_anaylzer",
"text" : "Is this a box ?"
}
输出结果为:
{
"tokens" : [
{
"token" : "is",
"start_offset" : 0,
"end_offset" : 2,
"type" : "",
"position" : 0
},
{
"token" : "this",
"start_offset" : 3,
"end_offset" : 7,
"type" : "",
"position" : 1
},
{
"token" : "a",
"start_offset" : 12,
"end_offset" : 13,
"type" : "",
"position" : 2
},
{
"token" : "box",
"start_offset" : 14,
"end_offset" : 17,
"type" : "",
"position" : 3
}
]
}
参考
https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis.html
https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-tokenfilters.html
https://github.com/medcl/elasticsearch-analysis-ik