用UBI与SRW度量改进OpenSearch搜索质量
DataHot 速览
本文介绍在Amazon OpenSearch Service上使用User Behavior Insights(UBI)开放标准捕获搜索行为,并用Search Relevance Workbench(SRW)评估搜索质量。查询日志只能记录用户输入,无法反映用户看到、选择或离开的原因;文章给出收集信号、生成相关性判断、上线前验证的闭环框架。这是系列文章的第一部分,后续将讨论端到端自动化。
为什么值得关注:搜索质量评估是数据产品中的常见难题,UBI+SRW提供了可复制的信号采集与度量框架,对做搜索、推荐或数据产品评估的从业者有直接参考价值。
本文目录 15 节
译文
AI 逐段翻译搜索是许多应用程序的门户,但大多数团队却难以回答一个看似简单的问题:“我的搜索真的返回相关结果了吗?”查询日志告诉你用户输入了什么,而不是他们看到了什么、选择了什么,或者为什么离开。当搜索感觉出问题时,罪魁祸首很少是搜索引擎。真正的问题在于缺乏刻意的信号收集、衡量和反馈循环来采取行动。
您可以使用 Amazon OpenSearch Service 上的用户行为洞察(UBI)和搜索相关性工作台(SRW)来弥补这一差距。UBI 是一个用于捕获搜索行为的开放模式标准,SRW 是用于衡量和评估搜索质量的工具包。您的应用程序生成 UBI 格式的记录。UBI 和 SRW 共同为您提供一个可重复的框架:收集信号,将其转化为相关性判断,并在每个更改发布之前验证它们。
在这篇文章中,我们向您展示如何在 Amazon OpenSearch Service 域上捕获 UBI 数据,并使用这些信号评估搜索质量。这是两部分系列文章的第一篇。我们在这里奠定基础,第 2 部分将介绍如何端到端自动化工作流。
挑战:您无法改进无法衡量的东西
考虑一位购物者在电子商务网站上搜索“手提包”。目录中有 16 种产品(手提袋、行李袋、电脑包),但每个标题都只说“包”。搜索返回零结果。大多数购物者离开。有耐心的人会改用“包”重试,并找到他们想要的东西。
您的服务器日志将第一次查询记录为一次干净的亚秒响应:没有错误,没有警报,没有信号。它完全错过了一个有购买意图的客户。该客户在搜索方式和目录编写方式之间遇到了词汇差距。放大并应用这个视角到拼写错误的查询、长尾搜索处理不当以及放弃会话。盲点比您想象的要大。
还有第二个问题:点击信号受到位置偏差的影响。用户选择第一个结果的可能性远高于第五个,无论相关性如何,因此原始点击次数反映了结果出现的位置,而不是它们是否应该出现在那里。任何从点击派生的判断都必须纠正这种偏差。我们在生成判断时会回到这一点。
使用 UBI 捕获行为数据
UBI 定义了两个索引。ubi_queries 索引为每个执行的查询保存一条记录:用户输入的文本、运行的完整查询(包括过滤器和分面)以及返回的文档 ID。ubi_events 索引保存随后的每个用户操作:展示、悬停、点击、加入购物车,每个操作都带有结果位置和产品的业务标识符(object_id)。一个共享的query_id将每个事件链接回触发它的查询。另外两个标识符完善了整体情况:client_id跟踪跨访问的浏览器,而session_id将事件限定在单次访问中。
查询记录捕获用户询问的内容以及引擎返回的文档 ID,包括像手提包搜索这样的零结果情况,它显示为带空结果列表的记录。以下是购物者对“包”的后续搜索:
{
"query_id": "1bf736d4-d673-4763-9193-4bc8a2282115",
"client_id": "9a9968ac-664b-42d7-9a9e-96f412b5ab49",
"user_query": "bag",
"query": "{"multi_match": {"query": "bag", "fields": ["title", "description", "category", "brand"]}}",
"query_response_hit_ids": [
"3760170840499",
"8400000000042"
],
"timestamp": "2026-07-23T07:53:35.264Z",
"application": "retail-shop"
}该UBI queries schema reference 文档记录了完整的查询模式,包括必填属性。
事件记录捕获用户接下来做了什么。对于每个渲染的结果,发出一个展示事件。当用户选择结果时,发出点击事件。以下是包搜索第一个结果的展示事件:
{
"action_name": "impression",
"query_id": "1bf736d4-d673-4763-9193-4bc8a2282115",
"client_id": "9a9968ac-664b-42d7-9a9e-96f412b5ab49",
"session_id": "0f2e6f2a-8f4e-4f60-9f6e-2a1b3c4d5e6f",
"user_query": "bag",
"timestamp": "2026-07-23T07:53:41.112Z",
"event_attributes": {
"position": {
"ordinal": 1
},
"object": {
"object_id": "3760170840499",
"object_id_field": "object_id"
}
}
}event_attributes 还接受您自己的自定义字段,以及标准位置和对象结构。action_name 属性至关重要:您稍后使用的判断模型仅消费展示和点击事件。将分页的结果页面视为同一逻辑查询:重用query_id 并记录绝对位置。该UBI events schema reference 文档记录了完整的事件模式。
在 Amazon OpenSearch Service 上收集 UBI 数据
行为数据(哪些结果排名、用户看到了什么、选择了什么)只存在于应用程序层。您的应用程序拥有记录,而 Amazon OpenSearch Ingestion(OSI)由 Data Prepper 驱动,是一款完全托管的无服务器数据收集器,提供托管交付路径。您的应用程序将记录作为 SigV4 签名的 HTTP POST 请求发送到 OSI 管道端点。将浏览器事件通过后端路由以进行签名。在编写任何代码之前需要了解一件事:您的应用程序生成并拥有query_id 属性。应用程序在运行搜索时创建 ID,并将其标记在用户产生的每个后续事件上,直到用户发出新搜索或会话结束。
前提条件
要跟着操作,您需要一个运行 OpenSearch 3.5 或更高版本并带有 OpenSearch UI 应用程序的Amazon OpenSearch Service 域,具有使用 AWS Identity and Access Management (IAM) 管道角色创建 OpenSearch Ingestion 管道的权限,以及一个可以检测以发出行为记录的搜索应用程序。
创建 UBI 索引
在开始收集用户指标之前,您需要将两个索引就位并具有正确的映射。这里字段类型很重要:query_id 作为关键字支持查询和事件之间的精确连接,timestamp 作为日期支持时间范围查询,而event_attributes 作为动态字段意味着您可以扩展事件的自定义字段而无需更改模式。
首先在 Dev Tools 中创建ubi_queries。它保存查询端记录。我们在这里缩写映射。请参考已发布的queries-mapping.json 文件以获取完整版本:
PUT ubi_queries
{
"mappings": {
"properties": {
"query_id": { "type": "keyword" },
"client_id": { "type": "keyword" },
"user_query": { "type": "keyword" },
"query_response_hit_ids": { "type": "keyword" },
"timestamp": {
"type": "date",
"format": "strict_date_time"
},
"application": { "type": "keyword" }
}
}
}然后创建ubi_events。它保存随后的每个用户动作(参考完整的events-mapping.json 文件):
PUT ubi_events
{
"mappings": {
"properties": {
"query_id": { "type": "keyword", "ignore_above": 100 },
"action_name": { "type": "keyword", "ignore_above": 100 },
"client_id": { "type": "keyword", "ignore_above": 100 },
"session_id": { "type": "keyword", "ignore_above": 100 },
"user_query": { "type": "keyword" },
"timestamp": {
"type": "date",
"format": "strict_date_time"
},
"event_attributes": {
"dynamic": true,
"properties": {
"position": {
"properties": {
"ordinal": { "type": "integer" }
}
},
"object": {
"properties": {
"object_id": { "type": "keyword" },
"object_id_field": { "type": "keyword" }
}
}
}
}
}
}
}创建两个索引后,下一步是将数据路由到它们中。您可以通过多种方式将 UBI 数据交付到您的域。本文使用 OSI 管道,设置后的图表中展示了端到端的流程。
设置 OSI 管道
创建两个 OSI 管道:一个用于查询,另一个用于事件。每个管道都暴露一个 HTTP 源端点,供您的应用程序写入(在每个管道的控制台页面上显示),并将数据发送到相应的索引。以下配置定义了事件管道:
version: '2'
ubi-events:
source:
http:
path: /ubi/events
max_request_length: 10mb
processor:
- date:
from_time_received: true
sink:
- opensearch:
hosts: ["https://<domain-endpoint>"]
aws:
serverless: false
region: <region>
sts_role_arn: <pipeline-role-arn>
index_type: custom
index: ubi_events
- s3:
aws:
region: <region>
sts_role_arn: <pipeline-role-arn>
object_key:
path_prefix: 'ubi_events/%{yyyy}/%{MM}/%{dd}'
bucket: <bucket-name>
threshold:
maximum_size: 50mb
event_collect_timeout: 60s
codec:
ndjson:注意: 查询管道遵循相同的模式,以 /ubi/queries 作为路径,以及 ubi_queries 作为接收索引和 S3 前缀。您可以自己创建管道角色,或让 OpenSearch Ingestion 创建它。如果您的域使用精细访问控制,还需要将管道角色映射到后端角色,以便域接受管道的写入。请参阅教程 Collecting UBI-formatted data in Amazon OpenSearch Service 以获取详细步骤。
管道运行后,您的应用程序即可开始发送数据。下图说明了端到端的流程:

