看板有漏斗阶段,为什么转化率仍可能是假的?用 ClickHouse 检查演示埋点

部署开源埋点分析系统后,最容易让人误判的画面,是看板已经显示"打开应用 → 浏览商品 → 加购 → 购买"。四个阶段都有数,似乎意味着用户转化漏斗已经跑通。但事件分布图、阶段用户数和按同一用户、按时间顺序计算的转化漏斗,是三种不同的东西。

本文用 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 接入说明列出了需要检查的接收地址和兼容边界。不要用演示图表替代真实事件验证。

一个可执行的验收顺序

  1. 看仓库中的 Demo 生成 SQL,确认它是否代表真实用户旅程;不要只看图形名称。
  2. 用 count() 看行数,用 uniqExact(distinct_id) 看各阶段用户数,先分清事件量与人数。
  3. 用按用户聚合的 countIf 检查阶段交集;没有交集时,不计算转化率。
  4. 用人工构造的跨阶段测试用户,再验证事件先后顺序、时间窗口和身份合并。
  5. 将 Demo、staging、production 分开,在 Superset 中复核与原始 SQL 相同的过滤条件。

结论很简单:演示看板验证的是系统可展示,真实漏斗验证的是数据语义。 对已有神策 SDK 的团队,SensorFlow 的价值在于能把事件送到自有 ClickHouse、让工程团队直接检查原始记录;代价是团队仍要定义指标口径并运维 Go、ClickHouse 和 Superset。若你更需要现成的完整产品分析界面,而不打算维护 SQL 指标,应另外评估专门的分析产品。

想复核本文的例子,直接从公开仓库的 Demo SQL开始,先跑两条查询,再决定是否激活真实 SDK 接收。

相关推荐
LucianaiB1 小时前
【TextIn xParse 与 Workbuddy实践】我把答辩材料丢给 AI 审了一遍,它开始追着我要证据
后端
王中阳Go1 小时前
读者问"你用的什么 Agent":3 个 AI 员工的分工表和工具链
人工智能·后端·ai编程
BadQiang1 小时前
Java 调用 Python 服务,报错后该从哪里查起?
后端
Hashan1 小时前
Vibe Coding 下前后端怎么对接接口?后端不给力的兜底方案
前端·后端·vibecoding
小蒜学长1 小时前
基于SpringBoot+Vue的小学数学智能出题系统(代码+数据库+LW)
java·数据库·spring boot·后端·智能出题系统
小朱爱编程1232 小时前
我用 Jev 做了三个实用工具:整理标签页、分诊飞书反馈、找回 GitHub 收藏
java·开发语言·人工智能·后端·python·架构·ai编程
明月_清风2 小时前
企业买了 Codex、WorkBuddy,AI 为什么还是没落地?我用 FDE + AKA 做深度定制
人工智能·后端
喵个咪3 小时前
RushWind Admin — 用 Rust 写的企业级中后台,开源了
后端·rust·开源
喵个咪3 小时前
RushWind Admin — 契约驱动:203 条路由零手写的工程化拆解
后端·rust·开源