Title: 数据模型 Locale: zh URL: https://sensorswave.com/docs/data-integration/data-model/ Description: 理解 Sensors Wave 的数据模型和数据结构 Sensors Wave 采用以事件为核心的数据模型,帮助您全面记录和分析用户行为。理解数据模型是有效使用 Sensors Wave 的基础,本文将详细介绍数据模型的核心概念和数据表之间的关系。 ## 为什么要了解数据模型? 在使用 Sensors Wave 进行数据分析之前,了解数据模型可以帮助您: - **设计合理的埋点方案**:明确应该追踪哪些事件,记录哪些属性,通过那种方式记录是最合适的 - **正确使用分析功能**:理解分析模型的基本原理和最佳使用方式 - **优化查询性能**:根据数据模型特点编写高效的查询 SQL - **避免常见错误**:避免数据重复、关联错误等问题 ## 核心概念 ### 事件 (Events) 事件是用户在应用中执行的具体行为或系统中发生的活动。事件是 Sensors Wave 数据模型的核心,所有的分析都基于事件数据展开。 **事件的组成**: 每个事件包含以下核心信息: - **事件名称** (`event`):描述用户行为的名称,如 `PageView`、`Purchase`、`UserLogin` - **事件时间** (`time`):事件发生的时间(客户端时间) - **用户标识**: - `distinct_id`:当前生效的用户唯一标识(登录 ID 优先,否则为匿名 ID) - `anon_id`:匿名 ID,标识设备或浏览器 - `login_id`:登录 ID,标识已登录用户 - `ssid`:服务端生成的用户唯一 ID,用于数据分析 - **事件属性**:描述事件的详细信息,如商品 ID、金额、来源渠道等 - **用户属性快照**:事件发生那一刻用户的属性快照,会在事件入库过程中进行关联记录 ### 用户 (Users) 用户表存储用户的基本信息和属性数据。每个用户在系统中有唯一的标识,用户的所有行为事件都会关联到这个用户。 **用户的组成**: - **用户唯一 ID** (`ssid`):服务端生成的用户唯一标识,用于关联事件表 - **登录 ID** (`login_id`):用户的业务账号 ID(如果用户已登录) - **匿名 ID 列表** (`anon_id`):用户的匿名 ID(如果登录过多个设备,会记录最后一次关联的设备 ID) - **关键时间节点**: - `$first_seen_time`:用户首次访问时间 - `$last_seen_time`:用户最后活跃时间 - **用户属性**:描述用户特征的信息,如年龄、性别、会员等级等 ### 事件属性 (Event Properties) 事件属性用于描述事件发生时的具体情况和上下文信息。事件属性随事件一起上报,不同的事件可以有不同的属性。 **事件属性的特点**: - 与特定事件关联,描述"这次行为"的详细信息 - 只在事件发生时记录,不会持久化到用户维度 - 可以用于事件筛选、分组、聚合等分析 **常见的事件属性**: | 事件类型 | 常见属性 | 示例 | |---------|---------|------| | **页面浏览** (`PageView`) | 页面标题、页面 URL、来源页面 | `page_title: "商品详情"` | | **商品购买** (`Purchase`) | 订单 ID、金额、支付方式、商品 SKU | `total_amount: 299.00` | | **用户注册** (`UserSignup`) | 注册方式、来源渠道、推荐人 | `signup_method: "email"` | | **按钮点击** (`ButtonClick`) | 按钮名称、所在页面、点击位置 | `button_name: "加入购物车"` | ### 用户属性 (User Properties) 用户属性用于描述用户的特征信息。用户属性存储在用户表中,会持久化保存,可以在任何时间更新。 **用户属性的特点**: - 与用户关联,描述"这个用户"的特征信息 - 持久化存储,直到被更新或删除 - 可以用于用户分群、漏斗分析、留存分析等 **常见的用户属性**: | 属性类型 | 常见属性 | 示例 | |---------|---------|------| | **基本信息** | 姓名、年龄、性别、城市 | `age: 28` | | **业务信息** | 会员等级、累计消费、注册时间 | `vip_level: "gold"` | | **行为特征** | 最近购买时间、购买次数、活跃天数 | `purchase_count: 15` | | **营销信息** | 注册渠道、推荐人、优惠券使用 | `signup_channel: "weixin"` | ### 事件属性 vs 用户属性 理解事件属性和用户属性的区别非常重要: | 对比维度 | 事件属性 | 用户属性 | |---------|---------|---------| | **数据范围** | 描述单次事件的详细信息 | 描述用户的整体特征 | | **存储方式** | 存储在事件表中,随事件记录 | 以快照方式存储在事件表中,最新值存储在用户表中,持久化保存 | | **更新方式** | 事件发生时记录,不可修改 | 可以随时更新、增加或删除(仅限用户表) | | **分析用途** | 事件筛选、分组统计、趋势分析 | 用户分群、留存分析、转化分析 | | **示例** | 订单金额、商品类别、页面 URL | 用户年龄、会员等级、注册时间 | **选择建议**: - **使用事件属性**:当信息与特定行为相关,且可能在不同事件中有不同值时 - (推荐) 商品 SKU(不同购买事件可能购买不同商品) - (推荐) 页面 URL(不同浏览事件访问不同页面) - (推荐) 订单金额(每次购买金额不同) - **使用用户属性**:当信息描述用户整体特征,相对稳定时 - (推荐) 用户年龄(相对固定) - (推荐) 会员等级(在一段时间内保持不变) - (推荐) 注册时间(固定不变) > **注意**:同一个信息可以同时作为事件属性和用户属性。例如,用户在某次购买时的会员等级可以作为事件属性记录(描述购买时的状态),同时当前会员等级也可以作为用户属性存储(描述用户当前状态)。 ## 数据表结构 Sensors Wave 的数据模型包含多个数据表,所有表以事件表为核心,形成星型数据模型(或雪花模型)。 > **默认表**:系统默认创建 **events 表**和 **users 表**,这两张表是数据模型的核心,必须存在。 > **可选表**:**entities 表**和 **dim_* 维度表**是可选功能,只有在用户开启相关功能并按照要求上报相关数据之后才会生成。 ### 事件表 (events) > **默认表**:系统自动创建,必须存在。 事件表是 Sensors Wave 的核心数据表,所有的事件数据都存储在这张表中。 **核心字段**: | 字段名 | 类型 | 说明 | |-------|------|------| | `time` | datetime | 事件发生时间(客户端时间) | | `event` | string | 事件名称 | | `event_id` | int | 事件 ID(服务端生成) | | `distinct_id` | string | 当前生效的用户唯一标识 | | `anon_id` | string | 匿名 ID(设备标识) | | `login_id` | string | 登录 ID(用户账号) | | `ssid` | int64 | 服务端生成的用户唯一 ID | | `trace_id` | string | 事件去重 ID(保证数据唯一性) | | `received_at` | datetime | 数据接收时间(服务端时间) | | `e_*` | 各种类型 | 事件属性字段(动态列) | | `u_*` | 各种类型 | 用户属性快照字段(动态列) | **特点**: - 事件表是一张事实表,记录用户行为的详细信息 - 不同事件类型存储在同一张表中,通过 `event` 字段区分 - 事件数据写入后不可修改(仅在用户身份关联时更新 `ssid`) - 通过 `ssid` 字段关联用户表 ### 用户表 (users) > **默认表**:系统自动创建,必须存在。 用户表存储用户的基本信息和属性数据。 **核心字段**: | 字段名 | 类型 | 说明 | |-------|------|------| | `ssid` | int64 | 用户唯一 ID(主键) | | `login_id` | string | 登录 ID | | `anon_id` | array | 设备 ID | | `$first_seen_time` | datetime | 首次访问时间 | | `$last_seen_time` | datetime | 最后活跃时间 | | `created_at` | datetime | 记录创建时间 | | `updated_at` | datetime | 记录更新时间 | | `u_*` | 各种类型 | 用户属性字段(动态列) | **特点**: - 用户表是维度表,通过 `ssid` 与事件表关联 - 支持用户属性的增删改查操作 - 一个登录 ID 关联了多个设备 ID 时,用户表中只记录最后一次关联的设备 ID - 用户属性可以随时更新 ### 多实体表 (entities) > **可选表**:仅在需要分析用户以外的其他实体时创建,例如分析设备、订单、商品等实体。 多实体表用于存储非用户实体的属性信息,支持多维度分析。 **核心字段**: | 字段名 | 类型 | 说明 | |-------|------|------| | `type` | string | 实体类型(如 `device`、`order`) | | `id` | string | 实体唯一标识(业务 ID) | | `$first_seen_time` | datetime | 首次出现时间 | | `$last_seen_time` | datetime | 最后出现时间 | | `created_at` | datetime | 记录创建时间 | | `updated_at` | datetime | 记录更新时间 | | `en_*` | 各种类型 | 实体属性字段(动态列) | **使用场景**: - **设备分析**:分析设备维度的指标,如设备型号、操作系统版本等 - **订单分析**:分析订单维度的指标,如订单状态、配送方式等 - **商品分析**:分析商品维度的指标,如商品类别、库存状态等 ### 自定义维度表 (dim_*) > **可选表**:用户可以创建自定义维度表,用于关联外部数据。 自定义维度表用于存储用户自定义的维度数据,可以与事件表进行关联查询。 **特点**: - 必须包含主键,用于与事件表关联 - 支持增删改查操作 - 适合存储百万级以下的维度数据 - 可以通过事件属性关联维度表字段 **使用场景**: - **门店维度表** (`dim_stores`):存储门店信息,通过 `store_id` 关联到事件表,用于门店维度分析 - **会员等级维度表** (`dim_vip_levels`):存储会员等级信息,通过 `level_id` 关联到用户表,用于会员分层分析 - **设备品牌维度表** (`dim_brands`):存储设备品牌信息,通过 `brand_id` 关联到多实体表,用于设备品牌分析 - **广告维度表** (`dim_campaigns`):存储广告信息,通过 `campaign_id` 关联到事件表,用于广告效果分析 ## 数据表关系 Sensors Wave 的数据模型是一个以事件表为核心的星型模型(或雪花模型)。 ### 表的分类 在数据模型中,表按照功能分为以下两类: - **事实表**:只有 **events 表**是事实表,记录用户行为的详细信息 - **维度表**: - **users 表**:用户维度表,相对于事件表的维度表(默认存在) - **entities 表**:多实体维度表,相对于事件表的维度表(可选) - **dim_* 表**:自定义维度表,可以作为事件表的维度表,也可以作为用户表或多实体表的维度表(可选) ### 数据模型示意图 以下是一个完整的数据模型示意图,展示了事件表、用户表、多实体表以及多个自定义维度表之间的关系: ``` ┌──────────────────┐ ┌──────────────────┐ │ 自定义维度表 │ │ 自定义维度表 │ │ (dim_*) │ │ (dim_*) │ │ 【可选】 │ │ 【可选】 │ └────────▲─────────┘ └────────▲─────────┘ │ │ │ 多对一 │ 多对一 │ │ ┌────────┴─────────┐ ┌────────┴─────────┐ │ 用户表 │ │ 多实体表 │ │ (users) │ │ (entities) │ │ 【必须】 │ │ 【可选】 │ └────────▲─────────┘ └────────▲─────────┘ │ │ │ 多对一 │ 多对一 │ │ ┌───────────────────────────────────────────────────┐ │ 事件表 (events) │ │ 【必须】 │ │ │ │ • 外键: ssid → users │ │ • 外键: e_* → dim_* (事件属性关联) │ │ • 外键: e_* → entities (事件属性关联) │ └──────────────────┬────────────────────────────────┘ │ │ 多对一 │ ┌───────▼──────────┐ │ 自定义维度表 │ │ (dim_*) │ │ 【可选】 │ └──────────────────┘ ``` **图示说明**: 1. **事件表(events)是数据模型的核心** - 事件表是唯一的事实表,必须存在 - 位于中心位置,所有维度表都通过事件表的外键关联 - 事件表记录用户行为,通过外键字段关联各个维度表获取更多信息 2. **用户表(users)和多实体表(entities)并列** - **用户表(users)**:必须存在,默认创建,是最核心的维度表 - **多实体表(entities)**:可选表,用于分析用户以外的其他实体 - 两者功能定位相似,都是事件表的主要维度表 - 事件表通过外键直接关联这两张表(多对一关系) 3. **自定义维度表(dim_*)的三种关联方式** - **方式一:直接关联事件表**(图示下方):通过事件属性字段(如 `e_store_id`)直接关联,形成星型模型 - **方式二:关联用户表**(图示左上):通过用户属性字段(如 `u_vip_level_id`)关联用户表,再间接关联到事件表,形成雪花模型 - **方式三:关联多实体表**(图示右上):通过实体属性字段(如 `en_brand_id`)关联多实体表,再间接关联到事件表,形成雪花模型 4. **数据流向与多对一关系** - 箭头方向表示外键关联方向:从事件表(多)指向维度表(一) - **事件表 → 用户表**:多个事件通过 `ssid` 关联到同一个用户 - **事件表 → 多实体表**:多个事件通过 `e_*` 事件属性关联到同一个实体 - **事件表 → 自定义维度表**:多个事件通过 `e_*` 事件属性直接关联到同一个维度记录 - **用户表/多实体表 → 自定义维度表**:多个用户/实体通过属性字段关联到同一个维度记录 5. **星型模型 vs 雪花模型** - **星型模型**:自定义维度表直接关联事件表,查询路径短,性能更好(适合高频查询场景) - **雪花模型**:自定义维度表先关联用户表/多实体表,再间接关联事件表,数据规范化程度更高,减少冗余(适合维度管理复杂的场景) ### 关联关系详解 #### 1. 事件表 → 用户表 **关联方式**: - 关联字段:`events.ssid = users.ssid` - 关系类型:多对一(多个事件属于同一个用户) - 数据流向:事件表通过 `ssid` 外键关联到用户表 **用途**: - 分析用户维度的指标,如用户活跃度、用户转化率等 - 通过用户属性对事件进行筛选和分组 - 例如:分析"购买"事件时,关联用户表获取用户的会员等级、注册时间等信息 #### 2. 事件表 → 多实体表 **关联方式**: - 关联字段:通过事件属性字段关联,如 `events.e_device_id = entities.id AND entities.type = 'device'` - 关系类型:多对一(多个事件关联到同一个实体) - 数据流向:事件表通过 `e_*` 事件属性关联到多实体表 **用途**: - 分析非用户实体维度的指标,如设备类型、订单状态等 - 支持多种实体类型的灵活分析 - 例如:分析"页面浏览"事件时,关联设备实体获取设备型号、操作系统等信息 #### 3. 事件表 → 自定义维度表(星型模型) **关联方式**: - 关联字段:通过事件属性字段关联,如 `events.e_store_id = dim_stores.store_id` - 关系类型:多对一(多个事件关联到同一个维度记录) - 数据流向:事件表通过 `e_*` 事件属性直接关联到自定义维度表 **用途**: - 直接关联外部数据,丰富分析维度 - 查询性能好,适合高频查询场景 - 例如:分析"购买"事件时,通过 `e_store_id` 直接关联门店维度表,获取门店名称、地区等信息 #### 4. 用户表 → 自定义维度表(雪花模型) **关联方式**: - 关联字段:通过用户属性字段关联,如 `users.u_vip_level_id = dim_vip_levels.level_id` - 关系类型:多对一(多个用户关联到同一个维度记录) - 数据流向:事件表 → 用户表 → 自定义维度表(两级关联) **用途**: - 扩展用户维度层次,减少用户表中的数据冗余 - 便于维度数据的统一管理和更新 - 例如:用户表存储 `u_vip_level_id`,通过会员等级维度表获取等级名称、折扣率等详细信息 #### 5. 多实体表 → 自定义维度表(雪花模型) **关联方式**: - 关联字段:通过实体属性字段关联,如 `entities.en_brand_id = dim_brands.brand_id` - 关系类型:多对一(多个实体关联到同一个维度记录) - 数据流向:事件表 → 多实体表 → 自定义维度表(两级关联) **用途**: - 扩展实体维度层次,支持更复杂的分析需求 - 减少实体表中的数据冗余,提高数据管理效率 - 例如:设备实体表存储 `en_brand_id`,通过品牌维度表获取品牌名称、国家等详细信息 ## 数据模型最佳实践 ### 1. 合理设计事件和属性 **事件设计原则**: - 事件名称使用大驼峰命名法(PascalCase),如 `PageView`、`UserLogin` - 事件名称要清晰表达用户行为,避免过于抽象 - 粒度适中,既不过于细化也不过于粗糙 - 保持事件语义的稳定性,避免频繁修改 **属性设计原则**: - 属性名称使用下划线命名法(snake_case),如 `order_id`、`total_amount` - 区分事件属性和用户属性,避免混淆 - 属性值类型要明确,避免同一属性使用不同类型 - 避免在属性中存储敏感信息(如密码、身份证号) ### 2. 正确使用用户标识 - 在用户登录时调用 `identify` 方法关联匿名 ID 和登录 ID - 使用稳定的业务 ID 作为登录 ID,避免使用会变化的值 - 确保匿名 ID 的唯一性和持久性 - 理解 `distinct_id`、`anon_id`、`login_id`、`ssid` 的区别和用途 详见 [如何正确的标识用户](user-identification.mdx)。 ### 3. 优化数据查询性能 **查询优化建议**: - 在筛选条件中优先使用索引字段(如 `time`、`event_id`、`ssid`) - 限制查询的时间范围,避免查询过长时间跨度的数据 - 在分组查询时,选择基数较低的字段(如事件名称、用户分群) - 使用用户分群替代复杂的用户筛选条件 **避免的做法**: - 不对高基数字段(如 `trace_id`、`distinct_id`)进行分组统计 - 不要在查询中使用过多的事件属性筛选条件 - 不要频繁查询全量数据,优先使用采样或聚合数据 ### 4. 维护数据质量 **数据质量保障**: - 在开发环境充分测试埋点代码 - 定期检查数据上报质量,监控异常数据 - 建立元数据管理规范,统一事件和属性定义 - 使用数据验证工具,确保数据格式正确 **避免的做法**: - 不要在生产环境直接测试埋点 - 不要频繁修改已有事件的语义 - 不要在事件属性中存储空值或异常值 ## 注意事项 ### 数据存储限制 - **事件表**:事件数据一旦写入不可修改(仅 `ssid` 字段会在用户身份关联时更新) - **用户表**:支持用户属性的更新,但用户删除后数据会在一定期限后物理删除 - **自定义维度表**:建议数据量控制在百万级以下,超大数据量会影响查询性能 ### 字段命名规范 - **事件属性字段**:统一使用 `e_` 前缀,如 `e_product_id` - **用户属性字段**:统一使用 `u_` 前缀,如 `u_age` - **实体属性字段**:统一使用 `en_` 前缀,如 `en_device_model` - **虚拟属性字段**:事件虚拟属性使用 `ve_` 前缀,用户虚拟属性使用 `vu_` 前缀 > **提示**:虚拟属性是在查询时动态计算的属性,不实际存储在数据表中。 ### 数据更新时机 - **事件数据**:事件发生时立即写入,无法修改 - **用户属性**:可以随时更新,建议在属性值变化时及时更新 - **实体属性**:可以随时更新,建议定期同步外部数据 - **维度表数据**:可以随时更新,建议在业务数据变化时同步更新 ## 相关文档 - [如何正确的标识用户](user-identification.mdx):了解用户标识的核心概念和最佳实践 - [事件和属性](events-and-properties.mdx):深入了解事件和属性的设计规范 - [埋点方案选择](tracking-strategy.mdx):选择合适的埋点方式 --- **最后更新时间**:2026 年 1 月 20 日