Elasticsearch:多个单词的同义词不会影响查询中的分数



ES新手,寻求帮助了解问题所在。

让我们考虑一下这个索引映射,在这里我为类似摩托车的模型定义了一些同义词:

{
"settings": {
"analysis": {
"char_filter": {
"replace": {
"type": "mapping",
"mappings": [
"&=> and "
]
}
},
"filter": {
"word_delimiter": {
"type": "word_delimiter",
"split_on_numerics": "false",
"split_on_case_change": "true",
"generate_word_parts": "true",
"generate_number_parts": "true",
"catenate_all": "true",
"preserve_original": "true",
"catenate_numbers": "true"
},
"custom_synonym": {
"type": "synonym",
"lenient": "true",
"synonyms": [
"r 1200 r , r1200 r, r 1200r, r1200r",
"r 1150 r, r1150 r, r 1150r, r 1150 r, r1150r"
]
}
},
"analyzer": {
"default": {
"type": "custom",
"char_filter": [
"html_strip",
"replace"
],
"tokenizer": "whitespace",
"filter": [
"custom_synonym",
"lowercase",
"word_delimiter"
]
}
}
}
},
"mappings": {
"product": {
"properties": {
"pname": {
"type": "text",
"analyzer": "default"
}
}
}
}
}

如果我在索引中放入两个文档:

PUT test_index/product/1
{
"pname" : "MOTORBIKE BMW R 1150 R"
}

PUT test_index/product/2
{
"pname" : "MOTORBIKE BMW R 1200 R"
}

然后执行匹配查询,如:

GET test_index/_search
{
"query": {
"match" : {
"pname" : "MOTORBIKE R1200R"
}
}
}

我得到了两个相同分数的命中率:

{
"took" : 0,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 0.2876821,
"hits" : [
{
"_index" : "test_index",
"_type" : "product",
"_id" : "2",
"_score" : 0.2876821,
"_source" : {
"pname" : "MOTORBIKE BMW R 1200 R"
}
},
{
"_index" : "test_index",
"_type" : "product",
"_id" : "1",
"_score" : 0.2876821,
"_source" : {
"pname" : "MOTORBIKE BMW R 1150 R"
}
}
]
}
}

我的期望是在"摩托车宝马R 1200 R"文档上获得更大的分数,因为我已经为"r1200r"术语定义了一个同义词:(R 1200 R,r1200 R,R 1200r,r1200r)。

有线索吗?

我终于有时间对您的示例进行了一些测试。我试着尽可能多地解释,让我指出我为了让它发挥作用而改变的两件事:

1) 在您的设置中,将分析器更改为:

"analyzer": {
"default": {
"type": "custom",
"char_filter": [
"html_strip",
"replace"
],
"tokenizer": "whitespace",
"filter": [
"lowercase",
"word_delimiter",
"custom_synonym"
]
}
}

查看过滤器部分。正如我所说,秩序很重要。您希望先小写,然后标记化(在应用同义词之前)。这可能就是造成代币混乱的原因。事实上,同义词也被标记化了。如果你用这个分析器分析你的同义词(例如"r 1200 r"),那么输出的结果是压倒性的。我试着举一个例子,用它们在索引中的位置来描述代币:[token](position):

索引"r 1200 r"将索引以下"树":

  • [r](0)[1200](1)[r](2)-原始/同义词变体1
  • [r1200](0)[r](1)-同义词变体2
  • [r] (0)[1200r](1)-同义词变体3
  • [r1200r](0)-同义词变体4

这是因为你定义同义词的方式意味着,弹性搜索会扩展并索引你定义的所有可能的组合。您还可以看到,对"r"的实际搜索会产生结果,因为r只是一个标记——即使在索引r1200r时也是如此。

2) 现在,我不认为这是你想要的,所以我把同义词的定义改成了收缩风格的符号:

"custom_synonym": {
"type": "synonym",
"lenient": "true",
"synonyms": [
"r 1200 r , r1200 r, r 1200r => r1200r",
"r 1150 r, r1150 r, r 1150r, r 1150 r => r1150r"
]
} 

它基本上转换令牌[r][1200][r]等,并且只对箭头右侧的项进行索引:r1200r。请阅读以下文章了解更多信息-整个事情相当复杂,人们需要思考期望的行为是什么:https://www.elastic.co/guide/en/elasticsearch/guide/master/synonyms-expand-or-contract.html

但是,有了这个定义,单独搜索"r"将不再产生任何结果。并且,搜索"MOTORBIKE R1200R"应该总是返回顶部id为2的文档。无论是"摩托车r 1200r"还是任何变体,分数都应该保持不变。

然而,请注意,使用该解决方案,单独搜索1200或1150将不会返回任何匹配,因为1200在由同义词过滤器处理时从来都不是索引项。(当然,如果你只索引"bla bla 1200",当然是个例外,因为同义词在上面不匹配。

同义词,尤其是多术语同义词,很难处理。我知道我对链接文档有点讨厌,但值得阅读整章,包括的子章节https://www.elastic.co/guide/en/elasticsearch/guide/master/synonyms.html

尽管如此,如果您有具体问题需要我回答,请随时发表评论。如果我有时间,我会尽量更新并澄清我的答案。

最新更新