多词同义词和短语查询

至此,同义词看上去还挺简单的。然而不幸的是,复杂的部分才刚刚开始。为了能使 短语查询 正常工作, Elasticsearch 需要知道每个词在初始文本中的位置。多词同义词会严重破坏词的位置信息,尤其当新增的同义词标记长度各不相同的时候。

我们创建一个同义词语汇单元过滤器,然后使用下面这样的同义词规则:

  1. "usa,united states,u s a,united states of america"
  1. PUT /my_index
  2. {
  3. "settings": {
  4. "analysis": {
  5. "filter": {
  6. "my_synonym_filter": {
  7. "type": "synonym",
  8. "synonyms": [
  9. "usa,united states,u s a,united states of america"
  10. ]
  11. }
  12. },
  13. "analyzer": {
  14. "my_synonyms": {
  15. "tokenizer": "standard",
  16. "filter": [
  17. "lowercase",
  18. "my_synonym_filter"
  19. ]
  20. }
  21. }
  22. }
  23. }
  24. }
  25. GET /my_index/_analyze?analyzer=my_synonyms&text=
  26. The United States is wealthy

解析器 会输出下面这样的结果:

  1. Pos 1: (the)
  2. Pos 2: (usa,united,u,united)
  3. Pos 3: (states,s,states)
  4. Pos 4: (is,a,of)
  5. 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 查询:

  1. GET /my_index/_validate/query?explain
  2. {
  3. "query": {
  4. "match_phrase": {
  5. "text": {
  6. "query": "usa is wealthy",
  7. "analyzer": "my_synonyms"
  8. }
  9. }
  10. }
  11. }

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

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

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

[TIP]

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

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

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

  1. PUT /my_index
  2. {
  3. "settings": {
  4. "analysis": {
  5. "filter": {
  6. "my_synonym_filter": {
  7. "type": "synonym",
  8. "synonyms": [
  9. "united states,u s a,united states of america=>usa"
  10. ]
  11. }
  12. },
  13. "analyzer": {
  14. "my_synonyms": {
  15. "tokenizer": "standard",
  16. "filter": [
  17. "lowercase",
  18. "my_synonym_filter"
  19. ]
  20. }
  21. }
  22. }
  23. }
  24. }
  25. GET /my_index/_analyze?analyzer=my_synonyms
  26. The United States is wealthy

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

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

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

  1. "usa is wealthy"

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

同义词与 query_string 查询

本书很少谈论到 query_string 查询,因为真心不推荐你用它。 在 复杂查询 一节中有提到,由于 query_string 查询支持一个精简的 查询语法 ,因此,可能这会导致它搜出一些出人意料的结果或者甚至是含有语法错误的结果。

这种查询方式存在不少问题,而其中之一便与多词同义有关。为了支持它的查询语法,你必须用指定的、该语法所能识别的操作符号来标示,比如 ANDOR+-field: 等等。 (更多相关内容参阅 {ref}/query-dsl-query-string-query.html#query-string-syntax[query_string 语法] 。)

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

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