ElasticSearch【有与无】【搜索引擎】【ES22】同义词【选读】

目录

1.简介

1.1.使用同义词

1.2.同义词格式

1.3.扩展或收缩

简单扩展

简单收缩

类型扩展

1.4.同义词和分析链

大小写敏感的同义词

1.5.多词同义词和短语查询

使用简单收缩进行短语查询

同义词与 query_string 查询

1.6.符号同义词


1.简介

词干提取:通过简化他们的词根形式来扩大搜索的范围

同义词:通过相关的观念和概念来扩大搜索范围
 

通常我们会对语言中的每一个词去尝试提供同义词以确保任何一个文档都是可发现的,以保证不管文档之间有多么微小的关联性都能够被检索出来。

这样做是不对的。
就像我们更喜欢不用或少用词根而不是过分使用词根一样,同义词也应该只在必要的时候使用。 
这是因为用户可以理解他们的搜索结果受限于他们的搜索词,如果搜索结果看上去几乎是随机时,他们就会变得无法理解
同义词扩大了一个匹配文件的范围。
正如 词干提取 或者 部分匹配 ,同义词的字段不应该被单独使用,而应该与一个针对主字段的查询操作一起使用,这个主字段应该包含纯净格式的
原始文本。在使用同义词时,参阅 [most-fields] 的解释来维护相关性。

1.1.使用同义词

同义词可以取代现有的语汇单元 或 通过使用 [同义词 语汇单元过滤器],添加到语汇单元流中

【举例】

PUT /my_index
{
  "settings": {
    "analysis": {
      "filter": {
        "my_synonym_filter": {
          "type": "synonym",  // 定义了一个 同义词 类型的语汇单元过滤器
          "synonyms": [  // 同义词格式
            "british,english",
            "queen,monarch"
          ]

        }
      },
      "analyzer": {
        "my_synonyms": {
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "my_synonym_filter" // 创建了一个使用 my_synonym_filter 的自定义分析器
          ]
        }
      }
    }
  }
}

同义词可以使用 synonym 参数来内嵌指定,或者必须 存在于集群每一个节点上的同义词文件中。 
同义词文件路径由 synonyms_path 参数指定,应绝对或相对于 Elasticsearch config 目录。
参照 [updating-stopwords] 的技巧,可以用来刷新的同义词列表。

【测试】

GET /my_index/_analyze?analyzer=my_synonyms
Elizabeth is the English queen
Pos 1: (elizabeth)
Pos 2: (is)
Pos 3: (the)
Pos 4: (british,english)  // 所有同义词与原始词项占有同一个位置
Pos 5: (queen,monarch)    // 所有同义词与原始词项占有同一个位置

这样的一个文件将匹配任何以下的查询: English queen 、British queen 、 English monarch 或 British monarch 。 即使是一个短语查询也将会工作,因为每个词项的位置已被保存。

在索引和搜索中使用相同的同义词语汇单元过滤器是多余的。 
如果在索引的时候,我们用 english 和 british 这两个术语代替 English , 然后在搜索的时候,只需要搜索这些词项中的一个。
或者,如果在索引的时候不使用同义词,然后在搜索的时候,将需要把对 English 的查询转换为 english 或者 british 的查询。

是否在搜索或索引的时候做同义词扩展可能是一个困难的选择。我们将探索更多的选择 扩展或收缩。

1.2.同义词格式

同义词最简单的表达形式是 逗号分隔:"jump,leap,hop"

如果遇到这些词项中的任何一项,则将其替换为所有列出的同义词。例如:

或者, 使用  语法,可以指定一个词项列表(在左边),和一个或多个替换(右边)的列表:

"u s a,united states,united states of america => usa"
"g b,gb,great britain => britain,england,scotland,wales"

如果多个规则指定同一个同义词,它们将被合并在一起,且顺序无关,否则使用最长匹配。以下面的规则为例:

"united states            => usa",
"united states of america => usa"

