作者:来自 Elastic Matthew Adams

学习如何将 OpenTelemetry 搜索分析中的点击流和行为信号转化为判断列表、排序特征和 Learn To Rank 模型,从而让搜索相关性随着时间不断提升。
每一次对搜索结果的点击都是一种隐式的相关性判断,而转化是更强的信号。你通过 OpenTelemetry 捕获的搜索分析数据包含了用于提升搜索相关性的行为数据。这些技术可以从简单的方法开始,先解决本周就能上线的问题,然后逐步发展到使用真实点击数据训练的 Learn To Rank(LTR)模型。用于发现问题的检测机制,同时也会生成用于解决这些问题的训练数据。
你将了解到什么
在本文中,你将学习如何:
-
根据点击数据构建判断列表,用于评估和提升相关性。
-
根据分析数据应用基础的搜索调优(字段权重、boost、查询规则)。
-
根据行为信号创建排序特征,例如热度和转化率。
-
了解 LTR,以及点击数据如何转化为训练数据。
-
建立分析数据与相关性提升之间的反馈闭环。
你需要什么
-
来自本系列前几篇博客的搜索分析数据(Elastic 中的 search、click 和 conversion spans)。
-
一个包含产品数据的 Elasticsearch 索引(参考项目包含带有排序特征的示例数据)。
-
熟悉 Elasticsearch 查询(BM25 Elasticsearch 默认的文本评分算法、
rank_feature、function scores)。
搜索相关性技术概览
| 技术 | 工作量 | 改进内容 | 使用时机 |
|---|---|---|---|
| 字段权重调优 | 低 | 改善属性丰富型查询的相关性 | 第一步;快速获得收益 |
| 查询规则 | 低--中 | 特定高价值查询 | 已知某些词会产生错误结果时 |
| 排序特征 | 中 | 将行为信号与文本评分结合 | 热度、转化率、新鲜度提升 |
| LTR | 高 | 根据点击数据进行系统化排序 | 当你拥有 ≥5k 个带标签的查询-文档对时 |
从搜索分析到搜索相关性改进
在前面的三篇文章中,你已经构建了一套完整的检测机制,包括带有 search.* 属性的搜索 spans,以及带有位置数据和点击率(click-through rate - CTR)/平均倒数排名(MRR)指标的点击跟踪。这套检测机制还包括将搜索与收入关联起来的转化 spans。所有这些数据都位于 traces-generic.otel-default 中,可以使用 Elasticsearch Query Language(ES|QL)进行查询。
现在你已经有了仪表板,并且知道你的 CTR 是 28%。你还知道哪些查询能够产生收入,以及哪些查询会被用户放弃。此外,你还可以准确告诉产品经理转化漏斗中的具体流失位置。
现在呢?
搜索分析的真正价值在于利用行为数据改进相关性,并建立反馈闭环。同样重要的是,让搜索能够从用户行为中学习。你的经验告诉你,衡量是必要的,但仅仅衡量还不够,而一个显示排名较差的仪表板并不能改善排名。
**关于示例的说明:**本系列文章始终使用电子商务搜索(产品、购物车、购买)作为示例,因为这样可以让分析变得具体且可衡量,但这些模式可以广泛应用。内容平台衡量的是互动,而不是购买;招聘网站跟踪的是申请,而不是加入购物车。
search.*属性以及下面介绍的技术都可以适用于任何用户会进行搜索并与搜索结果互动的领域。
想跟着代码一起实践? 参考项目包含带有排序特征(热度、利润率评分、转化率)的产品,以及 BM25 +rank_feature查询。
本文涵盖四个实践领域:
-
**判断列表:**评估和改进相关性的基础。
-
**基础搜索调优:**根据分析数据调整字段权重、boost 和查询规则。
-
**用于个性化的排序特征:**将行为信号反馈到排序过程中。
-
**LTR:**使用点击数据训练机器学习(ML)模型,自动优化排序。
每一种方法都直接使用你已经在收集的 search.* 属性,而且不需要任何新的检测机制。
什么是判断列表?
在深入了解具体技术之前,值得先理解一个将这些技术串联起来的概念:判断列表。
判断列表是一组带有相关性等级的查询-文档对:对于给定的查询,每个文档的相关性有多高?它们看起来是这样的:
| 查询 | 文档 | 等级 | 标签 |
|---|---|---|---|
| "无线耳机" | SKU-001(Sony WH-1000XM5) | 3 | 高度相关 |
| "无线耳机" | SKU-042(AirPods Max) | 2 | 相关 |
| "无线耳机" | SKU-099(有线耳塞) | 0 | 不相关 |
判断列表有三个用途:
-
评估当前的相关性 。给定一组查询和已知的优质结果,你的搜索对这些结果的排序效果如何?归一化折损累计增益(NDCG)等指标以及 Rank Eval API 都会使用判断列表来评估你的排序质量。这可以在进行更改之前为你提供一个基准。
-
衡量更改带来的影响。当你调整字段权重或添加同义词时,判断列表可以告诉你这项更改是带来了帮助还是造成了损害。修改 boost 规则时也是如此。在更改前后运行相同的评估:如果 NDCG 提高了,就说明这项更改改善了这些查询的相关性。
-
训练 LTR 模型 。LTR 算法需要带标签的训练数据,例如,对于这个查询,这些文档是相关的,而那些文档是不相关的。判断列表就是这种训练数据。
手动与自动生成判断列表
传统上,判断列表由人工评估人员创建,他们会针对一组测试查询手动评估文档。这对于少量高价值查询(例如排名前 50 的搜索)效果很好,但无法扩展。当目录中有数千个不同的查询,并且库存频繁发生变化时,手动评估就变得不切实际。
这正是点击数据发挥价值的地方。每一次点击都是一种隐式的相关性判断;也就是说,它表明对于某个查询,某个文档具有足够的相关性,值得用户进行互动。转化则是更强的信号。通过汇总这些数据,你可以根据真实的用户行为自动构建判断列表,其规模是手动评估无法匹敌的。
这种方法需要在噪声方面做出权衡。点击会受到位置偏差的影响(无论相关性如何,用户点击排名靠前的结果的概率都更高),也会受到展示效果的影响。此外,还会受到误点击的影响。我们将在本文后面介绍处理这些噪声的技术。但关键在于,个性化和 LTR 等方法更倾向于使用自动生成的判断列表,因为无论是为每个查询或用户群组手动创建列表,还是在每次库存发生变化时重新创建列表,都无法进行规模化。
Search Labs 上的判断列表指南深入介绍了这一概念,包括如何构建列表以便使用 Rank Eval API 进行评估。
搜索分析如何识别搜索相关性问题
搜索分析数据最直接的用途是识别并修复具体的相关性问题。这只需要利用数据指导人工改进,无需个性化或 ML。
使用搜索分析查找问题查询
应用程序中用于点击跟踪的 ES|QL 查询可以为你提供每个查询的 CTR 和 MRR。按照搜索量降序、CTR 升序进行排序,就可以找到影响最大的相关性问题:
sql
`
1. FROM traces-generic.otel-default
2. | WHERE ((name == "search" AND attributes.search.query IS NOT NULL)
3. OR attributes.search.first_click == true)
4. AND attributes.search.query IS NOT NULL
5. | STATS
6. searches = COUNT(CASE(name == "search" AND attributes.search.query IS NOT NULL, 1)),
7. clicked = COUNT(CASE(attributes.search.first_click == true, 1))
8. BY attributes.search.query
9. | EVAL ctr_pct = ROUND(100.0 * clicked / searches, 1)
10. | WHERE searches > 5
11. | SORT ctr_pct ASC, searches DESC
12. | LIMIT 20
`AI写代码
这是重新排序后的按查询统计 CTR 的查询,用于优先发现问题。WHERE searches > 5 过滤条件会排除只出现一次的查询,因为这些查询的样本量太小,噪声会导致它们占据低 CTR 列表的前列。
-
有结果但 CTR 为零的查询。你的排序能够返回内容,但没有任何结果足够吸引用户。这类查询通常可以通过扩展同义词来改善。你也可以通过 boost 规则或固定结果来改善它们。
-
低 CTR、高搜索量的查询。这些是最值得投入相关性优化资源的机会,而且会影响最多的用户。
-
低 MRR、高 CTR 的查询。用户能够找到他们需要的内容,但需要向下滚动才能找到。在这种情况下,相关文档确实存在,但排序位置不正确。
试试看:在参考项目中闭合反馈环
如果你在参考项目中已经有点击数据(python generate_traffic.py --blog 3 --sessions 100),可以针对 traces-generic.otel-default 运行上面的查询问题查询,并观察 CTR 最低的查询。
参考项目的 app.py 已经使用 rank_feature 进行 boost:rank_features.popularity、rank_features.conversion_rate、rank_features.margin_score 和 rank_features.freshness 都会被索引到每个产品中,并在查询时与 BM25 分数进行融合。要查看调整 boost 后的效果:
-
打开
reference/app.py,找到_build_search_query()中的"should"子句。 -
将
rank_features.popularity上的"boost"值从2改为5。 -
重启服务器(
python app.py),然后重新运行generate_traffic.py --blog 3 --sessions 50。 -
在 ES|QL 中比较调整前后的热门查询和点击位置分布。
这是利用你收集的行为数据进行有依据的手动调优,而不是 ML。这也是本文其余部分采用的模式:首先,ES|QL 告诉你哪里出了问题。然后,通过配置更改以及最终的 LTR 模型来修复这些问题。
字段权重、boost 和评分对搜索相关性的影响
Elasticsearch 中最简单的调优手段,就是调整不同字段对相关性分数的贡献方式。对 title、description 和 brand 字段执行 multi_match 查询时,可以提高 title 的权重,因为通常匹配标题的结果具有更高的相关性。你的分析数据可以告诉你这些权重在哪里设置得不合理:如果用户持续点击标题与查询不匹配、但描述与查询匹配的产品,那么你的标题 boost 可能设置得过高。
除了字段权重之外,你还可以将业务指标直接纳入评分。一个常见的例子是_根据利润率进行 boost_;也就是说,当相关性分数相近时,让利润率更高的产品排名稍微靠前。rank_feature 字段类型就是专门为此设计的:在每个文档中同时索引一个数值信号(利润率、热度、新近程度),然后在查询时通过rank_feature 查询将其与文本相关性结合起来。对于更复杂的评分组合,例如衰减函数、加权字段值和脚本,function_score 查询可以让你完全控制评分。Search Labs 上的利润率和热度 boost 指南对此进行了详细介绍,包括加法 boost 和乘法 boost方法之间的权衡。
使用查询规则针对性修复搜索相关性
对于针对性的干预,查询规则可以针对特定查询固定、提升或排除特定结果,并且不需要训练模型。它们相当于搜索领域中的手动覆盖机制。
你的分析数据可以准确告诉你应该在哪里应用这些规则。当你发现一个 CTR 为零的查询,例如"退货政策",而它持续返回产品结果而不是退货页面时,可以针对该查询将退货页面固定在第 1 位。如果你发现某个高收入查询中最畅销的产品排在第 4 位,也可以提升它的排名。
查询规则的价值恰恰在于它们简单。它们可以立即解决已知问题,同时让你逐步构建更复杂的方法。Search Labs 上的查询规则教程介绍了具体的设置过程。
根据点击数据构建判断列表
上面的基础调优可以解决单个问题。要系统地提升相关性,你需要判断列表,而你的点击数据可以自动构建这些判断列表。
将点击数据转换为相关性等级
最简单的方法是统计每个查询-文档对的点击次数,并为其分配分级相关性:
sql
`
1. FROM traces-generic.otel-default
2. | WHERE attributes.search.action == "click"
3. AND attributes.search.query IS NOT NULL
4. | STATS
5. click_count = COUNT(*),
6. avg_position = AVG(attributes.search.result_click_position)
7. BY attributes.search.query, attributes.search.result_click_id
8. | SORT attributes.search.query, click_count DESC
`AI写代码
这样你就可以得到一个由(query、document、click_count、avg_position)元组组成的表格。分级步骤会将点击次数映射为相关性等级:
| 点击次数 | 建议等级 | 标签 |
|---|---|---|
| 0 | 0 | 不相关(针对该查询从未被点击) |
| 1 | 1 | 略微相关 |
| 2--3 | 2 | 相关 |
| 4+ | 3 | 高度相关 |
**关于等级为 0 的文档的说明:**下面的 ES|QL 查询只会返回被点击过的文档;它无法告诉你哪些文档已经展示给用户但被忽略了。要生成等级为 0 的示例,你需要_展示数据_;也就是说,需要获取每次搜索返回的完整文档列表。如果你在搜索 spans 上设置
search.query_response_hit_ids,就可以在 ES|QL 中将展示数据与点击数据关联起来,并识别出哪些文档出现在结果中但从未被点击。没有这些数据时,可以使用本节后面的skip-above查询作为替代方案。用户跳过的结果位置上的文档属于较弱的负面信号。
这些阈值取决于你的流量规模。对于高流量网站,你可能需要 10 次以上的点击,才能将某个文档判定为"高度相关"。对于较低流量的网站,即使两三次点击也是有意义的信号。关键在于,来自多个用户的点击频率比任何一次单独的点击都是更强的信号。
你还可以通过加入转化数据来进一步增强判断:一个被点击_并且_加入购物车的文档,比一个被点击后就被放弃的文档能够提供更强的相关性信号:
sql
`
1. FROM traces-generic.otel-default
2. | WHERE attributes.search.action IN ("click", "add_to_cart")
3. AND attributes.search.query IS NOT NULL
4. | STATS
5. clicks = COUNT(CASE(attributes.search.action == "click", 1)),
6. carts = COUNT(CASE(attributes.search.action == "add_to_cart", 1))
7. BY attributes.search.query, attributes.search.result_click_id
8. | SORT attributes.search.query, clicks DESC
`AI写代码
一个拥有 5 次点击和 3 次加入购物车的文档,比一个拥有 5 次点击但 0 次加入购物车的文档,更适合作为等级 3 的候选文档。
处理点击数据中的位置偏差
原始点击次数存在一个问题:位置偏差 。用户更经常点击第 1 位,是因为他们_首先看到_它,而不一定是因为它是最相关的结果。博客 3 在讨论点击位置分布时介绍了这一概念,并引用了 Joachims 等人(2005) 的奠基性研究。
位置偏差对判断列表很重要,因为这意味着原始点击数据会过度强调当前排名最先展示的内容。如果你使用存在偏差的判断结果训练 LTR 模型,它会学会复现现有的排序,从而违背了改进排序的初衷。
有两种实用的方法可以处理这个问题:
-
**按位置归一化的点击率。**不要使用原始点击次数,而是计算_每个位置_的点击率。一个在第 5 位展示时 10 次中被点击 3 次的文档,可以说比一个在第 1 位展示时 10 次中被点击 5 次的文档更相关。第 5 位的曝光度更低,因此在那里获得更高的点击率是更强的相关性信号。
-
**跳过上方结果的启发式方法。**当用户点击第 3 位,同时跳过第 1 位和第 2 位时,这些被跳过的文档可以被隐式判断为对于该查询 "相关性较低"。这是 Joachims 等人的核心观点:被跳过的上方结果可以提供负向训练信号。你可以从点击数据中提取这些查询-文档对:
sql
`
1. FROM traces-generic.otel-default
2. | WHERE attributes.search.action == "click"
3. AND attributes.search.query IS NOT NULL
4. | STATS
5. min_click_position = MIN(attributes.search.result_click_position),
6. max_click_position = MAX(attributes.search.result_click_position),
7. click_count = COUNT(*)
8. BY attributes.search.query_id, attributes.search.query
9. | WHERE min_click_position > 1
10. | SORT click_count DESC
`AI写代码
最小点击位置大于 1 的查询,表示用户跳过了顶部的结果。这些查询中被跳过位置上的文档,可以作为判断列表中等级为 0 的候选文档,因为用户看到了这些文档,却选择了排名更靠后的其他结果。
对于生产环境中的判断列表生成,Search Labs 上的 LTR 教程介绍了完整的流程。使用用户行为数据训练 LTR 模型指南介绍了如何根据点击行为推导训练数据的具体工作流程,包括用于消除偏差的 Clicks Over Expected Clicks(COEC)算法。而 LTR Jupyter notebooks 提供了用于特征提取和模型训练的可运行 Python 代码。
用于搜索相关性个性化的排序特征
基础调优会对每个用户应用相同的排序。个性化意味着根据搜索者的身份(他们的历史记录、偏好或用户群组)调整结果。排序特征是在 Elasticsearch 中实现这一目标最简单的方式。
从点击流中构建行为信号
你可以在文档级别聚合点击和转化数据,生成能够反映整体热度或特定用户群组热度的信号:
sql
`
1. FROM traces-generic.otel-default
2. | WHERE attributes.search.action IN ("click", "add_to_cart")
3. | STATS
4. clicks = COUNT(CASE(attributes.search.action == "click", 1)),
5. carts = COUNT(CASE(attributes.search.action == "add_to_cart", 1))
6. BY attributes.search.result_click_id
7. | EVAL cart_rate_pct = ROUND(100.0 * carts / clicks, 1)
8. | SORT clicks DESC
9. | LIMIT 20
`AI写代码
这些文档级信号(点击热度、加购率和转化率)会作为 rank_feature 字段索引到每个产品文档中。工作流程如下:
-
定期运行上面的 ES|QL 查询(每天或每周)。
-
将结果写回每个产品文档中的
click_popularity或conversion_raterank_feature字段。 -
使用
rank_feature查询,将文本相关性与行为信号结合起来。
rank_feature 查询默认会应用饱和函数:初始的热度提升最重要,随着数值变大,其影响会逐渐减弱。这样可以防止某个突然走红的产品主导所有查询。你可以调整该函数的 pivot point,以控制该特征相对于文本相关性的影响程度。
根据用户群组个性化排序特征
上面的查询生成的是_全局_热度;也就是说,对于每个用户都是相同的。个性化来自对这些信号进行分组。如果你正在跟踪 enduser.pseudo.id 或 user.id,就可以针对每个用户群组计算特征:
-
**品类偏好:**这个用户点击"电子产品"类商品的频率与点击"服装"类商品的频率相比如何?
-
**价格敏感度:**这个用户是否倾向于点击和购买价格较高或较低的商品?
-
**品牌偏好:**这个用户与哪些品牌互动最多?
这些都会成为额外的排序特征,并根据搜索者的身份在查询时应用。Search Labs 上的使用 LTR 实现个性化搜索指南介绍了如何训练针对每个用户的排序模型。对于更轻量的方法,考虑用户群组的排序指南介绍了如何在不使用 ML 的情况下,通过乘法 boost 在用户群组级别实现个性化,只需在查询时将从分析数据中得到的权重应用到排序特征即可。
使用 linear retriever 组合多个信号
当你将文本相关性与语义搜索和行为排序特征结合起来时,需要一种方法将它们组合起来。Elasticsearch 的 linear retriever 可以精确控制不同查询类型对最终排序的贡献。它会计算归一化分数的加权和,因此你可以设置_文本相关性占 60%、语义相似度占 30%、热度占 10%_,并根据你的分析数据调整这些权重。这与 Reciprocal Rank Fusion(RRF)不同,后者只考虑相对排名位置。
这对于个性化尤其有用,因为你可以针对不同用户群组调整权重。回访客户可以在购买历史上获得更高的权重,而首次访问的用户则可以在全局热度上获得更高的权重。
如果你同时使用基于 embedding 模型的语义搜索,Elastic Inference Service(EIS)现在提供 GPU 加速的 embedding 生成,包括多语言模型,并且可以直接在 Elastic Cloud 中使用,因此可以轻松地在文本和行为信号之外添加语义 retriever。
Learn To Rank 如何利用点击流优化排序
排序特征可以处理单个信号,而 LTR 可以一次处理所有信号。它会训练一个 ML 模型,将多个特征(例如文本相关性、热度、CTR、新近程度、利润率或用户偏好)组合成一个针对你的用户进行优化的统一排序函数。
在 Elasticsearch 中使用 Learn To Rank 需要什么
Elasticsearch 从 8.12 版本开始支持原生 Learning to Rank,这是 Enterprise 订阅功能。流程如下:
-
**判断列表。**包含相关性等级的查询-文档对(如上文所述,根据点击数据构建)。
-
**特征提取。**为每个查询-文档对提取数值信号(BM25 分数、热度、CTR、新近程度、价格、利润率、用户群组特征)。
-
**模型训练。**通常使用 XGBoost 或 LambdaMART,根据包含这些特征的判断列表进行训练。
-
**部署。**通过 Eland 将训练好的模型上传到 Elasticsearch,并将其作为 rescorer 使用。
本系列中的点击和转化数据会为第 1 步和第 2 步提供数据,而判断列表则是你的训练标签。上面的排序特征部分介绍的文档级特征(点击热度、转化率、利润率)可以与文本相关性分数一起作为额外特征。
为什么根据点击数据自动生成判断列表更具可扩展性
这正是自动生成判断列表的可扩展性优势变得具体的地方。手动整理的判断列表可能能够很好地覆盖排名前 100 的查询,但个性化排序需要覆盖数千个查询以及多个用户群组的判断数据。你不可能雇佣评估人员,分别为电子产品爱好者、预算型购物者和专业音频工程师评估"无线耳机"的搜索结果。
根据点击数据自动生成的判断列表可以覆盖用户实际执行的每一个查询,并随着库存和用户行为的变化进行更新。它们还可以按照用户群组进行细分。使用用户行为数据训练 LTR 模型指南展示了这一端到端工作流程,说明如何从原始点击事件一直到训练好的排序模型。
对于希望进一步闭合这一反馈环的团队,agentic 自动调优方法展示了如何使用 AI agent 持续监控搜索质量,并根据用户互动生成判断列表。它会自动重新训练 LTR 模型,将反馈环转变为一个自主运行的系统。
Learn To Rank 的要求:流量、流程和评估
LTR 需要足够的流量来生成有意义的判断列表,同时也需要工程投入来构建和维护整个流程。它还需要持续进行评估,以确保模型能够随着时间推移不断改善。但对于具有足够数据量的搜索应用来说,这是让排序从用户行为中学习的最有效方式。Search Labs 上的 LTR 介绍涵盖了完整的实施范围。
Elasticsearch Relevance Studio:可视化搜索相关性调优
在查询规则(手动、针对性)和 LTR(ML、系统化)之间,还有一种折中的方法:可视化相关性调优。Elasticsearch Relevance Studio 是一个用于并排比较和调优搜索配置的工具。它可以让你调整 boost 值、字段权重和查询结构,同时实时查看结果更新。
分析数据,尤其是 CTR 和 MRR,可以告诉你应该重点关注哪些查询。从问题查询的排序列表开始(即上面的 ES|QL 分析中那些低 CTR、高搜索量的查询),然后在 Relevance Studio 中系统地逐个处理,而不是猜测哪些搜索需要调优。
工作流程:
-
**识别问题查询。**运行按查询统计 CTR 和按查询统计 MRR 的分析。
-
**在 Relevance Studio 中打开这些查询。**同时查看当前结果和调优后的结果。
-
**调整字段权重和 boost。**尝试不同的配置更改。
-
**使用判断列表进行评估。**使用 Rank Eval API 确认更改是否提升了测试查询的 NDCG。
-
**衡量生产环境中的影响。**部署更改后重新运行分析,并比较 CTR / MRR。
这个前后对比的闭环正是分析与调优连接起来的地方。有了分析数据,你可以优先处理影响最多用户的查询,并验证更改是否确实带来了改善。没有这些数据,调优就只能靠猜测,你会不断调整权重,却不知道哪些查询最重要,也不知道如何衡量改进效果。
如果你正在进行相关性调优和评估,也应该了解一下 Elasticsearch Relevance Studio 项目,它可以让你直接比较不同的搜索策略。
闭合搜索分析与搜索相关性之间的反馈环
搜索相关性的改进遵循一个一致的闭环:使用 ES|QL 分析来衡量质量,应用更改(查询规则、字段权重、排序特征或 LTR 模型),然后再次进行衡量。

