Elasticsearch 排名 shorter/less 相关标题第一

Elasticsearch ranking shorter/less relevant titles first

我正在使用 Elasticsearch 7.3 进行产品搜索。产品标题的格式不同,但我对此无能为力。

有些标题可能是这样的:

Ford Hub Bearing

还有这样的其他人:

Hub bearing for a Chevrolet Z71 - model number 5528923-01

如果有人搜索 "Chevrolet Hub Bearing","Ford Hub Bearing" 产品排名第一,雪佛兰零件排名第二。如果我从产品标题中删除所有额外的文本(型号 5528923-01),雪佛兰部件将根据需要排名第一。

不幸的是,我无法修复产品标题,因此当有人搜索时,我需要能够将雪佛兰部件排名为第一 Chevrolet Hub Bearing。我只是将 name 的类型设置为 text 并在我的索引中应用了 standard 分析器。这是我的查询代码:

{
    query:{

        bool: {
            must: [
                {
                    multi_match:{
                        fields: 
                            [
                               'name'
                             ],
                             query: "Chevrolet Hub Bearing"
                    }
                 }                  
            ]
        }

    }         
}

乍一看我只有2条建议:

1.use 该领域的英语分析器。 我认为查询中术语之间的距离会影响文档的评分,我错了(编辑:正如@Pierre Mallet 所指出的,multi_query 并非如此)标准分析器保留 "for" 和 "a" 之类的词,这可能会降低文档的分数,因为 "for a" 被分析器视为标记。

2.if 你有描述或详细文档之类的东西,你可以将该字段添加到你的 multi_match 字段列表并使用 ^2 调整字段的评分以在数学上操纵评分(相关性名称的相关性比描述的相关性更重要,但描述的内容可能是某些结果的一个很好的决胜局)参见以下示例:

"multi_match": {
  "query": "open source",
  "fields": [
    "title^2",
    "content"
  ]
}

您还可以探索 multi_match 的类型参数,它会影响结果评分的行为方式。有关更多详细信息,请参阅此 documentation

Elasticsearch 在 BM25 算法的评分公式中使用字段长度。这就是为什么较长的文档即使匹配更多术语也会排在第二位的原因。

我建议您阅读那些关于 BM25 的精彩博文: how-shards-affect-relevance-scoring-in-elasticsearchthe-bm25-algorithm-and-its-variables

但是您可以调整 bm25 算法来避免这种行为。这是 bm25 documentation for elasticsearch and here a post explaining how to do it

TF/IDF based similarity that has built-in tf normalization and is supposed to work better for short fields (like names). See Okapi_BM25 for more details. This similarity has the following options:

k1 => Controls non-linear term frequency normalization (saturation). The default value is 1.2.

b => Controls to what degree document length normalizes tf values. The default value is 0.75.

discount_overlaps => Determines whether overlap tokens (Tokens with 0 position increment) are ignored when computing norm. By default this is true, meaning overlap tokens do not count when computing norms.

所以你应该像这样在你的索引设置中配置一个新的相似性:

PUT <index>
{
  "settings": {
    "index": {
      "number_of_shards": 1
    },
    "similarity": {
      "my_bm25_without_length_normalization": {
        "type": "BM25",
        "b": 0
      }
    }
  },
  "mappings": {
    "doc": {
      "properties": {
        "name": {
          "type": "text",
          "similarity": "my_bm25_without_length_normalization"
        }
      }
    }
  }
}

然后如果将停止惩罚更长的名字的得分。长度归一化将保留用于其他字段。

我建议将 multi_matchoperator parameter 设置为 and:

{
  "query": {
    "bool": {
      "must": [
        {
          "multi_match": {
            "fields": ["name"],
            "query": "Chevrolet Hub Bearing",
            "operator": "and"
          }
        }
      ]
    }
  }
}

and 运算符可确保搜索短语中的所有单词都必须出现在生成的文档中。仅此设置就可以为您提供所需的结果。