如果这些规则相互冲突,Elasticsearch 会将 United States of America 转换为词项 (usa),(of),(america) 。否则,会使用最长的序列,即最终得到词项 (usa) 。

 

1.3.扩展或收缩

在 同义词格式 中,可以通过 简单扩展 、 简单收缩 、或类型扩展 来指明同义词规则。

 

简单扩展

通过 简单扩展 ,可以把同义词列表中的任意一个词扩展成同义词列表 所有 的词:

"jump,hop,leap"

扩展可以应用在索引阶段或查询阶段。两者都有优点 (⬆)︎ 和缺点 (⬇)︎。到底要在哪个阶段使用,则取决于性能与灵活性:

 索引查询

索引的大小

⬇︎ 大索引。因为所有的同义词都会被索引,所以索引的大小相对会变大一些。

⬆︎ 正常大小。

关联

⬇︎ 所有同义词都有相同的 IDF,这意味着通用的词和较常用的词都拥有着相同的权重。

⬆︎ 每个同义词 IDF 都和原来一样。

性能

⬆︎ 查询只需要找到查询字符串中指定单个词项。

⬇︎ 对一个词项的查询重写来查找所有的同义词,从而降低性能。

灵活性

⬇︎ 同义词规则不能改变现有的文件。对于有影响的新规则,现有的文件都要重建(注:重新索引一次文档)。

⬆︎ 同义词规则可以更新不需要索引文件。

 

 

 

 

 

 

 

 

简单收缩

简单收缩 ,把 左边的多个同义词映射到了右边的单个词:

"leap,hop => jump"

它必须同时应用于索引和查询阶段,以确保查询词项映射到索引中存在的同一个值。

相对于简单扩展方法,这种方法也有一些优点和一些缺点:

  • 索引的大小

       ⬆︎ 索引大小是正常的,因为只有单一词项被索引。

  • 关联

       ⬇︎ 所有词项的 IDF 是一样的,所以不能区分比较常用的词、不常用的单词。

  • 性能

       ⬆︎ 查询只需要在索引中找到单词的出现。

  • 灵活性

       ⬆︎ 新同义词可以添加到规则的左侧并在查询阶段使用。

例如,我们想添加 bound 到先前指定的同义词规则中。那么下面的规则将作用于包含 bound 的查询或包含 bound 的文档索引:

"leap,hop,bound => jump"

似乎对旧有的文档不起作用是么?其实可以把上面这个同义词规则改写下,以便对旧有文档同样起作用

"leap,hop,bound => jump,bound"

当重建索引文件,可以恢复到上面的规则来获得查询单个词项的性能优势。

 

类型扩展

类型扩展是完全不同于简单收缩 或扩张, 并不是平等看待所有的同义词,而是扩大了词的意义,使被拓展的词更为通用。以这些规则为例:

"cat    => cat,pet",
"kitten => kitten,cat,pet",
"dog    => dog,pet"
"puppy  => puppy,dog,pet"

通过在索引阶段使用类型扩展:

  • 一个关于 kitten 的查询会发现关于 kittens 的文档。
  • 查询一个 cat 会找到关于 kittens 和 cats 的文档。
  • 一个 pet 的查询将发现有关的 kittens、cats、puppies、dogs 或者 pets 的文档。

或者在查询阶段使用类型扩展, kitten 的查询结果就会被拓展成涉及到 kittens、cats、dogs。

可以有两全其美的办法,通过在索引阶段应用类型扩展同义词规则,以确保类型在索引中存在。然后,在查询阶段, 你可以选择不采用同义词(使 kitten 查询只返回 kittens 的文件)或采用同义词, kitten 的查询操作就会返回包括 kittens、cats、pets(也包括 dogs 和 puppies)的相关结果。

