ES3_2分析

搜索的前提是分析文档和搜索词。

分析器和倒排索引

一个倒排索引由文档中所有不重复词的列表构成,对于其中每个词,有一个包含它的文档列表。建立倒排索引的过程称为分析,执行分析过程的程序称为 分析器

  1. 字符过滤器(Character Filters):字符串按顺序通过每个 字符过滤器 。他们的任务是在分词前整理字符串。一个字符过滤器可以用来去掉 HTML,或者将 & 转化成 and
  2. 分词器(Tokenizer):将待索引的内容拆分成单独的 词(我们称它为 词条tokens ),创建一个包含所有不重复词条的排序列表,然后列出每个词条出现在哪个文档。
  3. Token 过滤器:删除无用词(a、and、the 等),合并统一大小写后相同的词(Quick 和 quick)、具有相同词根的词(fox 和 foxes),增加同义词(jump 和 leap)等。

内置分析器

“Set the shape to semi-transparent by calling set_trans(5)”

  1. 标准分析器
    标准分析器是 Elasticsearch 默认使用的分析器。它是分析各种语言文本最常用的选择。它根据 Unicode 联盟 定义的 单词边界 划分文本(standard 分词器)。删除绝大部分标点(standard 语汇单元过滤器)。最后将词条小写(lowercase 语汇单元过滤器),stop 语汇单元过滤器是被禁用的,它会删除停用词–对搜索相关性影响不大的常用词,如 a , the , and , is ,如需启用它,你可以通过创建一个基于 standard 分析器的自定义分析器并设置 stopwords 参数,可以给分析器提供一个停用词列表,或者告知使用一个基于特定语言的预定义停用词列表。。它会产生:
    set, the, shape, to, semi, transparent, by, calling, set_trans, 5
  2. 简单分析器
    简单分析器在任何不是字母的地方分隔文本,将词条小写。它会产生:
    set, the, shape, to, semi, transparent, by, calling, set, trans
  3. 空格分析器
    空格分析器在空格的地方划分文本。它会产生:
    Set, the, shape, to, semi-transparent, by, calling, set_trans(5)
  4. 语言分析器
    特定语言分析器可用于 很多语言。它们可以考虑指定语言的特点。例如, 英语 分析器附带了一组英语无用词(常用单词,例如 and 或者 the ,它们对相关性没有多少影响),它们会被删除。 由于理解英语语法的规则,这个分词器可以提取英语单词的 词干 。英语 分词器会产生下面的词条(注意看 transparentcalling 和 set_trans 已经变为词根格式):
    set, shape, semi, transpar, call, set_tran, 5

常用字符过滤器

https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-charfilters.html
字符过滤器用来整理 一个尚未被分词的字符串:

  1. Html 擦除字符过滤器
    擦除像

    这样的 HTML 标签,以及将像&Aacute转换为相对应的 Unicode 字符Á。

常用分词器

https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-tokenizers.html
分词器把字符串分解成单个词条或者词汇单元:

  1. 标准分词器
    把一个字符串根据单词边界分解成单个词条,并且移除掉大部分的标点符号。
  2. 关键词分词器
    完整地输出 接收到的同样的字符串,并不做任何分词。
  3. 空格分词器
    只根据空格分割文本 。
  4. 正则分词器
    根据匹配正则表达式来分割文本。

常用词单元过滤器

https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-tokenfilters.html
词单元过滤器可以修改、添加或者移除词单元:

  1. lowercase
  2. stop
  3. 词干
    把单词 遏制 为 词干。
  4. ascii_folding
    移除变音符,把一个像 “très” 这样的词转换为 “tres” 。
  5. ngram 和 edge_ngram
    可以产生 适合用于部分匹配或者自动补全的词单元。

自定义分析器

  • 一个分析器可以有多个过滤器唯一一个分词器,自定义分析器的格式如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    PUT /my_index
    {
    "settings": {
    "analysis": {
    "char_filter": { ... custom character filters ... },
    "tokenizer": { ... custom tokenizers ... },
    "filter": { ... custom token filters ... },
    "analyzer": { ... custom analyzers ... }
    }
    }
    }
  • 下面创建了一个新的分析器,叫做 es_std , 并使用预定义的 西班牙语停用词列表:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    PUT /spanish_docs
    {
    "settings": {
    "analysis": {
    "analyzer": {
    "es_std": {
    "type": "standard",
    "stopwords": "_spanish_"
    }
    }
    }
    }
    }
    es_std 分析器不是全局的–它仅仅存在于我们定义的 spanish_docs 索引中。 为了使用 analyze API 来对它进行测试,我们必须使用特定的索引名,这会发现停用词 El 已被正确移除:
    1
    2
    3
    4
    5
    GET /spanish_docs/_analyze
    {
    "analyzer": "es_std",
    "text": "El veloz zorro marrón"
    }
  • 下面这个分析器除了使用 Html 擦除字符过滤器移除 HTML 部分、标准分词器分词、lowercase 词过滤器将单词转为小写,还使用一个自定义的字符过滤器把&替换为and,一个自定义停词过滤器移除自定义的停止词列表中包含的词:
    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" ]
    }}
    }}}
    调用下面的接口来测试:
    1
    2
    3
    4
    5
    GET /my_index/_analyze
    {
    "analyzer": "my_analyzer",
    "text": "The quick & brown fox"
    }
    这个分析器现在是没有多大用处的,除非我们告诉 Elasticsearch在哪里用上它。我们可以像下面这样把这个分析器应用在一个 string 字段上:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    PUT /my_index/_mapping/my_type
    {
    "properties": {
    "title": {
    "type": "string",
    "analyzer": "my_analyzer"
    }
    }
    }