图 1:Amazon OpenSearch Service 上的 UBI 收集模式
工作流程包括以下步骤:
- 用户与您的搜索应用程序交互。
- 应用程序将签名的查询记录发送到 OSI HTTP 端点。
- OSI 将查询写入
ubi_queries索引。 - 用户与结果交互,查看和选择文档。
- 应用程序将携带相同
query_id的签名事件记录发送到 OSI HTTP 端点。 - OSI 将事件写入
ubi_events索引。 - 可选地,两个管道都将记录存档到 Amazon Simple Storage Service (Amazon S3)。
- Search Relevance Workbench (OpenSearch UI) 使用
ubi_queries和ubi_events索引中收集的数据。
注意: 如果您已通过现有的第三方工具收集站点分析数据,则无需替换它。将您的搜索相关事件(查询、点击和转化)映射到 UBI 架构并存储在 OpenSearch 中。这足以解锁开箱即用的评估框架、隐式判断生成和完整的 SRW 指标管道,而无需从零开始定义单个自定义指标。
可视化收集的数据
在 UBI 行为指标开始流入后,您可以在 OpenSearch UI 仪表板的 Discover 选项卡中查看数据。筛选 ubi_queries 中的空结果列表可以识别您的词汇缺口。您还可以通过 OpenSearch 中的示例用户行为洞察(UBI)仪表板 可视化收集的数据。

