一、问题背景

在日常的搜索应用中,我们经常会遇到搜索结果排序不符合业务预期的情况。比如说,我们在电商平台搜索“运动鞋”,本以为那些销量高、评价好的商品会排在前面,可实际搜索出来的结果却不尽如人意,一些不太相关或者质量一般的商品反而排在了前面。这就是搜索排序不符合业务预期的典型例子。而 Elasticsearch 作为一款强大的搜索引擎,它的相关性评分机制在搜索排序中起着关键作用。当搜索排序出现问题时,我们就需要对其相关性评分机制进行调整。

二、Elasticsearch 相关性评分机制基础

2.1 TF-IDF 原理

Elasticsearch 最基础的相关性评分算法是 TF-IDF(Term Frequency - Inverse Document Frequency)。简单来说,TF 就是词频,指的是某个词在文档中出现的次数。比如,在一篇关于篮球的文章中,“篮球”这个词出现了 10 次,那么它的词频就是 10。而 IDF 是逆文档频率,它衡量的是一个词在整个文档集合中的普遍程度。如果“篮球”这个词在所有文档中都经常出现,那么它的 IDF 值就会比较低;反之,如果某个词只在少数文档中出现,它的 IDF 值就会比较高。

示例(Elasticsearch 技术栈):

{
  "query": {
    "match": {
      "title": "篮球"
    }
  }
}
// 这个查询会根据 TF-IDF 算法来计算包含“篮球”这个词的文档的相关性评分。如果某个文档中“篮球”出现的次数多(TF 高),并且“篮球”在整个文档集合中不那么普遍(IDF 高),那么这个文档的相关性评分就会比较高。

2.2 BM25 算法

BM25 是对 TF-IDF 的改进算法,它在计算相关性评分时考虑了更多的因素,比如文档的长度。因为在实际情况中,长文档可能会包含更多的词,从而使得某些词的词频看起来比较高,但实际上这些词的相关性可能并没有那么强。BM25 算法通过对文档长度进行归一化处理,避免了长文档在评分上的优势。

示例(Elasticsearch 技术栈):

{
  "query": {
    "match": {
      "content": {
        "query": "足球",
        "analyzer": "standard",
        "boost": 2
      }
    }
  },
  "explain": true
}
// 这里使用了 BM25 算法来计算包含“足球”的文档的相关性评分。“boost”参数可以提高这个查询的权重,“explain”参数可以让 Elasticsearch 返回评分的详细解释,方便我们了解评分是如何计算的。

三、应用场景

3.1 电商搜索

在电商平台上,用户搜索商品时,我们希望搜索结果按照商品的销量、评价、价格等因素进行排序。比如,用户搜索“手机”,我们希望那些销量高、评价好的手机排在前面。这时,我们就可以通过调整 Elasticsearch 的相关性评分机制,将销量、评价等因素纳入评分计算中。

示例(Elasticsearch 技术栈):

{
  "query": {
    "function_score": {
      "query": {
        "match": {
          "product_name": "手机"
        }
      },
      "functions": [
        {
          "field_value_factor": {
            "field": "sales_volume",
            "modifier": "log1p",
            "factor": 1
          }
        },
        {
          "field_value_factor": {
            "field": "rating",
            "modifier": "sqrt",
            "factor": 2
          }
        }
      ],
      "score_mode": "multiply"
    }
  }
}
// 这里使用了 function_score 查询,将商品的销量和评价纳入评分计算。“sales_volume”字段表示销量,“rating”字段表示评价。“modifier”参数可以对字段值进行一些数学变换,“factor”参数可以调整每个因素的权重。“score_mode”设置为“multiply”表示将各个因素的得分相乘。

3.2 新闻搜索

在新闻搜索中,我们希望搜索结果按照新闻的时效性、热度等因素进行排序。比如,用户搜索“科技新闻”,我们希望那些最新发布、热度高的新闻排在前面。我们可以通过调整 Elasticsearch 的相关性评分机制,将新闻的发布时间、浏览量等因素纳入评分计算中。

示例(Elasticsearch 技术栈):

{
  "query": {
    "function_score": {
      "query": {
        "match": {
          "news_title": "科技新闻"
        }
      },
      "functions": [
        {
          "gauss": {
            "publish_date": {
              "origin": "now",
              "scale": "7d",
              "offset": "1d",
              "decay": 0.5
            }
          }
        },
        {
          "field_value_factor": {
            "field": "views",
            "modifier": "log1p",
            "factor": 1
          }
        }
      ],
      "score_mode": "sum"
    }
  }
}
// 这里使用了 function_score 查询,将新闻的发布时间和浏览量纳入评分计算。“gauss”函数用于处理发布时间,它会根据新闻的发布时间与当前时间的距离来计算得分。“views”字段表示浏览量,“modifier”和“factor”参数的作用与前面的示例类似。“score_mode”设置为“sum”表示将各个因素的得分相加。

四、技术优缺点

4.1 优点

  • 灵活性高:Elasticsearch 的相关性评分机制非常灵活,我们可以根据不同的业务需求,通过多种方式调整评分规则。比如,我们可以使用 function_score 查询,将多个因素纳入评分计算,并且可以对每个因素的权重进行调整。
  • 性能较好:Elasticsearch 经过了优化,在处理大规模数据时,能够快速计算相关性评分,保证搜索的响应速度。
  • 可扩展性强:我们可以根据业务的发展,不断扩展和优化评分机制。比如,随着业务的发展,我们可能需要引入新的因素来调整搜索排序,Elasticsearch 可以很方便地实现这一点。

4.2 缺点

  • 复杂度较高:调整 Elasticsearch 的相关性评分机制需要一定的技术知识,对于一些初学者来说,理解和使用起来可能会有一定的难度。
  • 调优成本高:要想得到理想的搜索排序结果,可能需要进行多次调优和测试,这会消耗一定的时间和精力。

五、注意事项

5.1 数据质量

在调整相关性评分机制之前,要确保数据的质量。如果数据存在错误或者不完整的情况,会影响评分的准确性。比如,在电商平台中,如果商品的销量数据不准确,那么将销量纳入评分计算时,就会导致搜索排序出现问题。

5.2 性能优化

在调整评分机制时,要注意性能优化。一些复杂的评分规则可能会增加计算的复杂度,从而影响搜索的性能。我们可以通过合理设置参数、优化查询语句等方式来提高性能。

5.3 测试验证

在调整评分机制后,要进行充分的测试验证。可以使用一些测试数据和实际用户的搜索请求来验证搜索排序是否符合业务预期。如果发现问题,要及时进行调整。

六、文章总结

Elasticsearch 的相关性评分机制在搜索排序中起着至关重要的作用。当搜索排序不符合业务预期时,我们可以通过调整评分机制来解决问题。我们可以利用 TF-IDF、BM25 等基础算法,结合 function_score 查询等方式,将业务相关的因素纳入评分计算中。同时,我们要注意数据质量、性能优化和测试验证等方面的问题。通过合理调整 Elasticsearch 的相关性评分机制,我们可以提高搜索结果的质量,满足用户的需求。