1. Analyzer概述
Elasticsearch使用Analyzer来实现文本分析,从而实现将非结构化文本(例如文章正文、邮件内容等)转换为结构化数据,便于检索。Analyzer用于两个场景:对文本字段进行索引和搜索文本。Analyzer只对配置之后的索引生效。
Analyzer包含3个构建块:
- Character filters,字符过滤器,接收原始文本,添加、删除或者改变原始文本的字符。例如HTML标签过滤等。1个Analyzer中可以有0个或者多个字符过滤器。
- Tokenizer, 分词器,接收经过字符过滤器后的字符流,对其进行分词。1个Analyzer中只能有1个Tokenizer。
- Token filters, 分词过滤器,接收经过分词器后的分词列表,添加、删除或者更改分词。例如大小写转换、同义词添加等。1个Analyzer中可以有0个或者多个分词过滤器。
Elasticsearch英文官网中对于以上3个构建块的表述很准确,字符过滤器和分词过滤器用的是复数,Character filters和Token filters,而Tokenizer用的是单数,表示只有1个。
以下通过REST API为例说明Analyzer的使用。
2. 配置Analyzer
ES内置了很多Analyzer,譬如standard analyzer,包含1个standard tokenizer、2个token filter:lower case token filter 和 stop token filter,可以不需要任何配置就应用到索引和搜索中。同样,Elasticsearch中也内置了大量Character filters和Token filters。
Elasticsearch也提供了插件开发接口,用于开发者自己编写Analyzer或者Tokenizer、Character filter和Token filter。譬如各类中文分词插件。
在实际场景中,通常需要通过组合配置分词插件、内置Analyzer、内置Tokenizer、内置Character filters和内置Token filters等来实现索引需求。
内置Analyzer(standard analyzer)可以不需要配置而直接应用到索引配置中,本节主要描述自定义的Analyzer。
自定义Analyzer有2种情况:
对内置Analyzer或者Analyzer插件的默认配置进行修改。
在内置Analyzer或者Analyzer插件的基础上,组合添加Tokenizer、Character filters和Token filters。
不管是哪种情况,都需要创建自定义的Analyzer,不能直接应用原有Analyzer。
2.1. 修改内置Analyzer的配置
内置Analyzer包括:
Fingerprint、Keyword、Language、Pattern、Simple、Standard、Stop、Whitespace。
以修改standard analyzer的属性为例。
standard analyzer可修改的属性如下:
官网参考:https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-standard-analyzer.html
- max_token_length,最大token长度,默认为255。
- stopwords,预定义的停止词列表名称,默认为none。预定义的停止词列表名称见https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-stop-tokenfilter.html#analysis-stop-tokenfilter-stop-words-by-lang。
- stopwords_path,预定义的停止词列表文件路径。
修改standard analyzer的默认属性如下:
curl -X PUT "localhost:9200/my-index-000001?pretty" -H 'Content-Type: application/json' -d'
{
"settings": {
"analysis": {
"analyzer": {
"my_english_analyzer": {
"type": "standard",
"max_token_length": 5,
"stopwords": "_english_"
}
}
}
}
}
'
为方便看request body的格式,扁平化一下,
settings.analysis.analyzer.<自定义分析器名称>
{
"type": "standard",//这里填写要修改的内置分析器名称
"max_token_length": 5,//这里是内置分析器可以修改的属性
"stopwords": "_english_"//这里是内置分析器可以修改的属性
}
可以用下面的方法测试分词效果。
curl -X POST "localhost:9200/my-index-000001/_analyze?pretty" -H 'Content-Type: application/json' -d'
{
"analyzer": "my_english_analyzer",
"text": "The 2 QUICK Brown-Foxes jumped over the lazy dog\u0027s bone."
}
'
2.2. 组合内置模块
内置模块分为3类:Tokenizer、Filter、Char Filter。
- Tokenizer: Character group, Classic, Edge n-gram, Keyword, Letter, Lowercase, N-gram, Path hierarchy, Pattern, Simple pattern, Simple pattern split, Standard, Thai, UAX URL, mail, Whitespace
- Filter: Apostrophe, ASCII folding, CJK bigram, CJK width, Classic, Common grams, Conditional, Decimal digit, Delimited payload, Dictionary decompounder, Edge n-gram, Elision, Fingerprint, Flatten graph, Hunspell, Hyphenation decompounder, Keep types, Keep words, Keyword marker, Keyword repeat, KStem, Length, Limit token count, Lowercase, MinHash, Multiplexer, N-gram, Normalization, Pattern capture, Pattern replace, Phonetic, Porter stem, Predicate script, Remove duplicates, Reverse, Shingle, Snowball, Stemmer, Stemmer override, Stop, Synonym, Synonym graph, Trim, Truncate, Unique, Uppercase, Word delimiter, Word delimiter graph
- Char Filter: HTML strip, Mapping, Pattern replace
任意组合内置模块,生成自定义的分析器。例如:
curl -X PUT "localhost:9200/my-index-000001?pretty" -H 'Content-Type: application/json' -d'
{
"settings": {
"analysis": {
"analyzer": {
"my_custom_analyzer": {
"type": "custom",
"tokenizer": "standard",
"char_filter": [
"html_strip"
],
"filter": [
"lowercase",
"asciifolding"
]
}
}
}
}
}
'
为方便看request body的格式,扁平化一下,
settings.analysis.analyzer.<自定义分析器名称>
{
"type": "custom",//这里填写custom,因为要自己组装内置模块形成一个自定义分析器。
"tokenizer": "standard",,//tokenizer, 字符串,内置tokenizer名称
"char_filter": ["html_strip"],//char_filter,数组,内置char_filter列表
"filter": [ "lowercase", "asciifolding" ] //filter,数组,内置filter列表
}
简言之,格式为从内置模块中,选择1个tokenizer,0个或多个char_filter,0个或多个filter。
2.3. 所有模块自定义
与2.2相比,这里对内置模块的属性也进行了修改,将修改属性后的内置模块组合成自定义分析器Analyzer。属于最通用的自定义分析器。
例如:
curl -X PUT "localhost:9200/my-index-000001?pretty" -H 'Content-Type: application/json' -d'
{
"settings": {
"analysis": {
"analyzer": {
"my_custom_analyzer": {
"type": "custom",
"char_filter": [
"emoticons"
],
"tokenizer": "punctuation",
"filter": [
"lowercase",
"english_stop"
]
}
},
"tokenizer": {
"punctuation": {
"type": "pattern",
"pattern": "[ .,!?]"
}
},
"char_filter": {
"emoticons": {
"type": "mapping",
"mappings": [
":) => _happy_",
":( => _sad_"
]
}
},
"filter": {
"english_stop": {
"type": "stop",
"stopwords": "_english_"
}
}
}
}
}
'
为方便看request body的格式,扁平化一下,
settings.analysis.analyzer.<自定义分析器名称>
{
"type": "custom",//这里填写custom,因为要自己组装自定义模块形成一个自定义分析器。
"tokenizer": "自定义tokenizer名称",,//tokenizer, 字符串,内置tokenizer或者自定义tokenizer名称
"char_filter": ["自定义char_filter名称"],//char_filter,数组,内置char_filter和自定义char_filter列表
"filter": [ "lowercase", "自定义filter名称" ] //filter,数组,内置filter和自定义filter列表
}
settings.analysis.tokenizer.<自定义tokenizer名称>
{
"type": "pattern", //要修改的tokenizer类型名称
"pattern": "[ .,!?]" //要修改的属性
}
settings.analysis.char_filter.<自定义char_filter名称>
{
"type":"mapping", //要修改的char_filter类型名称
"mappings":[balabala...] //要修改的属性
}
settings.analysis.filter.<自定义filter名称>
{
"type":"stop", //要修改的filter类型名称
"stopwords": "_english_" //要修改的属性
}
简言之,格式为在analysis的子节点中添加各种自定义模块,从中选择1个tokenizer,0个或多个char_filter,0个或多个filter组成自定义分析器Analyzer。
3. 应用Analyzer
Analyzer应用在2个场景:
- 索引(index,在索引中插入数据时进行文本分析)
- 搜索(search,搜索时对搜索词进行文本分析)
3.1. 索引场景
指定index的分析器Analyzer。
大多数情况下,在创建index时,在mapping参数中为每一个text field都指定一下analyzer是最好的实践。这样的情况下,使用[indexName]/_mapping就能看到每一个text字段的分词器设置。用index templates也可以。
3.1.1. 为某个字段指定分析器
创建索引index时,在mapping参数中指定。
curl -X PUT "localhost:9200/my-index-000001?pretty" -H 'Content-Type: application/json' -d'
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "whitespace"
}
}
}
}
'
3.1.2. 为index指定默认的分析器
创建或者更新index的settings时,指定analysis.analyzer.default参数。参数值的类型就是自定义analyzer的类型。
curl -X PUT "172.22.69.39:9210/ibase-reserved-ansj/_settings?pretty" -H 'Content-Type: application/json' -d'
{
"index": {
"analysis": {
"analyzer": {
"cmpv2_ansj": {
"type": "custom",
"tokenizer": "index_ansj",
"char_filter": [
"html_strip"
]
},
"default": {
"type": "custom",
"tokenizer": "index_ansj",
"char_filter": [
"html_strip"
]
}
}
}
}
}
'
3.2. 搜索场景
指定搜索的分析器。
3.2.1. search检索中,指定分析器。
curl -X GET "localhost:9200/my-index-000001/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"match": {
"message": {
"query": "Quick foxes",
"analyzer": "stop"
}
}
}
}
'
3.2.2. 在创建index时,mapping参数中,指定text字段的search_analyzer参数。
curl -X PUT "localhost:9200/my-index-000001?pretty" -H 'Content-Type: application/json' -d'
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "whitespace",
"search_analyzer": "simple"
}
}
}
}
'
3.2.3. 在创建index时,在analysis.analyzer参数中,指定default_search字段。即analysis.analyzer.default_search参数。如果设置这个参数,那么analysis.analyzer.default参数也得设置。
curl -X PUT "localhost:9200/my-index-000001?pretty" -H 'Content-Type: application/json' -d'
{
"settings": {
"analysis": {
"analyzer": {
"default": {
"type": "simple"
},
"default_search": {
"type": "whitespace"
}
}
}
}
}
'
如果上面3种都没有设置,那么会使用field中的analyzer参数值。也就是index时的analyzer。
4. 测试Analyzer
可以直接使用/_analyze来测试分词效果。
curl -X POST "localhost:9200/my-index-000001/_analyze?pretty" -H 'Content-Type: application/json' -d'
{
"analyzer": "my_custom_analyzer",
"text": "I\u0027m a :) person, and you?"
}
'
也可以使用/_search来检索
curl -X GET "localhost:9200/my-index-000001/_search?pretty" -H 'Content-Type: application/json' -d'
{
"query": {
"match": {
"message": {
"query": "Quick foxes",
"analyzer": "stop"
}
}
}
}
'