【问题标题】:match_phrase doesn't work well with Synonym Token Filter (genre expansion) in Elasticsearchmatch_phrase 不适用于 Elasticsearch 中的同义词标记过滤器(类型扩展)
【发布时间】:2019-08-29 04:57:01
【问题描述】:

更新:

在阅读了 Richa 的解释和推荐的blog post 后,问题似乎已经解决,但我需要更多测试才能确认。

首先,应按照 Richa 的建议更改同义词格式:

["green => khaki,green", "pet => cat,pet"]

然后,我必须在索引映射中指定search_analyzer 和index_analyzer:

  "mappings": {
    "properties": {
      "phone_case": {
        "type": "text",
        "norms": false,
        "index_analyzer": "standard",
        "search_analyzer": "lowercaseWhiteSpaceAnalyzer"
      }
    }
  }

在映射中添加这两个属性后,我不需要在查询中使用analyzer。

这些更改似乎使流派扩展在“term”和“match_phrase”查询中都能正常工作。


弹性搜索 7.2

同义词数据:

[ "khaki => khaki,green", "cat => cat,pet"]

索引映射:

{
    settings: {
        "analysis": {
            "char_filter": {
                "same_word": {
                    "type": "mapping",
                    "mappings": ["-=>", "&=>and"]
                },
            },
            "filter": {
                "my_stopwords": {
                    "type": "stop",
                    "stopwords": STOPWORD_FILE
                },
                "my_synonym": {
                    "type": "synonym",
                    "synonyms": [ "khaki => khaki,green", "cat => cat,pet"],
                    "tokenizer": "whitespace"
                },
            },
            "analyzer": {
                "lowercaseWhiteSpaceAnalyzer": {
                    "type": "custom",
                    "char_filter": ["html_strip", "same_word"],
                    "tokenizer": "standard",
                    "filter": [
                        "lowercase",
                        "my_stopwords",
                        "my_synonym",
                    ]
                },
            }
        }
    }
}

材料领域:

"phone_case":{"type":"text","norms":false,"analyzer":"lowercaseWhiteSpaceAnalyzer"}

示例文件:

 [
  {
      id: "1",
      phone_case: "khaki,brushed and polished",
  },
  {
      id: "2",
      phone_case: "green,brushed",
  },
  {
      id: "3",
      phone_case: "black,matte"
  }
]

“phone_case”字段是一个文本字段。

当我搜索 khaki 时,我想查找只有 khaki 结果的文档,不包括任何包含 green 的结果。另一方面,在搜索 green 时,我想获取带有 green 或 khaki 的文档。这应该是类型扩展应该做的。

术语级别查询适用于此类目的:

