部署开源埋点分析系统后,最容易让人误判的画面,是看板已经显示"打开应用 → 浏览商品 → 加购 → 购买"。四个阶段都有数,似乎意味着用户转化漏斗已经跑通。但事件分布图、阶段用户数和按同一用户、按时间顺序计算的转化漏斗,是三种不同的东西。
本文用 SensorFlow 的公开 Demo 数据生成脚本做一个反例。它能帮新用户确认 ClickHouse 与 Superset 的演示链路,不是生产 SDK 的真实行为样本。我们直接读脚本、运行 SQL,看看一个"四阶段看板"到底证明了什么。
看板显示四个阶段,是否意味着真实用户完成了漏斗?
不能。 四个事件名都有记录,只证明每个阶段分别出现过;即便每个阶段都有去重用户,也不能证明有同一个用户依次完成这些阶段。真正的漏斗还需要固定用户标识、时间窗口、事件顺序、时区、去重和重试规则。
SensorFlow 的演示阶段由 ./install.sh 导入标记为 app_id = 'sensorflow-demo' 的合成事件,并创建 Superset 图表;此时真实神策 SDK 接收服务尚未启动。需要真实接收时,应按中文快速开始另行激活许可证。演示看板只能用于检查部署与可视化,不应拿来证明业务转化率。
先看数据是怎样造出来的
Demo SQL从 numbers(240) 产生 240 条记录。事件由 number % 12 决定,用户由 number % 48 决定。因为 48 是 12 的倍数,同一个 demo-user-* 在这批样本里总落在同一类事件,而不是跨阶段移动。
它还把事件时间按每条间隔 3 小时回推,并给购买事件设置演示收入。is_first_day 只是生成脚本设置的示例值,不是生产环境中经过身份合并后计算的"真实新用户"。这些设计适合展示图表形状,但不足以验证同一用户的完整转化路径。
从表结构可见,事件表叫 sensors.event,关键字段有 time、event、distinct_id、app_id。先查询各阶段的行数与去重用户数:
sql
SELECT
event,
count() AS event_rows,
uniqExact(distinct_id) AS users
FROM sensors.event
WHERE app_id = 'sensorflow-demo'
GROUP BY event
ORDER BY event;
在当前脚本首次、只导入一批 240 条 Demo 事件 的情况下,四个阶段分别是:打开应用 100 行/20 人,浏览商品 80 行/16 人,加购 40 行/8 人,购买 20 行/4 人。这里的"人"是 distinct_id 去重结果,不等于实际客户人数。若你运行的是旧版脚本或已有演示数据,结果可能不同;请以自己表里的记录为准。
再检查"浏览过的人"与"买过的人"是否重叠
最小的下一步不是马上算 4 / 16 = 25%,而是查同一 distinct_id 是否同时出现两个事件:
sql
WITH per_user AS
(
SELECT
distinct_id,
countIf(event = 'demo_product_view') > 0 AS viewed,
countIf(event = 'demo_purchase') > 0 AS purchased
FROM sensors.event
WHERE app_id = 'sensorflow-demo'
GROUP BY distinct_id
)
SELECT
countIf(viewed) AS view_users,
countIf(purchased) AS purchase_users,
countIf(viewed AND purchased) AS both_users
FROM per_user;
按当前生成脚本,结果是 16 / 4 / 0:16 个浏览用户、4 个购买用户,同时满足两者的用户为 0 。所以 4 / 16 不是这批样本的"浏览到购买转化率"。上述 SQL 只检查用户交集;即使交集大于 0,它仍没有证明"先浏览、后购买",还要进一步加入时间顺序与窗口。
这里刻意使用 ClickHouse 的 countIf 条件聚合和 uniqExact 精确去重。大规模生产数据是否选近似去重,需要再按内存与精度要求评估,不能把 Demo 查询性能当成压测结果。
真正的漏斗至少多出三个约束
第一是同一人 。匿名 ID 和登录 ID 是否合并?distinct_id 是否跨设备稳定?若身份规则变化,UV 和漏斗分母都可能变化。
第二是顺序与窗口 。浏览、加购、购买必须按定义顺序发生,且全部落在约定时间内。ClickHouse windowFunnel 文档描述的正是时间窗口内的事件链计算;但窗口单位取决于时间戳参数类型。SensorFlow 表中的 time 是 DateTime64(3),不能未经验证就把现成秒级示例直接套到毫秒字段上。
第三是口径隔离 。看板和 SQL 应统一过滤 app_id,把 sensorflow-demo、测试环境和真实生产流量分开。购买事件里的演示收入不应进入真实 GMV;测试账号的事件也不应算入运营报表。
当这些约束确定后,再用少量人工可核对的真实 SDK 测试事件验证整条链路:客户端网络请求成功、接收端处理成功、ClickHouse 原始记录正确、Superset 指标与 SQL 一致。神策 SDK 接入说明列出了需要检查的接收地址和兼容边界。不要用演示图表替代真实事件验证。
一个可执行的验收顺序
- 看仓库中的 Demo 生成 SQL,确认它是否代表真实用户旅程;不要只看图形名称。
- 用
count()看行数,用uniqExact(distinct_id)看各阶段用户数,先分清事件量与人数。 - 用按用户聚合的
countIf检查阶段交集;没有交集时,不计算转化率。 - 用人工构造的跨阶段测试用户,再验证事件先后顺序、时间窗口和身份合并。
- 将 Demo、staging、production 分开,在 Superset 中复核与原始 SQL 相同的过滤条件。
结论很简单:演示看板验证的是系统可展示,真实漏斗验证的是数据语义。 对已有神策 SDK 的团队,SensorFlow 的价值在于能把事件送到自有 ClickHouse、让工程团队直接检查原始记录;代价是团队仍要定义指标口径并运维 Go、ClickHouse 和 Superset。若你更需要现成的完整产品分析界面,而不打算维护 SQL 指标,应另外评估专门的分析产品。
想复核本文的例子,直接从公开仓库的 Demo SQL开始,先跑两条查询,再决定是否激活真实 SDK 接收。