图 2:Discover 中的 UBI 记录,显示零结果的手提包查询和后续的包查询及其曝光和分页事件
当数据流入您的索引时,在扩展到生产环境时请记住以下几点:
- 将遥测保持在搜索关键路径之外 – 对记录进行排队并异步转发。丢失一小部分行为数据在统计上是无害的。但阻塞用户是有害的。
- 有意识地管理数据量 – 批量处理曝光事件,如果您进行采样,请采样整个查询而不是单个事件,以保留驱动判断的点击率。
- 对于较大的部署隔离分析负载 – 将管道路由到具有与生产环境相同引擎版本、映射和分析器的独立分析域。这可以防止行为写入影响实时搜索延迟。
- 规划保留和完整性 – 将 UBI 映射注册为索引模板,并在索引增长时应用索引状态管理(ISM)保留策略。您应该验证和限制事件写入路径,并将查询文本和客户端标识符纳入数据保留策略。
使用 Search Relevance Workbench 评估搜索质量
借助 ubi_queries 和 ubi_events 收集数据,您现在拥有评估搜索质量所需的信号。Search Relevance Workbench 在 Amazon OpenSearch Service 3.5 中普遍可用,它将这些信号转化为结构化实验:比较查询配置、根据相关性判断对结果进行评分,并揭示指导迭代调优的指标。

