Elasticsearch 文本分析

Elasticsearch 文本分析

文本分析是将非结构化文本转换为针对搜索优化的结构化格式的过程。

文本分析简介

文本分析使 Elasticsearch 能够执行全文搜索,其中搜索返回所有相关结果,而不仅仅是完全匹配。

文本分析可以分为两个方面:

  • Tokenization(分词化) - 分析通过分词化使全文搜索成为可能:将文本分解成更小的块,称为分词。在大多数情况下,这些标记是单独的 term(词项)。
  • Normalizeation(标准化) - 经过分词后的文本只能进行词项匹配,但是无法进行同义词匹配。为解决这个问题,可以将文本进行标准化处理。例如:将 foxes 标准化为 fox

Analyzer(分析器)

文本分析由 analyzer(分析器) 执行,分析器是一组控制整个过程的规则。无论是索引还是搜索,都需要使用分析器。

analyzer(分析器) 由三个组件组成:零个或多个 Character Filters(字符过滤器)、有且仅有一个 Tokenizer(分词器)、零个或多个 Token Filters(分词过滤器)

它的执行顺序如下:

1
character filters -> tokenizer -> token filters

Elasticsearch 内置的分析器:

  • standard - 根据单词边界将文本划分为多个 term,如 Unicode 文本分割算法所定义。它删除了大多数标点符号、小写 term,并支持删除停用词。
  • simple - 遇到非字母字符时将文本划分为多个 term,并将其转为小写。
  • whitespace - 遇到任何空格时将文本划分为多个 term,不转换为小写。
  • stop - 与 simple 相似,同时支持删除停用词(如:the、a、is)。
  • keyword - 部分词,直接将输入当做输出。
  • pattern - 使用正则表达式将文本拆分为 term。它支持小写和非索引字。
  • fingerprint - 可创建用于重复检测的指纹。
  • 语言分析器 - 提供了 30 多种常见语言的分词器。

默认情况下,Elasticsearch 使用 standard analyzer(标准分析器),它开箱即用,适用于大多数使用场景。Elasticsearch 也允许定制分析器。

测试分析器

_analyze API 是查看分析器如何分词的工具。

::: details 【示例】直接指定 analyzer 进行测试

查看不同的 analyzer 的效果

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
GET _analyze
{
"analyzer": "standard",
"text": "2 running Quick brown-foxes leap over lazy dogs in the summer evening."
}

GET _analyze
{
"analyzer": "simple",
"text": "2 running Quick brown-foxes leap over lazy dogs in the summer evening."
}

GET _analyze
{
"analyzer": "stop",
"text": "2 running Quick brown-foxes leap over lazy dogs in the summer evening."
}

GET _analyze
{
"analyzer": "whitespace",
"text": "2 running Quick brown-foxes leap over lazy dogs in the summer evening."
}

GET _analyze
{
"analyzer": "keyword",
"text": "2 running Quick brown-foxes leap over lazy dogs in the summer evening."
}

GET _analyze
{
"analyzer": "pattern",
"text": "2 running Quick brown-foxes leap over lazy dogs in the summer evening."
}

:::

::: details 【示例】自由组合分析器组件进行测试

1
2
3
4
5
6
POST _analyze
{
"tokenizer": "standard",
"filter": [ "lowercase", "asciifolding" ],
"text": "Is this déja vu?"
}

:::

指定分析器

内置分析器可以直接使用,无需任何配置。但是,其中一些支持配置选项来更改其行为。

在搜索时,Elasticsearch 通过按顺序检查以下参数来确定要使用的分析器:

  1. 搜索查询中的 analyzer 参数。请参阅 指定查询的搜索分析器
  2. 字段的 search_analyzer 映射参数。请参阅 为字段指定搜索分析器
  3. analysis.analyzer.default_search 索引设置。请参阅 指定索引的默认搜索分析器
  4. 字段的 analyzer mapping 参数。请参阅 为字段指定分析器

如果未指定这些参数,则使用 standard 分析器。

::: details 【示例】设置索引的默认分析器

将 std_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
PUT my-index-000001
{
"settings": {
"analysis": {
"analyzer": {
"std_english": {
"type": "standard",
"stopwords": "_english_"
}
}
}
},
"mappings": {
"properties": {
"my_text": {
"type": "text",
"analyzer": "standard",
"fields": {
"english": {
"type": "text",
"analyzer": "std_english"
}
}
}
}
}
}

:::

::: details 【示例】设置字段的分析器

将字段 title 的分析器设为 whitespace

1
2
3
4
5
6
7
8
9
10
11
PUT my-index-000001
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "whitespace"
}
}
}
}

:::

::: details 【示例】指定查询的搜索分析器

1
2
3
4
5
6
7
8
9
10
11
GET my-index-000001/_search
{
"query": {
"match": {
"message": {
"query": "Quick foxes",
"analyzer": "stop"
}
}
}
}

:::

::: details 【示例】指定字段的搜索分析器

1
2
3
4
5
6
7
8
9
10
11
12
PUT my-index-000001
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "whitespace",
"search_analyzer": "simple"
}
}
}
}

:::

::: details 【示例】指定索引的默认搜索分析器

