Elasticsearch-匹配更多单词时文档得分更高

时间:2018-12-18 14:02:41

标签: elasticsearch

我有一个问题,希望任何人都能帮助我。

我有一个使用匹配查询进行搜索的简单示例

"query": {
    "match": {
        "filterValues": "ordner ohne griffloch"
    }
}

我碰到了两个热门歌曲:

"hits" : [
  {
    "_index" : "filters",
    "_type" : "filter",
    "_id" : "F-114150068-1170182",
    "_score" : 5.420828,
    "_source" : {
      "filterValues" : [
        "Ja",
        "Griffloch vorhanden",
        "Griffloch",
        "mit Griffloch"
      ]
    },
    "highlight" : {
      "filterValues" : [
        "<em>Griffloch</em>"
      ]
    }
  },
  {
    "_index" : "filters",
    "_type" : "filter",
    "_id" : "F-114150069-1170182",
    "_score" : 4.452639,
    "_source" : {
      "filterValues" : [
        "ohne Griffloch",
        "kein Griffloch",
        "Nein"
      ]
    },
    "highlight" : {
      "filterValues" : [
        "<em>ohne Griffloch</em>"
      ]
    }
  }
]

我的问题是:我想找到第二个匹配的“ ohne Griffloch”作为第一匹配(更好的分数),因为它匹配更多的单词。但是我认为第一个得分更高,因为它包含的“格里弗洛奇”频率更高。

我无法使用术语查询,因为当查询包含其他单词(此处为“ ordner”)时,由于找不到与之完全匹配的内容,因此我找不到任何东西。

有什么想法吗?

谢谢!

有关信息,索引配置:

"settings": {
    "analysis": {
      "analyzer": {
        "default": {
          "type": "custom",
          "tokenizer": "keyword",
          "filter": [
            "lowercase"
          ]
        },
        "lowercase_shingle": {
          "tokenizer": "whitespace",
          "filter": [
            "lowercase",
            "my_shingle"
          ]
        }
      },
      "filter": {
        "my_shingle": {
          "type": "shingle",
          "min_shingle_size": 2,
          "max_shingle_size": 4
        }
      }
    }
  },
  "mappings": {
    "filter": {
      "properties": {
        "filterValueId": {
          "type": "long"
        },
        "filterValues": {
          "type": "text",
          "position_increment_gap": 100,
          "analyzer": "default",
          "search_analyzer": "lowercase_shingle"
        },
        "categoryId": {
          "type": "long"
        }
      }
    }
  }

2 个答案:

答案 0 :(得分:0)

您应该在查询中的短语匹配上增加一个关键词。因此,自然会提高在多个filterValues之一中找到所有查询词的文档。

但是您需要提防这个怪癖(see here, official doc

我不知道(也许力量在你身边),但是您的映射对于position_increment_gap已经正确,但是您应该删除设置

  

search_analyzer”:“小写字母”

,因为在您的上下文中似乎有点奇怪。

然后我们在匹配词组上增加

{
    "query": {
        "bool": {
            "must": [
                {
                    "match": {
                        "filterValues": "ordner ohne griffloch"
                    }
                }
            ],
            should: [
              {
                "match_phrase": {
                        "filterValues": {
                          "query": "ordner ohne griffloch",
                          "slop": 10 
                        }

                    }
                }
            ]
        }
    }
}

希望它能起作用!

评论后编辑:

如果您更改映射,以在索引时间使用shingle_analyzer添加子字段

"mappings": {
    "filter": {
      "properties": {
        "filterValueId": {
          "type": "long"
        },
        "filterValues": {
          "type": "text",
          "position_increment_gap": 100,
          "analyzer": "default",
          "search_analyzer": "lowercase_shingle",
          "fields": {
              "shingled": {
                   "type": "text",
                   "analyzer": "lowercase_shingle",
              }
          }
        },
        "categoryId": {
          "type": "long"
        }
      }
    }
  }

然后您可以通过此查询在带状线子字段上添加

{
        "query": {
            "bool": {
                "must": [
                    {
                        "match": {
                            "filterValues": "ordner ohne griffloch"
                        }
                    }
                ],
                should: [
                  {
                    "match": {
                            "filterValues.shingled": "ordner ohne griffloch" 
                        }
                    }
                ]
            }
        }
    }

它将在您的示例中提升第二个文档,而不是第一个文档

答案 1 :(得分:0)

我通过使用功能分数查询和自定义脚本来轻松解决了问题。

此脚本成为完整的搜索词,并执行以下两项操作: 根据值的长度设置分数(因此,“ ohne griffloch”大于“ griffloch”,因此更好)。

第二个(可选,但对我而言是好东西)是,它使用值在文本中的位置。

我需要做的是,删除值的数组,并将每个值作为一个文档放在索引中。

"functions": [
              {

                "script_score": {
                  "script": {
                    "source": "def v=doc['filterValue'].value; def score = 10000; score += v.length(); score -= \"ordner ohne griffloch\".indexOf(v)*50;",
                    "lang": "painless"
                  }
                }
              }
            ],
            "score_mode": "multiply",
            "boost_mode": "replace",
            "max_boost": 3.4028235e+38,
            "boost": 1
          }

  }