前面的示例规则,对 kitten 的 IDF 将是正确的,而 cat 和 pet 的 IDF 将会被 Elasticsearch 降权。然而, 这是对你有利的,当一个针对 kitten 的查询被拓展成了针对 kitten OR cat OR pet 的查询, 那么 kitten 相关的文档就应该排在最上方,其次是 cat 的文件, pet 的文件将被排在最底部。

 

1.4.同义词和分析链

使用 usa 来举例阐述一些同义词相关的知识。那么为什么 使用的不是 U.S.A. 呢?原因是, 这个 同义词 的语汇单元过滤器只能接收到在它前面的语汇单元过滤器或者分词器的输出结果。

假设有一个分析器,它由 standard 分词器、 lowercase 的语汇单元过滤器、 synonym 的语汇单元过滤器组成。文本 U.S.A. 的分析过程,看起来像这样的:

original string(原始文本)                                  → "U.S.A."
standard            tokenizer(分词器)                  → (U),(S),(A)
lowercase          token filter(语汇单元过滤器)  → (u),(s),(a)
synonym            token filter(语汇单元过滤器)  → (usa)

如果指定的同义词 U.S.A. ,它永远不会匹配任何东西。因为, my_synonym_filter 看到词项的时候,句号已经被移除了,并且字母已经被小写了。

这其实是一个非常需要注意的地方。如果想同时使用同义词特性与词根提取特性,那么 jumps 、jumped 、jump 、leaps 、leaped 和 leap 这些词是否都会被索引成一个 jump ? 

可以把同义词过滤器放置在词根提取之前,然后把所有同义词以及词形变化都列举出来:

"jumps,jumped,leap,leaps,leaped => jump"

但更简洁的方式将同义词过滤器放置在词根过滤器之后,然后把词根形式的同义词列举出来:

"leap => jump"

 

大小写敏感的同义词

通常,我们把同义词过滤器放置在 lowercase 语汇单元过滤器之后,因此,所有的同义词 都是小写。 但有时会导致奇怪的合并。

"CAT,CAT scan           => cat_scan"
"PET,PET scan           => pet_scan"
"Johnny Little,J Little => johnny_little"
"Johnny Small,J Small   => johnny_small"

大小不敏感的同义词规则

"cat                    => cat,pet"
"dog                    => dog,pet"
"cat scan,cat_scan scan => cat_scan"
"pet scan,pet_scan scan => pet_scan"
"little,small"

 

1.5.多词同义词和短语查询

为了能使 短语查询 正常工作, Elasticsearch 需要知道每个词在初始文本中的位置。多词同义词会严重破坏词的位置信息,尤其当新增的同义词标记长度各不相同的时候。

【举例】
PUT /my_index
{
  "settings": {
    "analysis": {
      "filter": {
        "my_synonym_filter": {
          "type": "synonym",
          "synonyms": [
            "usa,united states,u s a,united states of america"
          ]

        }
      },
      "analyzer": {
        "my_synonyms": {
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "my_synonym_filter"
          ]
        }
      }
    }
  }
}

GET /my_index/_analyze?analyzer=my_synonyms&text=The United States is wealthy

【结果】

Pos 1:  (the)
Pos 2:  (usa,united,u,united)
Pos 3:  (states,s,states)
Pos 4:  (is,a,of)
Pos 5:  (wealthy,america)

如果你用上面这个同义词语汇单元过滤器索引一个文档,然后执行一个短语查询,那你就会得到惊人的结果,下面这些短语都不会匹配成功:

  • The usa is wealthy
  • The united states of america is wealthy
  • The U.S.A. is wealthy

但是这些短语会:

  • United states is wealthy
  • Usa states of wealthy
  • The U.S. of wealthy
  • U.S. is america

如果在查询阶段使同义词,那你就会看到更加诡异的匹配结果。看下这个 validate-query 查询:

GET /my_index/_validate/query?explain
{
  "query": {
    "match_phrase": {
      "text": {
        "query": "usa is wealthy",
        "analyzer": "my_synonyms"
      }
    }
  }
}

