作者:来自 Elastic Mattias Brunnert
通过使用 minimum score 阈值来提升语义精度。该文章包含了语义搜索和混合搜索的具体示例。
Elasticsearch 充满了新功能,帮助你为你的使用场景构建最佳的搜索解决方案。了解如何在我们关于构建现代 Search AI 体验的动手网络研讨会中将它们付诸实践。你也可以现在开始免费的云试用,或在你的本地机器上试用 Elastic。
语义搜索为搜索相关性打开了一个充满机会的世界。高质量的稀疏和稠密模型,例如 ELSER、E5 和 Jina Embedding v4,基于词语的含义而不是关键词匹配来返回相关结果。然而,语义搜索有时会在结果尾部,或在索引中缺乏相关结果的查询情况下,返回不相关的结果。稀疏和稠密模型的这一特性可能会让用户感到困惑,或为大型语言模型 ( LLMs ) 浪费宝贵的 token。
在本文中,你将了解如何使用 minimum score 参数来提升你的语义搜索结果的精度。如果你想测试本博客文章中提供的示例,请前往相关的 Jupyter notebook。
背景:精度和召回率
在搜索相关性中,Precision 和 Recall 是关键概念。强烈建议尚不熟悉的读者先了解它们。以下是一个总结。
- Precision:返回的搜索结果中与用户相关的结果所占的比例。
- Recall:语料库中所有相关文档中,被包含在搜索结果集里的比例。
更多阅读:Elasticsearch:理解搜索中的 precision 及 recall
换句话说,precision 是只返回相关结果;recall 是返回所有相关结果。可以想象,这两者往往是相互竞争的要求。语义搜索通常具有很高的 recall,但在 precision 方面可能会遇到困难。继续阅读,了解如何绕过这一特性。
引入 minimum score 参数
min_score 参数允许我们通过设置一个最小分数来提升 precision,它会通过移除分数低于定义阈值的匹配结果来截断结果集。下面是一个简单示例:
`
1. GET search-movies/_search
2. {
3. "retriever": {
4. "linear": {
5. "min_score": 4,
6. "retrievers": [
7. ...
8. ]
9. }
10. }
11. }
`AI写代码
分数归一化
设置 minimum score 很好;然而,并不是所有语义模型都会返回适合静态阈值的分数。例如,ELSER 返回的分数是无界的。一些稠密模型的分数高度聚集,只在特定查询的上下文中才有意义。
对于大多数语义搜索场景,我们建议在应用 min_score 之前先使用归一化方法。归一化可以确保文档分数落在一个定义好的区间内。Elasticsearch retrievers 提供了两种这样的归一化器:l2_norm 和 minmax。最常用的是 minmax,因为它容易理解,并且在许多场景下效果很好。minmax 的关键特性包括:
- 文档分数分布在 0–1 之间
- 得分最高的文档始终为 1
- 得分最低的文档始终为 0
- 这会使其不太适合关键词搜索。更多讨论请参见 “Hybrid search” 部分
下面是一个使用 min_score 的归一化语义查询示例。rank window size 被增加到 500,以便我们可以从 100 开始返回更长的搜索结果列表。
`
1. GET search-movies/_search
2. {
3. "size": 100,
4. "_source": [
5. "title", "overview"
6. ],
7. "retriever": {
8. "linear": {
9. "rank_window_size": 500,
10. "min_score": 0.25,
11. "retrievers": [
12. {
13. "normalizer": "minmax",
14. "retriever": {
15. "standard": {
16. "query": {
17. "semantic": {
18. "field": "overview_vector",
19. "query": "superhero movie"
20. }
21. }
22. }
23. }
24. }
25. ]
26. }
27. }
28. }
`AI写代码
size 被设置为比生产环境中通常看到的更高的值。这样做是为了让我们可以检查搜索结果的质量并对结果进行调优。
使用 linear retriever 的混合搜索
对于混合搜索,最简单的方法是对所有分数进行归一化、分配权重,并应用 minimum score。注意,通过选择权重之和为 1,你可以将总分保持在 0–1 的范围内。这使得最终分数更容易理解,也更容易调优 min_score。下面是一个示例:
`
1. GET search-movies/_search
2. {
3. "size": 100,
4. "_source": ["title", "overview","keywords"],
5. "retriever": {
6. "linear": {
7. "rank_window_size": 500,
8. "min_score": 0.25,
9. "retrievers": [
10. {
11. "weight": 0.6,
12. "normalizer": "minmax",
13. "retriever": {
14. "standard": {
15. "query": {
16. "semantic": {
17. "field": "overview_vector",
18. "query": "superhero movie"
19. }
20. }
21. }
22. }
23. },
24. {
25. "weight": 0.4,
26. "normalizer": "minmax",
27. "retriever": {
28. "standard": {
29. "query": {
30. "multi_match": {
31. "query": "superhero movie",
32. "fields": ["overview","keywords", "title"],
33. "type": "cross_fields",
34. "minimum_should_match": "2"
35. }
36. }
37. }
38. }
39. }
40. ]
41. }
42. }
43. }
`AI写代码
使用 RRF 的混合搜索
对于 BM25,我们通常通过其他方式来控制 precision,例如使用 AND 操作符或 minimum_should_match。此外,由单个、精确且罕见词项组成的查询,天然会产生结果数量较少的搜索结果,而且往往都高度相关。这可能会导致:
- 即使绝对的 BM25 分数接近最高分命中,结果列表中靠后的结果在 BM25 retriever 中也会被分配较低的归一化分数
- 当一个非常低的 BM25 分数与语义分数相加时,总分可以近似为语义分数
- 缺乏 BM25 分数贡献可能会导致文档被 min_score 阈值丢弃
作为解决方案,我们可以改用倒数排序融合 (reciprocal rank fusion - RRF ) 来组合 BM25 和语义结果。RRF 通过关注每个结果集中的位置,而不是直接比较不同搜索算法的分数,从而绕过了分数可比性的挑战。在这种场景下,min_score 只应用于语义 retriever。
`
1. GET search-movies/_search
2. {
3. "_source": ["title", "overview","keywords"],
4. "retriever": {
5. "rrf": {
6. "rank_window_size": 500,
7. "retrievers": [
8. {
9. "linear": {
10. "rank_window_size": 500,
11. "min_score": 0.25,
12. "retrievers": [
13. {
14. "normalizer": "minmax",
15. "retriever": {
16. "standard": {
17. "query": {
18. "semantic": {
19. "field": "overview_vector",
20. "query": "superhero movie"
21. }
22. }
23. }
24. }
25. }
26. ]
27. }
28. },
29. {
30. "standard": {
31. "query": {
32. "multi_match": {
33. "query": "superhero movie",
34. "fields": ["overview", "keywords","title"],
35. "type": "cross_fields",
36. "minimum_should_match": "2"
37. }
38. }
39. }
40. }
41. ]
42. }
43. }
44. }
`AI写代码
结论
通过使用 min_score,我们展示了如何减少由于语义搜索算法高 recall 而在结果集中产生的假阳性数量。要了解更多关于 retrievers 的内容,请参阅这篇博客文章以及 Elasticsearch 文档。