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

时间:2019-02-12 16:43:12

标签: 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"
        }
      }
    ]
  }
}

我希望在“ MOTORBIKE BMW R 1200 R”文档中获得更高的分数,因为我为“ r1200r”术语定义了一个同义词:( r 1200 r,r1200 r,r 1200r,r1200r)。

有任何线索吗?

1 个答案:

答案 0 :(得分:0)

我终于有时间对您的示例进行一些测试。我尝试尽可能多地解释,让我指出为使其起作用而进行了两项更改:

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

这是因为,因为您定义同义词的方式意味着,elasticsearch会扩展并会索引您定义的所有可能的组合。您还可以看到,实际搜索'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的文档在最上面。而且无论是“ motorrike r 1200r”还是任何变体,得分都应保持不变。

但是请注意,使用此解决方案时,仅搜索1200或1150不会返回任何匹配项,因为当由同义词过滤器处理时1200永远不是索引项。 (当然,如果您仅索引“ bla bla 1200”,则例外,因为同义词将与此不匹配。

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

的子章节

不过,如果您对我的回答有特定疑问,请随时发表评论。如果有时间,我将尝试更新并澄清我的答案。