ElasticSearch08-分析器详解
1、分析器原理
Elasticsearch的分词器(Analyzer)是全文搜索的核心组件,它负责将文本转换为一系列单词(term/token)的过程,也叫分词。
(1)分析器的构成
字符过滤器(Character Filters) : 接收原始文本字符流,可以通过添加、移除或改变字符来转变原始字符流。例如,可以将印度-阿拉伯数字转换为阿拉伯-拉丁数字,或从流中去除HTML元素等。 分词器(Tokenizer) : 接收字符流,将其分解为单独的tokens(通常是单个单词),并输出tokens流。例如,whitespace
分词器在看到任何空格时将文本分解为tokens。它会将文本 "Quick brown fox!"
转换为多个terms [Quick, brown, fox!]
。分词器还负责记录每个term的顺序或位置以及该term所代表的原始单词的开始和结束字符偏移量。 Token过滤器(Token Filters) : 接收令牌流,并且可以添加、删除或改变token。例如,lowercase
token过滤器将所有token转换为小写,stop
token过滤器从token流中删除常用词(停用词),而synonym
token过滤器将同义词引入token流中。Token过滤器不允许更改每个token的位置或字符偏移量。
(2)分析器的工作流程
字符过滤器处理 :文本首先通过字符过滤器,进行预处理,如去除HTML标签或格式转换。分词器分词 :经过预处理的文本进入分词器,分词器根据定义的规则(如空格、标点符号等)将文本拆分成单个词汇。Token过滤器处理 :分词后的词汇通过一系列的Token过滤器,进行进一步的处理,如小写化、停用词过滤、同义词扩展等。输出tokens :经过Token过滤器处理后的词汇成为最终的tokens,这些tokens将被用于构建倒排索引。
(3)分析器的重要性
分词器对于Elasticsearch的全文搜索至关重要,因为它直接影响到搜索的准确性和相关性。不同的语言和文本类型可能需要不同的分词器来最有效地处理文本。 Elasticsearch提供了多种内置分词器,如standard
、simple
、whitespace
、stop
等,以适应不同的应用场景。 用户也可以根据需要自定义分词器,以满足特定的分词需求。
2、常见内置分词器
分词器名称 描述 示例文本 分词结果示例 Standard Tokenizer 使用Unicode文本分割算法,去除标点符号,适用于大多数欧洲语言 “Elasticsearch: Search & Analytics” [“Elasticsearch”, “Search”, “Analytics”] Whitespace Tokenizer 以空白字符为分词符,包括空格和制表符 “Elasticsearch, search & analytics” [“Elasticsearch,”, “search”, “&”, “analytics”] Lowercase Tokenizer 类似Whitespace Tokenizer,但将所有tokens转换为小写 “Elasticsearch, search & analytics” [“elasticsearch,”, “search”, “&”, “analytics”] Keyword Tokenizer 不进行分词,将整个文本作为一个单独的token “Elasticsearch: Search & Analytics” [“Elasticsearch: Search & Analytics”] Pattern Tokenizer 使用正则表达式进行分词,默认为\W+(非单词字符) “Elasticsearch: Search & Analytics” [“Elasticsearch”, “Search”, “Analytics”] N-Gram Tokenizer 创建n-grams,连续的字符序列 “elasticsearch”(2-gram) [“el”, “le”, “ea”, “ar”, “rc”, “ch”, “ha”, “an”, “nt”, “ts”] Edge N-Gram Tokenizer 从单词的开始或结束部分生成n-grams “elasticsearch”(1-gram,edge) [“e”, “l”, “s”, “e”, “l”, “a”, “r”, “c”, “h”]
3、分词器使用场景
(1)索引阶段(Indexing Phase)
**文档索引:**当文档被索引到Elasticsearch时,分词器用于将文本字段(如标题、内容等)转换为一系列tokens(词项)。这些tokens被存储在倒排索引中,以便后续搜索。 **分析器应用:**在索引过程中,指定的分析器(由分词器和token过滤器组成)会被应用到字段上,以确定如何将文本分割成tokens。
(2)查询阶段(Query Phase)
**查询解析:**当执行搜索查询时,Elasticsearch会对查询文本应用与索引时相同的分析器,包括分词器。这意味着查询文本也会被转换成tokens。 **查询处理:**查询的tokens与索引的倒排索引中的tokens进行匹配,以确定哪些文档包含这些tokens。
(3)相关性评分(Scoring Phase)
**评分计算:**在查询过程中,Elasticsearch会根据tokens在文档中出现的次数和频率计算相关性评分。分词器的使用确保了查询tokens与索引tokens的一致性,从而使得评分准确。
(4)聚合(Aggregations)
**术语聚合:**在执行基于术语的聚合(如terms聚合)时,分词器确保了聚合字段的tokens与查询tokens的一致性。
(5)高亮(Highlighting)
**结果高亮:**在搜索结果中,Elasticsearch会使用与索引相同的分析器对查询文本进行分词,以便在文档中高亮显示匹配的tokens。
(6)建议(Suggestions)
**自动完成和建议:**在自动完成或建议功能中,分词器用于处理用户输入的查询,以便与索引中的tokens匹配。
(7)同义词处理(Synonyms)
**查询扩展:**在使用同义词时,分词器可以与同义词过滤器结合使用,以便在查询时扩展tokens,包括同义词。
4、使用分词器
(1)默认分词器
Elasticsearch的默认分词器是standard
分词器。这个分词器适用于大多数西方语言,特别是英文,它基于Unicode文本分割算法(Unicode Text Segmentation)来分割文本,并去除大多数标点符号。standard
分词器在处理文本时会将所有单词转换为小写,以便进行不区分大小写的匹配。 在创建新的索引时,如果不指定分词器,Elasticsearch会自动使用standard
分词器来处理文本字段。例如,如果你创建了一个名为my_index
的索引,并且没有指定分析器,那么my_index
中的text
字段将默认使用standard
分词器。 使用分词器进行分词,默认分词器无法解析中文词组,所以全部分词成单个字。
# 请求
Get _analyze
{ "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 } , { "token" : "词" , "start_offset" : 3 , "end_offset" : 4 , "type" : "<IDEOGRAPHIC>" , "position" : 3 } , { "token" : "器" , "start_offset" : 4 , "end_offset" : 5 , "type" : "<IDEOGRAPHIC>" , "position" : 4 } ]
}
# 请求
Get _analyze
{ "text" : "测试分词器" , "analyzer" : "ik_max_word"
} # 返回
{ "tokens" : [ { "token" : "测试" , "start_offset" : 0 , "end_offset" : 2 , "type" : "CN_WORD" , "position" : 0 } , { "token" : "分词器" , "start_offset" : 2 , "end_offset" : 5 , "type" : "CN_WORD" , "position" : 1 } , { "token" : "分词" , "start_offset" : 2 , "end_offset" : 4 , "type" : "CN_WORD" , "position" : 2 } , { "token" : "器" , "start_offset" : 4 , "end_offset" : 5 , "type" : "CN_CHAR" , "position" : 3 } ]
}
(2)创建索引并指定分析器
我们创建了一个名为my_custom_analyzer
的自定义分析器,它使用standard
分词器,并且应用了lowercase
和asciifolding
过滤器。 我们将text
字段的分析器设置为定义的my_custom_analyzer
。
# 请求
PUT / my_index
{ "settings" : { "analysis" : { "analyzer" : { "my_custom_analyzer" : { "type" : "custom" , "tokenizer" : "standard" , "filter" : [ "lowercase" , "asciifolding" ] } } } } , "mappings" : { "properties" : { "text" : { "type" : "text" , "analyzer" : "my_custom_analyzer" } } }
} # 返回
{ "acknowledged" : true , "shards_acknowledged" : true , "index" : "my_index"
}
(3)索引文档
text
字段的值会被my_custom_analyzer
处理,包括分词、小写化和ASCII折叠。
# 请求
POST / my_index/ _doc
{ "text" : "Elasticsearch is a distributed search engine."
} # 返回
{ "_index" : "my_index" , "_type" : "_doc" , "_id" : "mhUp05MBwu_sOZK4ykdt" , "_version" : 1 , "result" : "created" , "_shards" : { "total" : 2 , "successful" : 1 , "failed" : 0 } , "_seq_no" : 0 , "_primary_term" : 1
}
(4)执行搜索
在这个搜索查询中,我们指定了my_custom_analyzer
来处理查询字符串"Elasticsearch",确保查询时的分词和索引时的分词一致。
# 请求
GET / my_index/ _search
{ "query" : { "match" : { "text" : { "query" : "Elasticsearch" , "analyzer" : "my_custom_analyzer" } } }
} # 返回
{ "took" : 4 , "timed_out" : false , "_shards" : { "total" : 1 , "successful" : 1 , "skipped" : 0 , "failed" : 0 } , "hits" : { "total" : { "value" : 1 , "relation" : "eq" } , "max_score" : 0.2876821 , "hits" : [ { "_index" : "my_index" , "_type" : "_doc" , "_id" : "mhUp05MBwu_sOZK4ykdt" , "_score" : 0.2876821 , "_source" : { "text" : "Elasticsearch is a distributed search engine." } } ] }
}
(5)注意事项
分析器的选择对搜索结果有重要影响。正确的分析器可以帮助提高搜索的相关性和准确性。 自定义分析器可以根据具体需求组合不同的分词器和过滤器。 在创建索引后,分析器的设置不能更改,除非重新创建索引。