分析器使用时机

  1. 索引一个文档时,它的全文域(包括自动给出的**_all**)被分析成词条以用来创建倒排索引。
    具体的,当 Elasticsearch 在你的文档中检测到一个新的字符串域 ,它会自动设置其为一个全文 字符串 域,使用 标准 分析器对它进行分析。
  2. 还有在全文域搜索的时候,需要将查询字符串通过 相同的分析过程 ,以保证我们搜索的词条格式与索引中的词条格式一致(当查询一个精确值域时不会分析)。
  3. 或者直接使用以下链接测试分析器:
    1
    2
    3
    4
    5
    GET /_analyze
    {
    "analyzer": "standard",
    "text": "Text to analyze"
    }
    结果中的每个 token 都代表一个实际存储到索引中的词条, position 指明词条在原始文本中出现的位置。 start_offset 和 end_offset 指明字符在原始字符串中的位置。

自然语言与查询Recall

在处理人类自然语言时,有些情况,尽管搜索和原文不完全匹配,但是还是希望搜到一些内容(也即提升recall值):

  • 归一化词元:比如played被转换为play。
  • 抽取词根:清除单复述和时态的差异
  • 包含同义词
  • 拼写错误、同音异形词等

中文分词方法的演变

  • 查字典
    从左往右扫描一次,遇到有的词就标示出来,复合词就找最长的,不认识的就分割成单字词。
  • 最小词数的分词理论
    查字典方法的理论化
    但仍有二义性问题
  • 统计语言模型
    解决二义性问题
  • 基于统计的机器学习算法

中文分词器的现状是以统计语言模型为基础,使用机器学习算法和词典相结合的方式实现,一方面能够提高分词准确率,另一方面能够改善领域适应性。
不同分词器的好坏,主要差别在于数据的使用和工程使用的精度

一些中文分词器

  • HanLP
  • IK

混合多语言的场景

一些混合多语言的场景:

  • 不同的索引使用不同的语言
  • 同一个索引中,不同的字段使用不同的语言
  • 一个文档的一个字段内混合不同的语言

混合多语言存在的一些挑战:

  • 词干提取:一些中文文本中可能穿插了英文、拼音等。
  • 不正确的文档频率:根据TF/IDF算法,匹配到的稀有词的算分可能会比较高,比如英文中出现的德文。
  • 语言识别:识别用户输入的语言

分词挑战:

  • 英文分词
    You’re、Half-baked这种词要不要切分、分成一个还是多个
  • 中文分词
    具体情况需制定不同的标准:哈工大标准中姓和名分开,HanLP是在一起的
    歧义(组合型歧义、交集型歧义、真歧义)

分析 - demo

1、standard

1
2
3
4
5
GET _analyze
{
"analyzer": "standard",
"text": "2 Hello World! you are well-come!"
}

注意结果中的:

  • 按词切分,因此2会出现在结果中
  • 大写的Hello和World被转换成小写了
  • are这些停用词没有被真正去掉

2、simple

1
2
3
4
5
GET _analyze
{
"analyzer": "simple",
"text": "2 Hello World! you are well-come!"
}
  • 按照非字母切分,非字母的都被去除,2也会被去掉
  • 转小写处理

3、whitespace

1
2
3
4
5
GET _analyze
{
"analyzer": "whitespace",
"text": "2 Hello World! you are well-come!"
}
  • 按空格切分,”-“、”!”还是保留的

4、stop

1
2
3
4
5
GET _analyze
{
"analyzer": "stop",
"text": "2 Hello World! you are well-come!"
}
  • 相对simple Analyzer,多了停用词的过滤,因此are这些词会被去掉

5、keyword

1
2
3
4
5
GET _analyze
{
"analyzer": "keyword",
"text": "2 Hello World! you are well-come!"
}
  • 没有进行任何处理

6、pattern

1
2
3
4
5
GET _analyze
{
"analyzer": "pattern",
"text": "2 Hello World! you are well-come!"
}
  • 按正则表达式分割,默认按\W+识别

7、language analyzers
按语言分析

1
2
3
4
5
GET _analyze
{
"analyzer": "english",
"text": "2 Hello World! you are well-come, evening! 你好"
}
  • evening被改成了even,英文词被转换了

中文的词之间没有空格分隔,而且根据上下文不同也会有不同的分词方式,可以下载ICU插件实现中文分词:
https://blog.csdn.net/qq_34069839/article/details/107639301

1
2
3
4
5
GET _analyze
{
"analyzer": "icu_analyzer",
"text": "2 Hello World! you are well-come, evening! 你好"
}

除了icu分词器外,还有ik、thulac等。

参考

  1. HanLP官网
  2. HanLP分词器的ES插件