2. 核心概念:事件、用户、会话、属性、时间戳的定义与关系
好,我们直接进入正题。用户行为流产品化设计,说白了就是围绕五个核心概念搭起来的:事件、用户、会话、属性、时间戳。这五个东西你搞清楚了,后面所有模型、管道、分析逻辑都是它们的排列组合。
我记得刚带团队做用户行为平台时,有个同事把「事件」和「属性」混在一起存,结果查询时维度拆不开,整张表重做。嗯,这种坑踩过一次你就记住了。
2.1 事件(Event)—— 行为的最小原子
事件就是用户在系统里做的一件事。一次点击、一次滑动、一次支付提交,都是事件。它不可再分,是行为流的最小单元。
我个人习惯把事件分为三类:
| 类型 | 举例 | 特点 |
|---|---|---|
| 自动采集事件 | 页面浏览、App 启动/退出 | SDK 自动触发,无需业务埋点 |
| 业务事件 | 加入购物车、提交订单、支付成功 | 需手动埋点,携带业务上下文 |
| 虚拟事件 | 「高价值用户注册」= 注册事件 + 首充事件 | 由多个原始事件组合而成,不在原始流中存储 |
{对象}_{动作} 的命名规则,比如 product_add_to_cart。
2.2 用户(User)—— 行为的载体
用户是事件的发起者。没有用户,事件就是孤立的噪声。
这里有个关键问题:用户怎么标识?
- 登录用户:用 user_id,稳定可靠。
- 未登录用户:用设备 ID(device_id)或 Cookie ID。
- 跨设备用户:需要 ID 映射表(ID-Mapping),把手机、电脑、小程序的同一用户关联起来。
你想想看,如果用户没登录就加购了商品,登录后又提交了订单,这两个事件如果分属两个不同的「用户」,那转化率就永远算不对。这就是为什么用户身份合并是行为流系统的第一道坎。
2.3 会话(Session)—— 行为的自然分段
会话把连续的事件切分成有意义的「段」。一次会话代表用户一次连续的、有目的的交互过程。
怎么切?常见策略:
- 超时切分:事件间隔超过 30 分钟(或自定义时长),自动开启新会话。
- 午夜切分:跨天时强制新会话。
- 场景切分:从首页到详情页到支付页,算一次会话;切到后台再切回来,算新会话。
我个人习惯用「超时 + 场景」组合策略。纯超时切分会把用户中午用和晚上用算成一次会话,这显然不合理。
2.4 属性(Properties)—— 事件的上下文
属性是事件的「形容词」。事件本身只告诉你「做了什么」,属性告诉你「在什么条件下做的」。
属性分两类:
| 属性类型 | 示例 | 说明 |
|---|---|---|
| 事件属性 | 商品 ID、价格、页面来源 | 随事件一起上报,只对该事件有效 |
| 用户属性 | 会员等级、注册渠道、性别 | 绑定在用户上,所有事件共享 |
举个例子:用户「点击购买」这个事件,事件属性里带着 product_id: 1001、price: 299,用户属性里带着 vip_level: gold。这样你就能分析「黄金会员是否更倾向于购买 200-300 元价位的商品」。
2.5 时间戳(Timestamp)—— 行为的坐标轴
时间戳是事件在时间轴上的坐标。没有时间戳,事件就是一盘散沙,你没法排序、没法算间隔、没法做漏斗。
这里有两个时间戳必须区分:
- 客户端时间戳:事件发生时的本地时间。问题在于用户可能改了系统时间,或者时区不对。
- 服务端时间戳:事件到达服务器的时间。问题在于网络延迟会导致时间偏差。
我个人习惯的做法是:双时间戳都存。客户端时间戳用于行为序列分析(用户真实操作顺序),服务端时间戳用于数据完整性校验(防止客户端篡改)。分析时以客户端时间戳为主,但做异常检测时会比对两者差值。
2.6 五者关系 —— 一张图说清楚
这五个概念不是孤立的。它们的关系可以用一句话概括:一个用户在一次会话中,在某个时间点触发了一个事件,并携带了若干属性。
下面这张图展示了它们之间的逻辑关系:
2.7 数据模型示例
最后,我们看看这五个概念在数据层面怎么落地。下面是一个典型的事件表结构:
-- 用户行为事件表(简化版)
CREATE TABLE user_behavior_events (
event_id BIGINT PRIMARY KEY, -- 事件唯一 ID
user_id VARCHAR(64) NOT NULL, -- 用户标识
session_id VARCHAR(64) NOT NULL, -- 会话 ID
event_name VARCHAR(128) NOT NULL, -- 事件名称
event_time DATETIME NOT NULL, -- 客户端时间戳
server_time DATETIME NOT NULL, -- 服务端时间戳
event_props JSON, -- 事件属性(JSON 格式)
user_props JSON -- 用户属性(快照)
);
你看,五个概念在这张表里全齐了。每一行记录就是一个完整的行为原子。