图 3:OpenSearch UI 中的 Search Relevance Workbench
SRW 实验依赖于三个组件。您只需设置一次,然后在每次实验中重用它们:查询集(您要评估的固定查询)、搜索配置(您要比较的查询结构)和判断列表(相关性真值)。以下各节将逐一介绍。
步骤 1:创建查询集
查询集是您要评估的固定查询集合。保持固定可以使结果在实验之间具有可比性。有效的查询集反映真实流量,而不是直觉。您可以从热门查询、随机样本或包括长尾和低性能查询的手动混合中种子化一个查询集。或者,SRW 可以直接从 ubi_queries 中使用概率比例抽样(PPS)进行采样,该抽样根据用户发出查询的频率来选择查询。这种方法代表频繁查询,如“包”,因此您的指标反映用户实际体验的搜索质量。

图 4:从 ubi_queries 中的真实流量创建采样查询集
步骤 2:定义搜索配置
搜索配置定义了搜索的执行方式:索引、查询结构以及 %SearchText% 占位符,SRW 会将其替换为查询集中的每个查询。创建两个配置并针对相同的查询集和判断列表运行,是您在用户看到之前验证更改的方式。
例如,这里我们定义两个配置:一个基线 multi_match 查询(retail_query)和一个提升标题匹配的变体(retail_boosted_query),以便我们可以衡量提升是否真正有助于排名。
{
"query": {
"multi_match": {
"query": "%SearchText%",
"fields": [
"title",
"description",
"category",
"brand"
]
}
}
}{
"query": {
"multi_match": {
"query": "%SearchText%",
"fields": [
"title^2",
"description",
"category",
"brand"
]
}
}
}| retail_query | retail_boosted_query |
配置不仅限于查询变体:候选可以是完全不同的检索策略,如结合关键词和神经检索的混合搜索。您可以使用评判来独立于检索方式对查询-文档对进行评分。您可以在上线前,基于现有流量对语义或混合方法进行离线测试。
步骤3:创建评判列表
评判是查询-文档对的相关性评级:质量指标衡量的基准真相。您可以创建显式评判(来自利益相关者或作为评判者的大型语言模型)、导入评判或隐式评判(从行为中派生)。这里我们使用从UBI选择行为派生的隐式评判,使用点击超出预期点击(COEC)模型进行评分。COEC模型通过比较每个文档的实际点击率与其排名位置的预期点击率来纠正位置偏差。表现优于其位置的文档得分为相关。那些因排名第一而被用户选择的文档得分接近平均水平。

图5:使用隐式(基于点击)类型和COEC点击模型创建隐式评判列表
在运行实验之前需要正确设置三件事:
object_id在您的事件中必须与产品目录中的文档_id匹配。您定义的搜索配置返回此_id,这使SRW能够将评判与结果关联。- 隐式评判是统计性的。它们需要数量和查询覆盖。作为经验法则,每个查询的目标是数百到数千个真实会话,以区分信号和噪声。
- 最大排名控制事件计入结果列表的深度。如果用户分页,则将其设置为超过一页。这里我们使用20。
步骤4:运行实验
本文使用三个SRW功能:查询分析、查询集比较和搜索评估。查询分析是快速的目测检查:并排比较特定查询的两个配置,以准确查看变化以及指标移动的原因。其他两个用数字回答更难的问题:配置的好坏以及两个配置与真实相关性信号相比如何。
查询集比较(也称为成对比较)接受两个配置并计算排名相似性。Jaccard重叠度衡量两个结果列表共享的程度,而排名偏差重叠(RBO)更重视列表顶部的协议。得分几乎相同意味着变化对用户几乎不可察觉。低重叠意味着真正的排名变化值得在发布前仔细审查。在这次运行中,两个配置得分为0.93 Jaccard和0.92 RBO,这是一个适度但真实的转变。SRW无法对“手袋”等零结果查询进行评分:它们在比较中显示零相似性,在评估中显示失败,这表明它们需要不同的修复方法,而不是排名调整。