创建索引时,可以使用该 analysis.analyzer.default_search 设置设置默认搜索分析器。如果提供了搜索分析器,则还必须使用 analysis.analyzer.default 设置指定默认索引分析器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
PUT my-index-000001
{
"settings": {
"analysis": {
"analyzer": {
"default": {
"type": "simple"
},
"default_search": {
"type": "whitespace"
}
}
}
}
}

:::

自定义分析器

自定义分析器,需要指定 type 为 custom 类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
PUT my-index-000001
{
"settings": {
"analysis": {
"analyzer": {
"my_custom_analyzer": {
"type": "custom",
"tokenizer": "standard",
"char_filter": [
"html_strip"
],
"filter": [
"lowercase",
"asciifolding"
]
}
}
}
}
}

中文分词

在英文中,单词有自然的空格作为分隔。

在中文中,分词有以下难点:

  • 中文不能根据一个个汉字进行分词
  • 不同于英文可以根据自然的空格进行分词;中文中一般不会有空格。
  • 同一句话,在不同的上下文中,有不同个理解。例如:这个苹果,不大好吃;这个苹果,不大,好吃!

可以使用一些插件来获得对中文更好的分析能力:

  • analysis-icu - 添加了扩展的 Unicode 支持,包括更好地分析亚洲语言、Unicode 规范化、Unicode 感知大小写折叠、排序规则支持和音译。
  • elasticsearch-analysis-ik - 支持自定义词库,支持热更新分词字典
  • elasticsearch-thulac-plugin - 清华大学自然语言处理和社会人文计算实验室的一套中文分词器。

Character Filters(字符过滤器)

Character Filters(字符过滤器) 将原始文本作为字符流接收,并可以通过添加、删除或更改字符来转换文本。

分析器可以有零个或多个 Character Filters(字符过滤器),如果配置了多个,它会按照配置的顺序执行。

Elasticsearch 内置的字符过滤器:

  • html_strip - html_strip字符过滤器用于去除 HTML 元素(如 <b>)并转义 HTML 实体(如 &amp;)。
  • mapping - mapping 字符过滤器用于将指定字符串的任何匹配项替换为指定的替换项。
  • pattern_replace - pattern_replace 字符筛选器将匹配正则表达式的任何字符替换为指定的替换。

Tokenizer(分词器)

Tokenizer(分词器) 接收字符流,将其分解为分词(通常是单个单词),并输出一个分词流。

分词器还负责记录每个 term 的顺序或位置,以及该 term 所代表的原始单词的开始和结束字符偏移量。``

分析器有且仅有一个 Tokenizer(分词器)

Elasticsearch 内置的分词器:

  • 面向单词的分词器
    • standard - 将文本划分为单词边界上的 term,如 Unicode 文本分割算法所定义。它会删除大多数标点符号。它是大多数语言的最佳选择。
    • letter - 遇到非字母字符时将文本划分为多个 term。
    • lowercase - 到非字母字符时将文本划分为多个 term,并将其转为小写。
    • whitespace - 遇到任何空格时将文本划分为多个 term。
    • uax_url_email - 与 standard 相似,不同之处在于它将 URL 和电子邮件地址识别为单个分词。
    • classic - 基于语法的英语分词器。
    • thai - 将泰语文本分割为单词。
  • 部分单词分词器
    • n-gram - 遇到指定字符列表(例如空格或标点符号)中的任何一个时,将文本分解为单词,然后返回每个单词的 n-gram:一个连续字母的滑动窗口,例如 quick[qu, ui, ic, ck]
    • edge_n-gram - 遇到指定字符列表(例如空格或标点符号)中的任何一个时,将文本分解为单词,然后返回锚定到单词开头的每个单词的 n 元语法,例如 quick[q, qu, qui, quic, quick]
  • 结构化文本分词器
    • keyword - 接受给定的任何文本,并输出与单个 term 完全相同的文本。它可以与 lowercase 等分词过滤器结合使用,以规范化分析的 term。
    • pattern - 使用正则表达式在文本与单词分隔符匹配时将文本拆分为 term,或者将匹配的文本捕获为 term。
    • simple_pattern - 使用正则表达式将匹配的文本捕获为 term。它使用正则表达式特征的受限子集,并且通常比 pattern 更快。
    • char_group - 可以通过要拆分的字符集进行配置,这通常比运行正则表达式代价更小。
    • simple_pattern_split - 使用与 simple_pattern 分词器相同的受限正则表达式子集,但在匹配项处拆分输入,而不是将匹配项作为 term 返回。
    • path_hierarchy - 基于文件系统的路径分隔符,进行拆分,例如 /foo/bar/baz[/foo, /foo/bar, /foo/bar/baz ]

Token Filters(分词过滤器)

Token Filters(分词过滤器) 接收分词流,并可以添加、删除或更改分词。常用的分词过滤器有: lowercase(小写转换)stop(停用词处理)synonym(同义词处理) 等等。

分析器可以有零个或多个 Token Filters(分词过滤器),如果配置了多个,它会按照配置的顺序执行。

Elasticsearch 内置了很多分词过滤器,这里列举几个常见的:

参考资料