关键在于,用于衡量搜索质量的同一套检测机制,也会生成用于改进搜索质量的数据。你的搜索 spans 会产生需要分析的查询,而点击 spans 会产生用于评估和 LTR 训练的判断数据。此外,你的转化 spans 还能告诉你哪些改进对业务最重要。
更改后衡量搜索相关性的改进效果
部署更改后,例如新增查询规则、更新字段权重或部署 LTR 模型,你需要知道它是否带来了改善:
| 指标 | 衡量内容 | 比较方式 |
|---|---|---|
| CTR 趋势 | 更改后是否有更多用户点击搜索结果 | 分别运行更改前后两周的按查询统计 CTR 的 ES |
| MRR 趋势 | 点击是否向排名更靠前的位置转移 | 使用按查询统计 MRR 的分析,比较更改前后的每个查询的平均倒数排名 |
| 转化率趋势 | 是否有更多点击转化为购买或加入购物车 | 分别针对两个时间段运行点击到转化的 ES |
| 每个查询的收入 | 更改是否带来了积极的业务影响 | 通过转化 spans 比较部署前后受影响查询所产生的收入 |
在更改前后运行相同的 ES|QL 查询。如果你的更改是针对"laptop bag"的查询规则,就比较该查询在更改前一周和更改后一周的 CTR 和 MRR。
使用实验属性进行 A/B 测试
feature_flag.key 属性正是为此设计的。将一定比例的流量分配给新的排序配置,并将 feature_flag.key 设置为实验名称,还可以选择将 feature_flag.result.variant 设置为具体变体(例如 "control" 或 "variant-boost-v2")。然后,以传播 query_id 的相同方式将这些属性传播到点击 spans,并比较不同组之间的指标:
vbnet
`
1. FROM traces-generic.otel-default
2. | WHERE ((name == "search" AND attributes.search.query IS NOT NULL)
3. OR attributes.search.first_click == true)
4. AND attributes.feature_flag.key IS NOT NULL
5. | STATS
6. searches = COUNT(CASE(name == "search" AND attributes.search.query IS NOT NULL, 1)),
7. clicked = COUNT(CASE(attributes.search.first_click == true, 1))
8. BY attributes.feature_flag.key, attributes.feature_flag.result.variant
9. | EVAL ctr_pct = ROUND(100.0 * clicked / searches, 1)
`AI写代码
这样你就可以按实验变体对 CTR 进行 A/B 对比。对于基础比较,你不需要单独的实验平台,不过如果要确保样本量和统计显著性方面的严谨性,还是需要一个完善的实验框架。
监控搜索相关性回归
一旦你确定了高价值查询,也就是那些能够带来收入并且已经调优到具有良好用户互动效果的查询,就需要保护它们。排名前 20 的创收查询出现相关性回归,是业务关键事件。
这就是监控发挥作用的地方。在本系列的下一篇博客中,我们将介绍如何针对这些指标设置告警:高收入查询的 CTR 下降,以及部署后的 MRR 回归。我们还会介绍转化率异常。同样的 ES|QL 查询既可以驱动你的分析仪表板,也可以驱动告警规则;这个反馈环涵盖了衡量和改进,同时也提供了运行保护。
搜索相关性改进路线图:从第 1 周到第 1 季度
这里有一个实用的起点。你不需要在第一天就实施 LTR。这些方法是逐步构建起来的:
-
**第 1 周:评估并修复已知问题。**运行按查询统计 CTR 的分析。找出搜索量高但 CTR 为零的查询,并通过同义词或查询规则中的固定结果来修复最严重的问题。你也可以调整字段权重。使用判断列表(即使只是针对热门查询创建一个小型手动列表)确认这些更改能够提升 NDCG,然后再部署。你应该能够立即获得有针对性的效果。
-
**第 1 个月:添加行为排序特征。**从你的分析数据中提取文档级的点击热度和转化率。将它们作为
rank_feature字段进行索引,并使用 linear retriever 或rank_feature查询,将行为信号与文本相关性结合起来。然后可以考虑加入利润率等简单的业务 boost。这样无需针对每个查询进行手动干预,就能提升所有查询的基础质量。 -
**第 1 季度:使用 LTR 实现自动化。**当你积累了足够的点击数据后(通常需要数周的生产环境流量),根据点击和转化数据自动构建判断列表。训练一个结合文本特征、行为特征和业务特征的 LTR 模型,然后将其部署为 rescorer。这样,排序就可以从用户行为中学习,并随着收集到更多数据而不断改进。
在每个阶段,都使用相同的指标来衡量影响。CTR 和 MRR 是你的评分标准,转化率也是如此。如果一项更改没有带来这些指标的变化,那么它就没有带来帮助,无论采用的方法多么复杂。
下一步:搜索可靠性工程和 SLO
我们已经介绍了完整的流程:检测搜索、衡量质量、跟踪转化,并改进相关性。缺少的部分是确保这一切能够持续正常运行。
接下来,我们将通过搜索可靠性工程结束本系列,包括针对搜索质量的服务等级目标(SLO)和针对指标回归的告警,以及能够在用户发现问题之前及时发现问题的运行监控仪表板。你一直在构建的这些相同指标将成为搜索健康状况监控的基础,让你的分析流程转变为一个可靠性系统。
开始使用
可运行的代码
- 参考项目: 整个博客系列的可运行代码;克隆、配置并运行。
原文:How click streams improve search relevance with LTR | Elasticsearch Labs