{
  "sort": [
    {
      "updated": {
        "order": "desc"
      }
    }
  ],
  "size": 10,
  "from": 0,
  "query": {
    "bool": {
      "filter": {
        "term": {
          "phone_case": "khaki"
        }
      }
    }
  }

它设法返回包含 khaki 的文档。

但使用 ma​​tch_phrase,它会返回带有 khaki 或 green 的文档。这不是我所期望的。我想获取包含 khaki 而不是 green 的文档:

{
  "sort": [
    {
      "updated": {
        "order": "desc"
      }
    }
  ],
  "size": 10,
  "from": 0,
  "query": {
    "match_phrase": {
      "phone_case": "khaki"
    }
  }
}

谁能告诉我 ma​​tch 查询无法排除包含“green”的结果有什么问题?我希望允许用户按确切顺序查找文本字段,但 ma​​tch 或 ma​​tch_phrase 不适用于 Genre Expansion Synonyms。

【问题讨论】:

  • 请分享您的索引和示例文档的映射
  • @Richa 你好,我刚刚包含了映射和示例文档。
  • 在描述中你有 When I search for "ceramic" I want to find documents with just "ceramic" results. When searching for "ceramic", I want to get documents with either "ceramic" or "cerachrom". 。我想,第二次是cerachrom
  • @Richa,感谢您指出错误。我只是更改了示例以使其更易于理解和阅读。

标签: node.js elasticsearch


【解决方案1】:

根据elastic documentation,当我们定义我们的同义词如a => b,c时,它被解析为

# Explicit mappings match any token sequence on the LHS of "=>"
# and replace with all alternatives on the RHS.  These types of mappings
# ignore the expand parameter in the schema.

因此,对于您的情况,"khaki => khaki,green",khaki 一词将替换为 khaki 和 green。这可以使用analyze api like

看到
GET stack-57703209/_analyze
{
  "text": "khaki",
  "analyzer": "lowercaseWhiteSpaceAnalyzer"
}

这会返回两个令牌,khaki 和 green。

{
  "tokens" : [
    {
      "token" : "khaki",
      "start_offset" : 0,
      "end_offset" : 5,
      "type" : "SYNONYM",
      "position" : 0
    },
    {
      "token" : "green",
      "start_offset" : 0,
      "end_offset" : 5,
      "type" : "SYNONYM",
      "position" : 0
    }
  ]
}

如果你检查green

GET stack-57703209/_analyze
{
  "text": "green",
  "analyzer": "lowercaseWhiteSpaceAnalyzer"
}

您将只获得一个令牌green。

{
  "tokens" : [
    {
      "token" : "green",
      "start_offset" : 0,
      "end_offset" : 5,
      "type" : "<ALPHANUM>",
      "position" : 0
    }
  ]
}

根据您的问题,您想要相反,因此理想情况下,同义词应如下所示

"green => khaki,green"
 not "khaki => khaki,green"

除此之外,您还在index 时间应用此分析器。因此,在索引您的文档时,khaki 一词被替换为 khaki 和 green 标记,正如我们在上面使用分析 api 看到的那样。

当您运行 Term Query 时,它会搜索确切的字词

{
  "sort": [
    {
      "updated": {
        "order": "desc"
      }
    }
  ],
  "size": 10,
  "from": 0,
  "query": {
    "bool": {
      "filter": {
        "term": {
          "phone_case": "khaki"
        }
      }
    }
  }

如果您搜索khaki,您只会得到第一个响应结果,因为术语查询不应用任何搜索分析器并且匹配确切的术语,因此它会查找khaki,而第二个文档phone_case: "green,brushed", 没有带有khaki 的令牌(可以使用analyze api 进行检查),因此不会返回。

但是,Match Query,默认应用与index analyzer 相同的分析器,在您的情况下为lowercaseWhiteSpaceAnalyzer。所以这两个文件都被退回了。

因此,根据您的要求,您需要search analyzer 而不是index analyzer,因此您可以将索引设置更改为

{
  "settings": {
    "analysis": {
      "char_filter": {
        "same_word": {
          "type": "mapping",
          "mappings": [
            "-=>",
            "&=>and"
          ]
        }
      },
      "filter": {
        "my_stopwords": {
          "type": "stop",
          "stopwords": "a, an"
        },
        "my_synonym": {
          "type": "synonym",
          "synonyms": [
            "green => khaki,green",      //NOTE THIS
            "cat => cat,pet"
          ],
          "tokenizer": "whitespace"
        }
      },
      "analyzer": {
        "lowercaseWhiteSpaceAnalyzer": {
          "type": "custom",
          "char_filter": [
            "html_strip",
            "same_word"
          ],
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "my_stopwords"
            ]
        },
        "synonym_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "my_synonym"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "phone_case": {
        "type": "text",
        "norms": false,
        "analyzer": "lowercaseWhiteSpaceAnalyzer"
      }
    }
  }
} 

然后指定search analyzer,例如

{
    "query": {
        "match_phrase": {
            "phone_case" : {
                "query" : "green",
                "analyzer" : "synonym_analyzer"  // NOTE THIS

            }
        }
    }
}

This 博客更详细地解释了这一点。 希望这会有所帮助!

【讨论】:

  • 感谢您的详细解释。它有很大帮助。但为了按预期进行类型扩展工作,我必须在索引映射中指定index_analyzer 和search_analyzer。添加它们后,我不需要在 match_phrase 查询中使用 analyzer 。请检查我更新的帖子,看看是否有遗漏的内容。
  • @RedGiant Yeah.. Search Anlayzer 也可以在设置中指定。
  • 使用多词同义词,例如 "vintage inspired =&gt; vintage inspired,reissue,retro" 我必须使用 synonym_graph 而不是 synonym 才能使其在“匹配”查询中工作.我想知道是否有必要,因为我在“同义词标记过滤器”elastic.co/guide/en/elasticsearch/reference/current/… 的文档中找到了一个关于 sea biscuit, sea biscit =&gt; seabiscuit 的示例
  • 是的。对于多字,你应该去synonym_graph
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-29
  • 1970-01-01
  • 2015-02-17
相关资源
最近更新 更多