ES学习——分析器和自定义分析器

简介

es在对文档进行倒排索引的需要用分析器(Analyzer)对文档进行分析、建立索引。从文档中提取词元(Token)的算法称为分词器(Tokenizer),在分词前预处理的算法称为字符过滤器(Character Filter),进一步处理词元的算法称为词元过滤器(Token Filter),最后得到词(Term)。这整个分析算法称为分析器(Analyzer)。

其工作流程:

  1. 先会使用字符过滤器CharacterFilters对文档中的不需要的字符过滤(例如html语言的\<br/>等等)
  2. Tokenizer分词器大段的文本分成词(Tokens)(例如可以空格基准对一句话进行分词)
  3. 最后用TokenFilter在对分完词的Tokens进行过滤、处理(比如除去英文常用的量词:a,the,或者把去掉英文复数等)
    图片

我们可以使用_analyze来看es的分词是不是符合我们的预期目标,我们使用默认的分析器对下面这句话进行分析。结果包括token,起始的偏移量,类型和序号。我目前先只关注token即可。

1
2
3
4
GET /jindouwin_search_group/_analyze
{
"text": "Her(5) a Black-cats"
}

结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
{
"tokens": [
{
"token": "her",
"start_offset": 0,
"end_offset": 3,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "5",
"start_offset": 4,
"end_offset": 5,
"type": "<NUM>",
"position": 1
},
{
"token": "a",
"start_offset": 7,
"end_offset": 8,
"type": "<ALPHANUM>",
"position": 2
},
{
"token": "black",
"start_offset": 9,
"end_offset": 14,
"type": "<ALPHANUM>",
"position": 3
},
{
"token": "cats",
"start_offset": 15,
"end_offset": 19,
"type": "<ALPHANUM>",
"position": 4
}
]
}

从结果看出,分词器先去掉了一些无用的符号,再把一句话分为Her、5、a、Black、cats,在用TokenFilter过滤大小写。

分析器

es中除了standard标准分析器外,还有englishstoplower等等。我们来看下使用english分析器来解析同一句话的效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
GET /jindouwin_search_group/_analyze
{
"text": "Her(5) a Black-cats" ,
"analyzer": "english"
}
结果:
{
{
"tokens": [
{
"token": "her",
"start_offset": 0,
"end_offset": 3,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "5",
"start_offset": 4,
"end_offset": 5,
"type": "<NUM>",
"position": 1
},
{
"token": "black",
"start_offset": 9,
"end_offset": 14,
"type": "<ALPHANUM>",
"position": 3
},
{
"token": "cat",
"start_offset": 15,
"end_offset": 19,
"type": "<ALPHANUM>",
"position": 4
}
]
}
}

可以明显的看出,english去掉了一些常用词(a),和把cats的复数形式去掉了。

当然es的强大之处在于除了内置的分词器之外,我们可以自定义分析器,通过组装CharacterFilters、Tokenizer、TokenFilter三个不同组件来自定义分析器或者可以使用别人完成的分析器,最出名的就是ik中文分词插件。
除此之外我们也可以CharacterFilters、Tokenizer、TokenFilter进行自定义。
关于一些内置的分析器种类,这里不一一分析,大家可以在官网进行翻阅。

自定义分析器

官网示例:
作为示范,让我们一起来创建一个自定义分析器吧,这个分析器可以做到下面的这些事:

  1. 使用 html清除 字符过滤器移除HTML部分。
  2. 使用一个自定义的 映射 字符过滤器把 & 替换为 “ and “ :

    1
    2
    3
    4
    5
    6
    "char_filter": {
    "&_to_and": {
    "type": "mapping",
    "mappings": [ "&=> and "]
    }
    }
  3. 使用 标准 分词器分词。

  4. 小写词条,使用 小写 词过滤器处理。
  5. 使用自定义 停止 词过滤器移除自定义的停止词列表中包含的词:
    1
    2
    3
    4
    5
    6
    "filter": {
    "my_stopwords": {
    "type": "stop",
    "stopwords": [ "the", "a" ]
    }
    }

我们的分析器定义用我们之前已经设置好的自定义过滤器组合了已经定义好的分词器和过滤器:

1
2
3
4
5
6
7
8
"analyzer": {
"my_analyzer": {
"type": "custom",
"char_filter": [ "html_strip", "&_to_and" ],
"tokenizer": "standard",
"filter": [ "lowercase", "my_stopwords" ]
}
}

汇总起来,完整的 创建索引 请求 看起来应该像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
PUT /my_index
{
"settings": {
"analysis": {
"char_filter": {
"&_to_and": {
"type": "mapping",
"mappings": [ "&=> and "]
}},
"filter": {
"my_stopwords": {
"type": "stop",
"stopwords": [ "the", "a" ]
}},
"analyzer": {
"my_analyzer": {
"type": "custom",
"char_filter": [ "html_strip", "&_to_and" ],
"tokenizer": "standard",
"filter": [ "lowercase", "my_stopwords" ]
}}
}}}

索引被创建以后,使用 analyze API 来 测试这个新的分析器:

1
2
3
4
5
GET /my_index1/_analyze
{
"analyzer":"my_analyzer",
"text": "The quick & brown fox"
}

拷贝为 CURL在 SENSE 中查看
下面的缩略结果展示出我们的分析器正在正确地运行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
{
"tokens": [
{
"token": "quick",
"start_offset": 4,
"end_offset": 9,
"type": "<ALPHANUM>",
"position": 1
},
{
"token": "and",
"start_offset": 10,
"end_offset": 11,
"type": "<ALPHANUM>",
"position": 2
},
{
"token": "brown",
"start_offset": 12,
"end_offset": 17,
"type": "<ALPHANUM>",
"position": 3
},
{
"token": "fox",
"start_offset": 18,
"end_offset": 21,
"type": "<ALPHANUM>",
"position": 4
}
]
}

这个分析器现在是没有多大用处的,除非我们告诉 Elasticsearch在哪里用上它。我们可以像下面这样把这个分析器应用在一个 string 字段上:

1
2
3
4
5
6
7
8
9
PUT /my_index/_mapping/my_type
{
"properties": {
"title": {
"type": "string",
"analyzer": "my_analyzer"
}
}
}

坚持原创技术分享,您的支持将鼓励我继续创作!