- 可观测性
- 后端
【免费下载链接】highlight
highlight.io: The open source, full-stack monitoring platform. Error monitoring, session replay, logging, distributed tracing, and more.
这篇指南以 highlight.io 的 Dashboards(仪表盘)产品为核心,讲解如何利用事件(events)数据源与CountDistinct 聚合函数,从零搭建一张统计"点击了页头链接(header links)的独立用户数"的柱状图。你将掌握事件源选型、过滤器编写、函数与分组配置、以及从"独立用户(unique users)"切换为"独立会话(unique sessions)"的完整方法,并理解 CountDistinct 在底层 ClickHouse 查询中是如何被生成与执行的。
教程目标与核心概念
用户分析(User Analytics)的核心问题通常是:"有多少不同的用户在使用我的应用的某个功能?"。本教程的目标是追踪点击了页头(header)中链接的独立用户数,借此理解用户与应用的交互行为与趋势。
实现这一目标依赖 highlight.io 的三层能力:
- 事件数据源:会话中产生的点击(Click)、导航(Navigate)以及自定义事件,都可以作为指标查询的数据来源;
- 用户标识:通过
H.identify()上报的identifier属性,用于区分"不同用户"; - CountDistinct 聚合:对标识字段去重计数,从而得到独立用户数而非事件总数。
在动手前,建议先阅读 Dashboards 总览 与 图表编辑(Graphing)文档 了解编辑器全貌。
准备工作:确保事件与用户标识被正确上报
在仪表盘中做用户分析之前,需要确认应用侧已经正确上报了事件与用户标识,否则图表将无数据可查。
上报用户标识
调用H.identify()为会话绑定用户级标识(如邮箱、ID),该调用会自动为会话建立索引,使其可以被这些属性过滤:
H.identify('eliza@corp.com', { id: 'ajdf837dj', phone: '867-5309' })其中第一个参数即identifier属性(如eliza@corp.com),是本教程 CountDistinct 去重的依据。还可以通过 metadata 中的highlightDisplayName、email、avatar覆盖会话查看器中的显示名与用户头像。
上报自定义事件
本教程过滤目标为自定义事件header-link-*,其中*表示被点击链接的后缀(例如点击首页链接会触发header-link-home)。这类事件需要在你的应用中手动上报,上报后即可在事件搜索与仪表盘中按事件名过滤。
分步搭建图表:独立用户点击统计
下面按官方教程的完整步骤,在 highlight.io Dashboards 的图表编辑器中配置这张柱状图。
第 1 步:选择数据源(Source)
在图表编辑器中,将Source(数据源)设置为events(事件)。事件数据源包含会话中的点击、导航动作以及自定义事件,能提供用户与应用交互的细粒度信息。这与 logs、traces、sessions、errors 等数据源并列,是 highlight.io 六类可查询资源之一。
第 2 步:选择图表类型(View Type)
将View type设置为Bar chart / histogram(柱状图/直方图)。柱状图擅长比较不同类别之间的数值,非常适合按事件名分组后对比各类事件的独立用户量。也可以按需切换到 Line chart(折线图)或 Table(表格)。
第 3 步:应用过滤器(Filters)
在Filters输入框中写入事件搜索查询,聚焦到目标事件。本例中过滤到自定义事件header-link-*:
event=header-link-*事件搜索的默认键是event,如果只输入header-link-*也会被解析为event=*header-link-*。关于键值语法、正则(=[regex])、exists等操作符的完整说明,可参考 搜索语法文档。
第 4 步:应用函数(Function)——CountDistinct 独立用户数
此时查询返回的是事件总数,而非用户数。要得到去重后的独立用户数,将Function(函数)更新为CountDistinct,字段选择identifier属性。identifier是每个用户的唯一标识(如邮箱或 ID),对它的值去重计数即可得到独立用户数。
关于标识的更多说明(显示名、头像、未识别会话的行为等),见 识别用户(Identifying Users)文档。
第 5 步:分组数据(Group by)
开启Group by,按event name(事件名)对结果分组。这样,被过滤出的header-link-*事件会被拆分为具体发生的事件(如header-link-pricing、header-link-docs),每一类独立显示一根柱。
第 6 步:分析结果
最终的图表展示的是所有被过滤会话中,每个事件的去重邮箱数(即独立用户数)。借助这张图你可以:
- 找出被点击最多的事件(即页头中最受欢迎链接);
- 观察用户参与度随时间的变化趋势;
- 判断应用中哪些区域被最频繁访问。
第 7 步:细化指标——切换到独立会话
如果希望统计独立会话(unique sessions)而非独立用户,只需将CountDistinct的字段从用户标识改为secure_session_id(事件发生的会话 ID)。这在需要区分"用户量"与"访问量"、计算 DAU(日活跃用户)等场景下非常有用。关于事件的更多搜索与属性用法,见 事件搜索文档。
第 8 步:解读数据并采取行动
利用图表洞察应用的整体使用情况:
- 识别页面上被使用最多的部分;
- 发现参与度下降的趋势并调查潜在原因;
- 识别驱动更高参与度的成功功能或内容;
- 基于用户参与模式规划有针对性的改进或营销活动。
建议定期监控并复查这些指标,随着应用与用户群体的演进持续调整。
底层实现:CountDistinct 如何变成 SQL
理解 CountDistinct 的底层执行有助于判断查询开销与结果语义。在 backend/private-graph/graph/schema.graphqls 中,MetricAggregator枚举定义了可用的聚合函数,包括Count、CountDistinct与CountDistinctKey(CountDistinctKey专用于对某个键去重计数):
enum MetricAggregator { Count CountDistinct CountDistinctKey # ... Min / Avg / P50 / P90 / P95 / P99 / Max / Sum 等 }前端图表配置的聚合函数会映射到后端 Go 代码,最终翻译为 ClickHouse SQL。在 backend/clickhouse/query.go 的getFnStr函数中可以看到具体的翻译规则:
case modelInputs.MetricAggregatorCountDistinctKey, modelInputs.MetricAggregatorCountDistinct: if useState { return fmt.Sprintf("uniqState(toString(%s))", column) } return fmt.Sprintf("round(count(distinct %s) * 1.0)", column)也就是说:
- CountDistinct(identifier)最终生成为
count(distinct identifier),即 ClickHouse 对identifier去重后计数; - 在增量聚合(State 模式,用于指标预聚合)下则使用
uniqState(toString(identifier)),把去重计数的中间状态持久化下来,避免重复全表扫描; getLimitFnStr(query.go)在限制分组数量(如 "Limit 10 by Count")时使用同样的去重逻辑。
这正是"图表上的一个下拉选项,背后是一整套 ClickHouse 去重计数执行链路"的体现。
进阶:事件搜索、自动注入属性与漏斗分析
事件的自动注入属性
事件在写入时会被注入一批默认属性,均可作为过滤与分组依据。与本教程直接相关的有:
| 属性 | 说明 | 示例 |
|---|---|---|
event | 发生的事件名 | SessionsPageLoaded |
identifier | 传入H.init/H.identify的用户标识 | 1 |
secure_session_id | 事件所在会话的 ID | e1845285cb360410aee05c61dd0cc57f85afe6da |
identified | 会话是否成功识别了用户 | false |
first_session | 是否为该用户的首个会话 | false |
browser_name/os_name/country/city/state | 浏览器、系统与地理位置信息 | Chrome/Mac OS X/Greece |
完整的自动注入属性表见 事件搜索文档 的 "Searchable Attributes" 小节。
特殊事件:Click 与 Navigate
highlight.io SDK 默认记录两类事件:
- Click 事件:由鼠标按下动作触发(即使点击的是非可交互元素,如页头空白处),主要属性包括
clickTextContent(被点击内容的文本)、clickTarget(被点击的 HTML 元素)、clickSelector(被点击元素的完整 HTML 路径); - Navigate 事件:由 URL 变化触发(含刷新),主要属性包括
url、landing_page、exit_page、reload。
本教程以自定义事件header-link-*为例,但同样可以直接对默认 Click 事件做用户分析,例如统计"点击了页头导航区域的独立用户数"。
用漏斗(Funnel)串联多个事件
事件分析不仅限于单张图。在事件搜索中选择Funnel Chart视图类型,可以查看一个会话中按步骤依次发生多个事件的比例——例如"点击页头链接 → 访问定价页 → 触发注册"的转化漏斗,与上述独立用户统计互为补充。
常见问题与最佳实践
Q1:CountDistinct 与 Count 有什么区别?Count 统计事件发生次数(同一用户点击多次会重复计入);CountDistinct 对指定字段去重(同一用户多次点击只计一次)。做"独立用户数"时必须用 CountDistinct +identifier。
Q2:什么时候用secure_session_id而不是identifier?统计"有多少次独立访问"时用secure_session_id(每次会话计一次);统计"有多少个独立的人"时用identifier(每人计一次)。指标含义(访问量 vs 用户量)完全不同。
Q3:图表的其他字段怎么配?
- Bucket by:默认按
Timestamp聚合为时间序列;也可以改为其他数值字段做直方图分布(如duration);禁用后则在整个时间范围内做聚合(适合表格形式的汇总指标); - Group by 的 Limit:可以限制展示的分组数量,例如按 Count 只展示 Top 10 事件,让图表更聚焦;
- Graph title:为每张图设置清晰的标题,便于在仪表盘中识别。
最佳实践:先确认事件与H.identify()已正确上报,再搭建图表;同时用"事件总数"与"独立用户数"两张图对比,可以快速判断某个页头链接是"少数人频繁点击"还是"多数人少量点击";最后定期复查指标定义,随着产品功能与用户规模演进及时调整分组维度与过滤条件。
至此,你已经掌握了在 highlight.io 中用事件数据源 + CountDistinct 做用户分析的完整流程,可以将其推广到任意自定义事件、默认 Click/Navigate 事件,以及漏斗分析等更复杂的场景中。
- 可观测性
- 后端
【免费下载链接】highlight
highlight.io: The open source, full-stack monitoring platform. Error monitoring, session replay, logging, distributed tracing, and more.
相关推荐
PostHog 深度指南:基于 $autocapture 事件探索用户点击行为与构建 Action
PostHog 深度指南:基于 $autocapture 事件探索用户点击行为与构建 Action 本文围绕 PostHog 仓库中 exploring aut
数据分析后端前端数据可视化大数据Flet Map 的 MapTapEvent:地图点击事件的数据结构与实战用法
Flet Map 的 MapTapEvent:地图点击事件的数据结构与实战用法 本篇技术指南聚焦于 Flet 开源仓库中 flet_map 包( Python
前端跨平台桌面应用移动开发Popcorn Time用户行为分析:事件跟踪与数据统计
Popcorn Time用户行为分析:事件跟踪与数据统计 你是否曾好奇自己在Popcorn Time上的观影习惯?为何某些节日会看到特殊界面?本文将带你深入了解
音视频
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考