查询关键字会被同义词语汇单元过滤器处理成类似这样的信息:

"(usa united u united) (is states s states) (wealthy a of) america"

这会匹配包含有 u is of america 的文档,但是匹配不出任何含有 america 的文档。

多词同义对高亮匹配结果也会造成影响。一个针对 USA 的查询,返回的结果可能却高亮了: The United States is wealthy 。

使用简单收缩进行短语查询

避免这种混乱的方法是使用 简单收缩, 用单个词项表示所有的同义词, 然后在查询阶段,就只需要针对这单个词进行查询了:

【举例】

PUT /my_index
{
  "settings": {
    "analysis": {
      "filter": {
        "my_synonym_filter": {
          "type": "synonym",
          "synonyms": [
            "united states,u s a,united states of america=>usa"
          ]
        }
      },
      "analyzer": {
        "my_synonyms": {
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "my_synonym_filter"
          ]
        }
      }
    }
  }
}

GET /my_index/_analyze?analyzer=my_synonyms
The United States is wealthy

上面那个查询信息就会被处理成类似下面这样:

Pos 1:  (the)
Pos 2:  (usa)
Pos 3:  (is)
Pos 5:  (wealthy)

现在再次执行我们之前做过的那个 validate-query 查询,就会输出一个简单又合理的结果:"usa is wealthy"

这个方法的缺点是,因为把 united states of america 转换成了同义词 usa, 不能使用 united states of america 去搜索出 united 或者 states 。 需要使用一个额外的字段并用另一个解析器链来达到这个目的。

 

同义词与 query_string 查询

由于 query_string 查询支持一个精简的 查询语法 ,因此,可能这会导致它搜出一些出人意料的结果或者甚至是含有语法错误的结果。

这种查询方式存在不少问题,而其中之一便与多词同义有关。为了支持它的查询语法,你必须用指定的、该语法所能识别的操作符号来标示,比如 AND 、 OR 、 + 、 - 、 field: 等等。

而在这种语法的解析过程中,解析动作会把查询文本在空格符处作切分,然后分别把每个切分出来的词传递给相关性解析器。 这也即意味着你的同义词解析器永远都不可能收到类似 United States 这样的多个单词组成的同义词。由于不会把 United States作为一个原子性的文本,所以同义词解析器的输入信息永远都是两个被切分开的词 United 和 States 。

所幸, match 查询相比而言就可靠得多了,因为它不支持上述语法,所以多个字组成的同义词不会被切分开,而是会完整地交给解析器处理。

 

1.6.符号同义词

符号同义词 是用别名来表示这个符号,以防止它在分词过程中被误认为是不重要的标点符号而被移除。

【举例】

PUT /my_index
{
  "settings": {
    "analysis": {
      "char_filter": {
        "emoticons": {
          "type": "mapping",
          "mappings": [  // 映射 过滤器把字符从  左边的格式转变成右边的样子。
            ":)=>emoticon_happy",
            ":(=>emoticon_sad"
          ]

        }
      },
      "analyzer": {
        "my_emoticons": {
          "char_filter": "emoticons",
          "tokenizer":   "standard",
          "filter":    [ "lowercase" ]

          ]
        }
      }
    }
  }
}

GET /my_index/_analyze?analyzer=my_emoticons
I am :) not :( 

输出: i 、 am 、 emoticon_happy 、 not 、 emoticon_sad

很少有人会搜 emoticon_happy 这个词,但是确保类似字符表情的这类重要符号被存储到索引中是非常好的做法,在进行情感分析的时候会很有用。当然,我们也可以用真实的词汇来处理符号同义词,比如: happy 或者 sad 。

提示: 映射 字符过滤器是个非常有用的过滤器,它可以用来对一些已有的字词进行替换操作, 如果想要采用更灵活的正则表达式去替换字词的话,那你可以使用[pattern_replace ]字符过滤器。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

琴 韵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值