如何使用 OpenTelemetry 对你的搜索 API 进行埋点,并使用 ES|QL 对其进行查询

发布时间:2026/7/23 7:56:57
如何使用 OpenTelemetry 对你的搜索 API 进行埋点,并使用 ES|QL 对其进行查询 作者来自 Elastic Matthew Adams向你的 OpenTelemetry span 添加自定义属性并运行六个 ES|QL 查询以揭示最热门的搜索、零结果率以及最慢的查询。Elasticsearch 提供了大量新功能帮助你针对自己的使用场景构建最佳搜索解决方案。在我们的实践网络研讨会《构建现代 Search AI 体验》中了解如何将这些功能付诸实践。你还可以立即开始 免费 Cloud 试用或在你的 本地机器 上试用 Elastic。使用大约 20 行的 OpenTelemetry ( OTel ) 代码为你的搜索 API 添加埋点然后通过 Elasticsearch查询语言ES|QL即可了解用户在搜索什么、他们有多少次没有获得任何结果以及搜索实际运行得有多快。这直接延续了本系列的第一篇文章在那篇文章中我们阐述了为什么应当使用 OpenTelemetry 而不是定制的分析管道。在本文中我们将为一个 FastAPI 搜索endpoint添加带有自定义search.*属性的埋点并针对生成的追踪数据运行六个 ES|QL 查询。在我们的演示集群中17.7% 的搜索返回了空结果而我们仅在开启埋点后的几分钟内就发现了这一问题。无需单独的日志管道。你使用的仍然是相同的 span、属性以及查询语言而这些很可能已经在 Elastic 的其他地方运行着。你将了解什么在本文中你将学习如何在一个示例 Python FastAPI 后端中设置 OpenTelemetry。使用约 20 行代码向你的搜索 span 添加自定义search.*属性。理解 OTel 原生摄取如何将属性映射为可查询的数据。针对真实追踪数据编写六个 ES|QL 查询热门查询、零结果率、哪些查询没有返回任何结果、平均和最大延迟、慢查询分析以及随时间变化的搜索量。将这些查询转换为已保存的Kibana可视化。你需要准备什么一个 Elastic Cloud 部署或启用了 OTel 原生摄取的自托管部署。示例基于 Elastic Stack 9.x 测试。从概念到代码构建搜索分析埋点在第一篇文章中我们介绍了为什么要使用 OpenTelemetry 来采集搜索分析数据。核心思路是向现有的 OTel span 添加search.*属性将它们发送到 Elastic APM然后使用 ES|QL 对它们进行查询。现在让我们开始构建它。想要可运行的代码本系列配套提供了一个参考项目。它是一个最小化的 FastAPI 应用包含了下面介绍的全部埋点代码。克隆该项目添加你的 Elastic Cloud 凭据10 分钟内你就能开始接收搜索分析数据。博客中的每个阶段都对应着一个带注释的代码块你可以随着阅读逐步启用它们。面向搜索 API 开发者的 OpenTelemetry 入门如果你一直在构建搜索系统但之前没有接触过 OpenTelemetry那么下面这些内容就是你需要了解的最基本知识。OTel 是一个用于收集应用可观测性数据包括追踪、指标和日志的开放标准。它与厂商无关你只需为代码埋点一次就可以将数据发送到任何兼容的后端。其中最核心的概念是span。一个 span 表示一次独立的操作例如一次 API 调用、一次数据库查询或者一次搜索请求。每个 span 都有开始时间、结束时间两者之间的差值就是span 持续时间以及属性attributes即用于描述此次操作的键值对。多个 span 通过嵌套关系组成trace。一个 trace 是由多个 span 构成的树状结构用于表示一次端到端请求。当用户执行一次搜索时这个 trace 可能如下所示浏览器请求 → API 处理器 → 搜索逻辑 → Elasticsearch 查询。每一个步骤都是一个 span而父子关系能够准确展示时间花费在哪个环节。这就是分布式追踪distributed tracing它能够跨越服务和网络边界工作因此一个 trace 可以一路跟踪请求从前端到后端再到数据库最后返回。为什么使用 trace而不是日志你当然可以记录一条类似search queryheadphones results15 took120ms的日志然后稍后再进行解析。但日志是扁平的它无法告诉你这 120ms 的 Elasticsearch 查询实际上包含在一个耗时 250ms 的 API 调用中从而暴露出应用层额外消耗了 130ms。Trace 提供了层级结构、时间信息以及跨服务的关联能力。对于搜索分析来说这意味着你不仅能够看到发生了什么还能知道时间花在哪里以及各个操作之间是如何关联的。对于本文而言你无需理解完整的 OTel 生态系统。你只需要掌握三件事当发生搜索请求时创建一个 span。向这个 span 添加属性用于描述此次搜索例如search.query或result_count。将 span 发送到 Elastic然后使用 ES|QL 对它进行查询。就是这么简单。如果你能够调用span.set_attribute(key, value)你就能够构建搜索分析。你将构建什么在本文结束时你的 API 中的每一次搜索请求都会生成一个类似下面这样的 OTel spanspan.name: search search.query: wireless headphones search.result_count: 15 search.query_id: e2afdb85eb63382e... search.took_ms: 165然后你将针对真实数据运行六个 ES|QL 查询回答你的团队已经在提出的问题而整个埋点代码总共只需要约 20 行。安装 OTel SDK这里我们使用 Python 和 FastAPI。相同的模式适用于任何提供 OTel SDK 的编程语言核心概念完全一致变化的只是导入语句。Elastic 提供了 Elastic Distribution of OpenTelemetry Python ( EDOT )它将标准 OTel SDK 与合理的默认配置、Elastic 提供的改进功能抢先体验以及一个用于处理所有样板代码的configure_opentelemetry()调用打包在一起。我们推荐使用它pip install elastic-opentelemetry \ opentelemetry-instrumentation-fastapi \ opentelemetry-instrumentation-elasticsearch三个软件包两种职责elastic-opentelemetryEDOT将 OTel API、SDK 和 OpenTelemetry Protocol ( OTLP ) 导出器整合到一个软件包中并针对 Elastic 完成了预配置。opentelemetry-instrumentation-fastapi自动为 HTTP endpoint 添加埋点为每个请求自动创建 span。opentelemetry-instrumentation-elasticsearch自动为 Elasticsearch 客户端调用添加埋点为每个查询自动创建 span。这些自动埋点软件包承担了真正的工作。无需编写任何追踪代码你就已经能够获得 HTTP 请求 span 和 Elasticsearch 查询 span。我们要做的是添加搜索相关的上下文信息将通用的追踪数据转变为搜索分析数据。**使用标准 OTel SDK**将elastic-opentelemetry替换为opentelemetry-api、opentelemetry-sdk和opentelemetry-exporter-otlp-proto-http。你需要手动配置TracerProvider、OTLPSpanExporter和BatchSpanProcessor大约多写 10 行代码。除此之外本文中的其他内容完全相同。完整的配置方法请参阅 Elastic OTel 指南。配置连接OTel 使用环境变量进行连接配置。开始之前你需要准备以下四个变量变量用途示例OTEL_EXPORTER_OTLP_ENDPOINTManaged OTLP ( mOTLP ) endpoint URLhttps://my-deployment.ingest.us-central1.gcp.elastic-cloud.comOTEL_EXPORTER_OTLP_HEADERS身份验证AuthorizationApiKey your-api-keyOTEL_SERVICE_NAME服务名称显示在 Kibana APM 中search-analytics-demoOTEL_RESOURCE_ATTRIBUTES其他资源属性service.version1.0.0这些值在哪里可以找到在 Elastic Cloud 中你的 mOTLP endpoint 遵循如下格式https://deployment.ingest.region.gcp.elastic-cloud.com。你可以在 Elastic Cloud 控制台中对应部署的详情页面找到它也可以在 Kibana 的 APM 集成页面/app/home#/tutorial/apm中的OpenTelemetry标签页找到。你的 API Key 可以通过 Kibana 的Stack Management API Keys创建也可以通过 Elasticsearch 的Create API Key API创建。对于自托管部署你可以使用 EDOT Collector 作为中间层负责接收 OTLP 数据并将其转发到 Elasticsearch。在你的环境变量或.env文件中设置它们export OTEL_EXPORTER_OTLP_ENDPOINThttps://my-deployment.ingest.us-central1.gcp.elastic-cloud.com export OTEL_EXPORTER_OTLP_HEADERSAuthorizationApiKey your-api-key export OTEL_SERVICE_NAMEsearch-analytics-demo export OTEL_RESOURCE_ATTRIBUTESservice.version1.0.0初始化 tracer完成 EDOT 和环境变量配置后初始化过程会配置三个部分tracer provider以及两个自动埋点软件包它们会自动为每一个 HTTP 请求和每一个 Elasticsearch 查询创建 spanfrom opentelemetry import trace from elastic_opentelemetry import configure_opentelemetry from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor from opentelemetry.instrumentation.elasticsearch import ElasticsearchInstrumentor def init_otel(app): configure_opentelemetry() FastAPIInstrumentor.instrument_app(app) ElasticsearchInstrumentor().instrument() tracer trace.get_tracer(search-api)configure_opentelemetry()会读取OTEL_*环境变量并使用针对 Elastic 优化的默认配置来设置 tracer provider、导出器和批处理处理器其中包括自动使用 HTTP 导出器而 mOTLP endpoint 正是需要这种导出器。如果你在使用原生 OTel 时看到连接错误最常见的原因是误用了 gRPC 导出器而不是 HTTP 导出器。这两个 instrumentor 会在启动时修改 FastAPI 和elasticsearch-py库因此每个请求和每次 Elasticsearch 调用都会自动生成一个 span无需对单独的 endpoint 进行任何代码修改。为你的搜索 API 添加埋点这里才是关键部分。这段代码将一个通用的 API endpoint 转变为搜索分析数据源from opentelemetry import trace tracer trace.get_tracer(search-api) app.post(/api/search) def search(request: SearchRequest): with tracer.start_as_current_span(search) as span: # Set attributes BEFORE the query # (available even if the query fails) query_id format(span.get_span_context().trace_id, 032x) span.set_attribute(search.query, request.query) span.set_attribute(search.query_id, query_id) results es.search( indexproducts, bodybuild_query(request) ) # Set attributes AFTER the query total_hits results[hits][total][value] span.set_attribute(search.result_count, total_hits) span.set_attribute(search.took_ms, results[took]) # Include query_id in the response so the frontend can link # click and conversion events back to this search return { **format_response(results), query_id: query_id, }在分析搜索查询之前对其进行规范化注意我们目前直接存储request.query的原始值。这意味着当你使用STATS ... BY attributes.search.query进行聚合时Laptop Bag、laptop bag 和 laptop bag 会被统计为三个不同的查询。为了获得更清晰的分析结果请在设置属性之前进行规范化处理span.set_attribute(search.query, request.query.strip().lower())对于大多数场景只需要转换为小写并去除空格即可。如果你需要保留原始搜索词用于展示或调试可以将它存储在单独的属性中例如search.query.original。但建议从简单方案开始。如果之后发现需要原始版本可以随时添加。一个搜索 API trace 的结构运行后单个搜索请求会生成如下 traceHTTP POST /api/search 根节点 —— 由 FastAPI 自动埋点 └── search 我们的 span —— search.* 属性存储在这里 ├── info ES 客户端 —— 自动埋点 ├── query_rules.get_ruleset ES 客户端 └── search ES 客户端 —— 实际的 Elasticsearch 查询自动埋点的 span 会提供 HTTP 延迟和 Elasticsearch 查询详情。中间的searchspan 将这些信息与业务上下文关联起来用户搜索了什么、返回了多少结果、Elasticsearch 花费了多少时间。你需要采集的搜索 span 属性以下是我们在搜索 span 上采集的完整属性集合属性类型设置时间用途search.querystring查询之前用户输入的查询内容search.query_idstring查询之前唯一标识符根据 trace ID 派生search.result_countint查询之后匹配结果总数0 表示零结果搜索search.took_msint查询之后Elasticsearch 执行时间单位为毫秒search.query_response_hit_idsstring[]查询之后返回的文档 ID可选支持基于单个结果的分析feature_flag.keystring查询之前A/B 测试标记名称可选与feature_flag.result.variant搭配使用用于比较不同变体的点击率CTR我们使用search.*命名空间这遵循了 OTel 的约定即使用领域特定前缀http.*、db.*、messaging.*。虽然 OTel 目前还没有标准化的搜索相关约定但search.*具有自描述性并且与厂商无关。这种命名方式参考了 User Behavior Insights (UBI) 标准该标准定义了搜索事件的 schema。我们参考它的结构但不与它绑定。对于已经存在 OTel 约定的场景例如 A/B 实验中的feature_flag.key标记名称和feature_flag.result.variant分配的变体我们直接复用这些约定而不是创建自定义属性。你会注意到上面的搜索 span 属性表中没有enduser.pseudo.id。对于查询分析来说我们不需要它但当你在第三篇博客中引入点击追踪时你会立即添加它它可以将点击事件关联回特定浏览器会话从而支持基于用户的 CTR 和平均倒数排名MRR分析。第三篇博客会添加enduser.pseudo.id由浏览器生成并且跨会话保持一致用于将点击关联回搜索。我们的第四篇聚焦于收入归因的博客会介绍session.id和user.id作为已经认证用户进行跨设备归因时可选的扩展属性。OpenTelemetry 属性如何转换为可查询的 ES|QL 字段在开始查询之前你需要了解 OTel 属性如何映射到 Elasticsearch 字段。通过将 OTel 原生摄取到 Elastic 中这种映射非常简单OTel attributeTypeES|QL fieldsearch.querystringattributes.search.querysearch.result_countintattributes.search.result_countsearch.took_msintattributes.search.took_mssearch.query_idstringattributes.search.query_idfeature_flag.keystringattributes.feature_flag.key通过 OTel 原生摄取属性名称会在attributes.*下保留其点号表示形式。所有类型都位于相同的命名空间中字符串字段和数值字段之间不存在拆分。布尔值会以原生布尔类型存储而不是字符串类型。如果你之前使用过 Elastic APM 的经典摄取方式你会喜欢这种简单性你在代码中设置的内容就是你查询的内容。在 Kibana Discover 中运行 ES|QL 查询当 span 流入 Elastic 后打开 Kibana 并进入Discover在左侧边栏的Analytics下或者使用全局搜索栏输入 Discover。默认情况下你会看到 KQL 查询栏这是一种 Kibana 仪表板中常用的过滤语言。点击右上角的Try ES|QL切换到 ES|QL 编辑器。与 KQL用于过滤文档或 JSON query DSL需要嵌套对象不同ES|QL 是一种管道式语言每一个|步骤都会转换前一步的输出使得STATS count BY field这样的聚合操作可以自然地从左到右阅读。编辑器提供了一个全宽文本区域你可以在其中输入管道式查询。结果会同时以表格和自动生成的图表形式展示Kibana 会根据你的查询结构选择合适的可视化方式。对于STATS ... BY查询你会自动获得柱状图。将时间范围设置得足够宽以捕获你的数据右上角的日期选择器。如果你刚开始使用可以尝试选择 “Last 30 days/过去 30 天”。用于搜索分析的六个 ES|QL 查询下面所有查询都针对traces-generic.otel-default运行这是 Elastic 的 OTel 原生摄取功能自动存储追踪数据的索引。你不需要创建这个索引当第一个 OTLP span 到达时Elastic 会自动创建它。这些查询运行于我们的实时演示集群62 次搜索、约 20 个不同的查询延迟范围为 77ms–153ms。注意下面的结果仅用于示例。当你运行参考项目并通过python generate_traffic.py --blog 2 --sessions 50生成流量时你看到的具体数字和热门查询会根据会话数量以及随机查询选择而有所不同。这里重要的是查询模式和 ES|QL 语法。查询 1span 是否正在到达从简单开始。统计你的搜索 span 数量。FROM traces-generic.otel-default | WHERE attributes.search.query IS NOT NULL AND name search | STATS total_searches COUNT(*)结果62。如果返回 0说明你的 span 没有到达。检查你的 OTLP endpoint 和 API Key并确认init_otel()在任何请求之前已经被调用。name search过滤条件确保你统计的是自定义 span而不是自动埋点的 Elasticsearch 客户端 span这些 span 的名称也叫 search。查询 2用户正在搜索什么这是每个搜索团队都会首先提出的问题。FROM traces-generic.otel-default | WHERE attributes.search.query IS NOT NULL AND attributes.search.query ! AND name search | STATS search_count COUNT(*), avg_results ROUND(AVG(attributes.search.result_count), 0) BY attributes.search.query | SORT search_count DESC | LIMIT 20结果查询搜索次数平均结果数laptop98headphones712running shoes65laptop 是最热门的查询共有 9 次搜索。总共有大约 20 个不同的查询包括零结果查询。avg_results列告诉你热门查询是否真正返回了内容。高搜索量但低结果数的查询通常是值得调查的相关性问题。如果你的查询具有高搜索量和高结果数则需要检查用户是否实际点击了结果。我们将在下一篇聚焦于使用点击数据衡量搜索质量的博客中讨论这一点。查询 3多少比例的搜索没有返回任何结果FROM traces-generic.otel-default | WHERE attributes.search.query IS NOT NULL AND name search | STATS total COUNT(*), zero_results COUNT(CASE(attributes.search.result_count 0, 1)) | EVAL zero_rate_pct ROUND(100.0 * zero_results / total, 1)结果17.7%62 次搜索中有 11 次没有返回任何结果。我们使用attributes.search.result_count 0这是一个直接的数值比较。当你已经拥有结果数量时不需要额外的布尔属性。零结果率超过 10% 值得进一步调查。每一次零结果搜索都代表一个用户提出了需求但没有得到任何返回。其中一些可能是无效查询但另一些则会暴露真实的内容缺失或查询解析失败问题。查询 4哪些查询没有返回任何结果零结果率告诉你存在问题。这个查询告诉你问题在哪里。FROM traces-generic.otel-default | WHERE attributes.search.result_count 0 AND name search | STATS occurrences COUNT(*) BY attributes.search.query | SORT occurrences DESC | LIMIT 20结果查询次数quantum physics calculator4unicorn saddle3holographic projector2time machine parts2三种不同的失败模式quantum physics calculator 和 unicorn saddle 属于目录之外的查询你永远无法为它们提供结果。了解这一点很有价值但没有什么需要修复的内容。holographic projector 可能是一个值得考虑的新兴类别。time machine parts 很可能只是噪声。在生产环境的商品目录中这些查询会与真正可以修复的零结果查询混合在一起例如缺少同义词、表达方式不匹配或者商品缺失。重复出现的零结果查询是最高优先级的修复项。一次性失败通常只是噪声。查询 5搜索速度有多快FROM traces-generic.otel-default | WHERE attributes.search.query IS NOT NULL AND name search | STATS avg_ms ROUND(AVG(attributes.search.took_ms), 0), max_ms MAX(attributes.search.took_ms)结果平均 81ms最大 153ms。search.took_ms记录 Elasticsearch 自己报告的执行时间即搜索响应中的took字段。这与span duration不同后者表示从 span 开始到结束的实际耗时如上面的入门介绍中所述。Span duration 衡量的是端到端时间包括网络往返、序列化以及应用逻辑耗时。你需要同时关注这两个指标比较它们可以帮助你定位额外开销在哪里。如果took_ms是 50ms但 span duration 是 200ms那么额外的 150ms 来自网络或应用层开销而不是查询问题。这个属性也让你的分析更加可移植。如果你使用 OTel 日志记录而不是 span我们在本系列第一篇博客中提到的一种更轻量的替代方案那么不存在 span duration。took_ms是你唯一拥有的时间信号。我们将在本系列最后一篇聚焦于 Search Reliability Engineering 的博客中深入讨论搜索性能监控服务级别目标 [SLO]、针对延迟回退进行告警以及如何将这些数据用于运维仪表板。想要专门查找慢查询FROM traces-generic.otel-default | WHERE attributes.search.query IS NOT NULL AND name search | STATS avg_ms ROUND(AVG(attributes.search.took_ms), 0), max_ms MAX(attributes.search.took_ms), search_count COUNT(*) BY attributes.search.query | SORT avg_ms DESC | LIMIT 20平均延迟高且结果数量高的查询通常命中了大量文档可以考虑进行查询优化。高延迟但低结果数可能意味着复杂过滤条件或较慢的聚合操作。异常的最大值通常来自冷缓存或集群问题。查询 6搜索量如何随时间变化数量、比例和延迟告诉你是什么。随时间变化的搜索量告诉你什么时候什么时候流量出现峰值什么时候流量下降以及什么时候零结果率突然升高FROM traces-generic.otel-default | WHERE attributes.search.query IS NOT NULL AND name search | EVAL bucket DATE_TRUNC(5 minutes, timestamp) | STATS searches COUNT(*) BY bucket | SORT bucketDATE_TRUNC(5 minutes, timestamp)会将每个时间戳向下取整到最近的 5 分钟时间边界。结果是一个时间序列Kibana 的 Lens 可以将其渲染为柱状图或折线图用于展示任意时间范围内的搜索流量模式。缩小时间桶可以获得更高粒度1 minute扩大时间桶可以用于趋势分析1 hour、1 day。当你将这个指标与零结果率一起添加到仪表板中时你可以回答零结果率升高是因为流量发生变化还是因为某些功能出现故障验证你的搜索 API 埋点是否正常工作如果你使用参考项目完整配置步骤如下git clone https://github.com/elastic/elasticsearch-labs.git cd elasticsearch-labs/supporting-blog-content/search-analytics-otel cp .env.example .env # fill in ELASTICSEARCH_URL, ELASTIC_API_KEY, # OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS python3 -m venv venv source venv/bin/activate pip install -r requirements.txt python load_data.py # index products into Elasticsearch python app.py # starts on http://localhost:8000然后触发一次搜索curl -X POST http://localhost:8000/api/search \ -H Content-Type: application/json \ -d {query:laptop}等待 5–10 秒让BatchSpanProcessor完成刷新然后打开 Kibana → Discover → 切换到 ES|QL 模式并运行FROM traces-generic.otel-default | WHERE attributes.search.query IS NOT NULL | LIMIT 5你应该能够看到包含attributes.search.query、attributes.search.result_count和attributes.search.took_ms的数据行。如果没有出现任何数据行请按以下顺序检查OTEL_EXPORTER_OTLP_ENDPOINT指向 mOTLP endpoint而不是你的 Elasticsearch URL。OTEL_EXPORTER_OTLP_HEADERS包含AuthorizationApiKey your-key。已设置OTEL_TRACES_SAMPLERalways_on默认采样器可能会丢弃 span。Kibana → Observability → APM → Services 中显示search-analytics-demo确认导出工作正常。将 ES|QL 结果转换为 Kibana 可视化Discover 根据你的 ES|QL 结果自动生成的柱状图是一个不错的开始但你还可以对其进行自定义。点击图表右上角的铅笔图标打开内嵌的 Lens 编辑器。从这里你可以更改图表类型柱状图、折线图、面积图、饼图、表格、指标。调整坐标轴并添加拆分维度。将可视化保存到仪表板。这就是从临时 ES|QL 探索到持久化仪表板面板的路径。你不需要从头开始构建可视化Discover 和 Lens 会根据你的查询结果处理图表渲染。Lens 是 Elastic 的拖放式可视化编辑器它的能力比这个快速工作流所展示的更多。你可以构建多层图表将指标与拆分维度结合添加参考线并设计完整的仪表板将 ES|QL 面板与传统基于聚合的可视化混合使用。对于搜索分析来说这意味着你可以在一个视图中并排展示热门查询、零结果趋势和延迟百分位。深入了解Lens 文档可视化编辑器的完整指南。Lens 中的 ES|QL将 ES|QL 查询作为仪表板面板的数据源。Kibana 仪表板构建和共享运维仪表板。使用一个 在 Kibana 中构建的 agent 来帮你创建可视化我们将在之后的博客中构建一个完整的搜索分析仪表板。采样如何影响搜索分析准确性大多数应用性能监控APM配置会对 trace 进行采样以控制成本例如只采集 10% 或 25% 的请求。对于应用监控来说这没有问题。但对于搜索分析来说这是一个问题。如果你的采样率是 10%那么你的“搜索总数”统计会比实际情况低 90%。你的零结果率仍然准确因为它是一个比例但数量统计会出现偏差。有两种方法方法 1为搜索 endpoint 配置 100% 采样。你的搜索 API 处理的请求量可能远低于主应用因此数据量增加通常是可控的。最简单的方法是通过环境变量进行配置# 100% sampling (capture every trace) export OTEL_TRACES_SAMPLERalways_on # Or sample a percentage (e.g. 50%) export OTEL_TRACES_SAMPLERtraceidratio export OTEL_TRACES_SAMPLER_ARG0.5这些是在每个 trace 开始时做出的基于头部的采样决策。它们会全局应用于服务如果你的搜索 API 是一个独立服务这没有问题。如果搜索 API 与其他 endpoint 共享同一个服务并且你需要基于 endpoint 的采样规则可以在 OTel SDK 中实现自定义Sampler在做决定之前检查 span 名称或属性。更复杂的路由针对不同 endpoint 使用不同采样策略、丢弃噪声 span或者在 trace 完成后再做决策[基于尾部的采样]通常需要部署一个 OTel Collector例如 EDOT Collector作为应用和 Elastic 之间的中间层。这是一种有价值的架构模式但超出了本文范围。有关基于 Collector 的采样和路由架构的更多信息请参阅 OTel Collector 文档 和 Elastic 的 EDOT Deployment。方法 2在查询中进行放大。如果你知道采样率可以进行乘法调整EVAL estimated_total total_searches * 10。比例和平均值仍然正确只有绝对数量需要调整。有关更通用的采样策略请参阅 OTel 采样文档。本文中的查询使用了 100% 采样。下一步向搜索分析添加点击追踪本文中的六个 ES|QL 查询回答了以下问题用户搜索什么、哪些查询没有返回结果、搜索速度如何以及什么时候流量出现峰值这些数据都来自一个埋点位置搜索 span。但它们无法告诉你用户是否找到了他们需要的内容。一个返回 15 个结果的搜索从服务端角度看似乎很健康。但如果没有用户点击任何结果那么你的排序就存在问题。在下一篇博客中我们将添加点击追踪这是第二个 span用于捕获用户点击了哪个结果以及该结果在列表中的位置。如果你一直在运行参考项目那么你已经有了 62 个搜索 span下一篇博客会直接基于这些数据构建。当搜索和点击关联起来后我们将计算**点击率CTR**多少比例的搜索最终产生了点击。**平均倒数排名MRR**用户需要向下滚动多少位置才能找到结果。**点击位置分布**用户点击位置的分布情况。模式保持不变你向 span 添加属性然后使用 ES|QL 查询它们。无需引入新的基础设施你就可以从相同的数据中获得更丰富的视角。使用 OpenTelemetry 开始搜索分析的资源参考项目整个博客系列的可运行代码克隆、配置并运行即可。EDOT PythonElastic 为 Python 提供的 OpenTelemetry 发行版。OpenTelemetry 与 Elastic如何将 OTel 数据发送到 Elastic APM。OpenTelemetry Python SDK上游 SDK 文档和埋点指南。ES|QL 文档查询语言参考。UBI Standard搜索事件结构的参考 schema。这是关于使用 OpenTelemetry 和 Elastic 进行搜索分析系列文章的第二篇。下一篇衡量搜索质量点击追踪、CTR、MRR 和点击位置分析。原文Search analytics with OTel: Instrumenting your search API - Elasticsearch Labs

相关新闻

最新新闻

日新闻

周新闻

月新闻