图6:查询集比较,显示两个配置之间的Jaccard和排名偏差重叠
搜索评估(也称为逐点评估)根据您的查询集和评判列表对单个配置进行评分,共有四个指标,每个指标在前k个结果上计算(默认k=10):
| 指标 | 衡量内容 | 告诉您的内容 |
| 覆盖率@k | 有评判的返回文档的比例 | 对其他三个指标的信任程度。低覆盖率意味着许多结果从未被评判 |
| 精确率@k | 前k个结果中相关结果的占比 | 第一页上出现的无关结果数量 |
| MAP@k(平均精确率均值) | 跨排名的平均精确率,奖励早期放置的相关文档 | 相关结果是否提前出现,即使精确率持平 |
| NDCG@k(归一化折损累计增益) | 分级评判值,按位置折损(排名1比排名9更重要) | 最佳结果是否首先出现。主要比较指标 |
每个逐点实验评估一个配置。要比较候选,请为每个配置运行一个实验并比较结果。在此运行中,基线(retail_query)的Coverage@10得分为1.0,Precision@10为1.0,MAP@10为0.95,NDCG@10为0.93,零结果的“手袋”查询在逐查询详细信息中显示为失败。

图7:一个配置的搜索评估结果:覆盖率、精确率、MAP和NDCG在10时,以及逐查询详细信息
从测量到改进
前面的实验是测试框架。以下是常用的杠杆,可以用它来测试。将每一个表达为新的搜索配置,针对相同的查询集和评判列表进行评估,仅当指标变动时采用:
- 同义词 – 解决已知词汇差距的一种选择是构建同义词。搜索时同义词标记过滤器将“手袋”和“包”视为等价,使用Amazon OpenSearch Service,您可以热部署自定义同义词包而无需重新索引。
- 字段权重 – 在multi_match查询中调整字段和提升值,例如之前测试的
title^2变体。 - 语义检索 – 混合查询结合关键词和神经得分,从整体上解决词汇不匹配,而不是逐词处理。评判在离线评估它时与词法候选完全一样。
- 重排序 – 搜索管道中的重排处理器使用交叉编码器模型对顶部结果重新排序。
清理
为避免未来费用,删除您为本演练创建的资源:
- 删除两个OpenSearch摄取管道。若要稍后重用它们,请停止它们。已停止的管道保留其配置,且不产生OpenSearch计算单元(OCU)小时费用。
- 如果您配置了可选的Amazon S3存档,请删除存档对象(或存储桶)。
- 如果您保留域,可选择删除
ubi_queries和ubi_events索引以及您创建的查询集、判断列表和实验。这些数据存在于域中,不会产生额外费用。 - 如果您专门为此文章创建了域,删除它即可移除所有内容,包括上一步中的资源。删除域是不可逆的。不要删除服务于其他工作负载的域。
结论
UBI收集证据,COEC将其转化为判断,SRW实验给出裁决:以覆盖率、精确率、MAP和NDCG取代猜测。部署获胜配置,持续收集,下一轮判断将显示改进是否与实际行为相符。过去有观点的地方,现在有了数字。
这里的一切都遵循可重复的模式,而可重复的模式有利于自动化。第2部分将介绍搜索相关性代理,可通过OpenSearch界面中的AI助手聊天(Ask AI按钮)使用。该代理分析您的UBI信号,生成调优假设,并在推荐更改之前进行离线验证。您在此文章中构建的流水线是基础。敬请期待第2部分。
要深入了解评估功能,请参阅搜索相关性工作台文档。
这篇内容对你有用吗?
反馈只用于改善内容筛选,不等同于收藏