本节您需了解以下知识点,便于您快速接入
- 用户&事件模型以及事件、用户、属性等概念
- DT 用户 ID、DT-ID、账号 ID 之间的关系
- 上报数据的结构、规则、限制
一、数据模型
用户的行为会被抽象为用户(User)和事件(Event)两个实体,实体相关数据分别存入用户表和事件表,同时这两张表的数据可以分别或关联起来参与具体的分析计算
表名称 | 数据说明 |
---|---|
用户表 | 以 uid(DT 后台的用户唯一 ID)为主键标识唯一用户,存放用户的状态和不会经常变化的属性,用作描述用户的完整画像 |
事件表 | 以 event_syn(DT 后台的事件唯一 ID)为主键标识唯一事件,存放事件的发生用户、发生时间、发生地点、发生方式等关键信息,用作还原用户在应用内实际完整行为,即“某用户在某时间某地点通过某方式做了某事” |
综上所述:用户在 app 内发生的所有行为,例如打开、浏览等行为,都被 DT 系统抽象为"事件",而打开、浏览等行为的时间、地点等特征,都被 DT 系统抽象成“属性”
二、标识用户
2.1 ID 类别说明
ID 类别 | ID 名称 | 作用 | 设置方式 |
---|---|---|---|
uid | DT 用户 ID | 用户在 DT 后台的唯一标识,任意正确入库的数据都会根据 dt_id 和 acid 创建该数据的 uid 或绑定已存在的 uid ,用以明确数据的归属用户在分析模型中计算的用户去重数,就是计算的 uid 去重数 |
系统自动 |
dt_id | DT-ID | 用户在未登录状态下的唯一标识,应用卸载重新安装后,该 ID 不会变化 | 客户端 SDK 自动;服务端 SDK 用户主动 |
acid | 账号 ID | 用户在登录状态下的唯一标识 支持客户调用 setAccountId 设置用户的账号 ID, DT 系统将会以账号 ID 作为身份识别 ID,多次调用 setAccountId 将覆盖先前的账号 ID |
用户主动 |
- 任何数据接入前,都应该先确定如何标识用户,用作明确每一条用户数据或事件数据是属于哪一个用户
- 如果您的应用没有账号体系,系统自动使用
dt_id
来标识唯一用户。注意无acid则置空值,不要使用任何形式的默认值,如 空字符串 "null" "-1" 等。 - 如果您的应用带有账号体系,则可能出现一个账号在多个设备产生数据的情况,此时在数据接入过程中则需要传入
acid
,DT 系统将通过结合dt_id
和acid
这两个 ID 来标唯一用户
注意:如果一个项目中,同时接入 iOS 端和 Android 端的数据,账号 ID 必须使用同一体系,如果您同时通过客户端 SDK 和服务端接入的方式上传数据,请务必保证账号 ID 的体系一致
2.2 ID 处理逻辑
DT 系统的用户识别规则强依赖于dt_id,客户端 SDK 会自动采集,服务端 SDK 需用户主动设置
- 当系统收到数据只包含
dt_id
时,且该 ID 是第一次收到,系统会认定为是一个新用户的数据,同时为该用户新建一个uid
,同时将新建的uid
与dt_id
进行关联 - 当系统收到数据同时包含
dt_id
和acid
时,分为以下三种情况,且存在 ID 绑定机制
-
都是第一次收到,系统会认定为是一个新用户的数据,同时新建一个
uid
,同时将新建的uid
与传入 ID 进行关联,最后该数据将与新建uid
进行关联 -
acid
非第一次收到,dt_id
是第一次收到,则dt_id
将和acid
进行ID 绑定,一个acid
可以绑定多个dt_id
,即一个用户账号可能在多个设备上登录,最后该数据将与acid
此前关联的uid
进行关联 -
dt_id
非第一次收到,acid
是第一次收到,分为以下两种情况dt_id
已经和其他acid
绑定过,则dt_id
和acid
不会进行 ID 绑定,且系统新建一个uid
,最后该数据将与新建uid
进行关联dt_id
没有和其他acid
绑定过,则dt_id
和acid
会进行 ID 绑定,最后该数据将与已存在dt_id
的uid
进行关联
综上所述:uid与acid是一一对应的关系,acid与dt_id是一对多的关系,但是一个dt_id只能绑定一个acid
三、数据规则
3.1 数据结构
所有的 DT SDK 的数据上报以及 DT 服务端数据的接收处理入库,都遵循以下数据格式:
以行为单位,且符合 JSON 规则的数据,且使用 UTF-8 编码格式;即一条 JSON 数据,对应物理意义上的一条数据,数据意义上对应的是用户产生一次行为,或者是设置一次用户属性。
从结构上看,一条JSON数据,我们可以分为“数据头部”和“数据体”两部分。
- 以下是上报事件数据的样例
{
"#app_id": "dt_xxxx",
"#bundle_id": "com.datatower.ai",
"#gaid": "0e3b4bxxxxxxxd5818e8a7",
"#dt_id": "37e04xxxxxxx71a709f94",
"#acid": "abc",
"#event_time": 1678952745764,
"#event_name": "#session_start",
"#event_type": "track",
"#event_syn": "1447172248184095741",
"properties": {
"#mcc": "410",
"#mnc": "04",
"#os_country_code": "PK",
"#os_lang_code": "en",
"#app_version_code": 10202,
"#app_version_name": "1.02.02",
"#sdk_type": "Android",
"#sdk_version_name": "1.3.3.1",
"#os": "Android"
}
}
- 以下是上报用户数据的样例
{
"#app_id": "dt_xxxx",
"#dt_id": "37e04xxxxxxx71a709f94",
"#acid": "abc",
"#event_name": "#user_set",
"#event_type": "user",
"#event_time": 1678952443601,
"properties": {
"nick_name": "小张",
"last_login_time": "2023-03-16 07:40:04"
}
}
3.1.1 数据头部
数据头部指的是一条JSON数据中,与properties
同级的所有字段,主要作用是描述这条数据的基本信息,如事件名、事件的发生时间、发生事件的用户等
字段名 | 说明 | 设置方式 | 是否必传 |
---|---|---|---|
#app_id |
项目唯一标识,创建项目后 DT 后台自动分配,请在【项目设置-项目详情】中获取 如果数据中的app_id非法,则该条将会直接被过滤
|
用户主动 | 是 |
#dt_id | DT 系统中的设备唯一 ID;用户在未登录状态下的唯一标识,应用卸载重新安装后,该 ID 不会变化 | 客户端 SDK 自动 | 是 |
#event_name | 上报事件类型数据时,为事件的名称,命名规则:以字母开头,可包含数字、小写字母和下划线“_”,长度最大为 64 个字符;任何以"#"或"$"开头的自定义事件都被视为非法字段,将无法入库 上报用户类型数据时,为用户数据上报方法的名称,取值: 1. #user_set :对用户表进行操作,覆盖一个或多个用户属性,如果该属性已有值存在,覆盖先前值2. #user_set_once :对用户表进行操作,初始化一个或多个用户属性,如果该属性已有值存在,则忽略本次操作3. #user_add :对用户表进行操作,为一个或多个数值型用户属性做累加计算4. #user_unset :对用户表进行操作,清空该名用户的一个或多个用户属性的属性值5. #user_append :对用户表进行操作,对列表类型的用户属性属性添加元素 |
用户主动 | 是 |
#event_time | 事件发生时的客户端时间,获取时间戳,精确到毫秒 | 客户端 SDK 自动 | 是 |
#event_type |
数据类型,区分事件数据和用户数据 如果是事件数据,则固定填“track” 如果是用户数据,则固定填"user" |
用户主动 | 是 |
#event_syn | 由 SDK 生成,用于区分事件同一个 event_name 的事件发生多次,event_syn 均不相同 | 客户端 SDK 自动 | 是 |
#acid | 应用内的用户账号 ID;用户在登录状态下的唯一标识,可不传 | 用户主动 | 否 |
#gaid | 谷歌广告标识 ID | 客户端 SDK 自动 | 否 |
#bundle_id | 应用包名 | 客户端 SDK 自动 | 否 |
#debug |
本条事件是否debug数据,当为debug时,数据不入库
|
用户主动 | 否 |
3.1.2 数据体
数据体指的就是properties
内层的数据,properties
是一个 JSON 对象,以键值对(key-value)的形式表示。如果是事件数据,其代表了该事件的属性(相当于事件表中的属性字段);如果是用户数据,则代表需要进行设置的属性内容。
- key 值为该属性的名称,类型是字符串,自定义的属性必须以字母开头,只能包含:字母(忽略大小写)、数字和下划线“_”,且长度最大 64 个字符;另外可能会存在以#开头的 DT预置属性,具体的见DT的预置属性表
- value 值为该属性的值,当前DT支持的值类型包括:数值、文本、日期和时间、布尔、列表、对象、对象组
3.2 数据处理
3.2.1 事件及属性处理
数据操作 | 处理规则 |
---|---|
发送新事件数据 | 在收到新增事件的数据后,DT 后台会自动地创建新增事件与其属性的关联模型;如果收到了新的属性,则首次收到该属性时的属性类型将会设置为该属性的类型,属性的类型之后将不能修改 |
增添事件属性 | 如果需要对已有事件增添属性,只需要在上传数据时将新增属性一并传入即可,DT后台将会动态地关联事件与新增属性,不需要进行其他配置 |
先后发送的事件属性不一致 | 所有属性的类型会根据第一次收到该属性值的类型所决定,后续数据的类型必须与相应属性的类型一致;如果后续的数据类型与首次收到的类型不一致,DT 系统会尝试对属性做兼容转换然后按照首次收到类型进行入库处理,如果转换失败,该属性不会入库,事件正常入库 |
弃用事件属性 | 如果需要弃用事件某个属性,则只需要在 DT 后台的元数据管理中将该属性隐藏(操作可逆)即可,后续传输的数据可不传该属性。如需删除该属性的数据,请联系 DT 工作人员 |
多事件共有属性 | 不同事件的同名属性被视为是同一属性,类型一致,因此需要保证所有同名属性的类型一致,以避免由于类型不一致而导致的属性值被抛弃 |
3.2.2 用户属性处理
操作 | 对应事件名 | 处理规则 |
---|---|---|
覆盖用户属性 | #user_set |
对用户表进行操作,覆盖用户的原有属性值,如果之前不存在该用户属性,则会新建该用户属性,类型与覆盖操作传入属性的类型一致 |
初始化用户属性 | #user_set_once |
对用户表进行操作,初始化用户属性,如果该属性已有值存在,系统忽略本次操作 |
累加用户属性 | #user_add |
对用户表进行操作,对数值型的用户属性做累加计算,如果该属性还未被设置,则会赋值 0 后再进行计算,可传入负值等同于相减操作 |
清空用户属性值 | #user_unset |
对用户表进行操作,清空用户属性的属性值,即设置成 NULL,如果被清空的属性不存在也不会新建该属性 |
追加列表型用户属性的元素 | #user_append |
对用户表进行操作,对列表类型的用户属性追加元素,如果被追加的列表属性不存在,系统将自动生成并进行追加 |
追加并去重列表类型用户属性的元素 | #user_uniq_append |
对用户表进行操作,对列表类型的用户属性值追加元素,并会进行一次全列表去重(去重保证前后原有的元素顺序不变),如果被追加的列表属性不存在,系统将自动生成并进行追加再去重 |
3.3 数据限制
3.3.1 数据数量限制
DT对每个公司账号有项目数量限制,每个项目有元事件、元事件属性和用户属性数量的限制,具体限制数,您可以在【项目详情】中查看,其中各部分的数量说明如下:
- 元事件:已上报的事件类别,包含预置事件、自定义事件、服务端事件,不包含虚拟事件
- 元事件属性:已上报的事件属性,包含预置事件属性、自定义事件属性、服务端事件属性,不包含虚拟属性、维度表属性。如上报属性超出限制,则包含超出限制数量的任意事件都不会入库,且做丢弃处理
- 用户属性:已上报的用户属性,包含预置用户属性、自定义用户属性、服务端用户属性,不包含虚拟属性、维度表属性。如上报属性超出限制,则包含超出限制数量的任意事件都不会入库,且做丢弃处理
注意:上报的元事件及其属性和用户属性的数量越多,分析模型计算消耗的性能越大,直接影响计算速度
3.3.2 数据名称限制
数据类别 | 名称 |
---|---|
事件 | String 类型,以字母开头,可包含数字、小写字母和下划线“_”,长度最大为 64 个字符 |
属性 | String 类型,以字母开头,可包含数字、小写字母和下划线“_”,长度最大为 64 个字符 |
注意:任何以"#"或"$"开头的自定义事件都被视为非法字段,将无法入库
3.3.3 数据类型限制
DT 数据类型 | 取值样例 | 取值说明 | 数据类型 |
---|---|---|---|
数值 | 123,1.23 | 数据范围是 -1.79E308 至 1.79E308,精度为 15 位有效数字 | Number |
文本 | "ABC","深圳" | 字符的默认上限是 2000 个字符,包括中英文 | String |
日期和时间 | "2019-01-01 00:00:00","2019-01-01 00:00:00.000" | "yyyy-MM-dd HH:mm:ss.SSS"或"yyyy-MM-dd HH:mm:ss",如需表示日期,可使用"yyyy-MM-dd 00:00:00"注意:对于数据类型为“日期和时间”的属性,不论用户传入什么时区,系统都会认为是 UTC 时区 | String |
布尔 | true,false | - | Boolean |
列表 | ["a","1","true"] | 列表中的元素都会转变为字符串类型列表内最多 500 个元素,且列表内总的字符数量不超过 60000 个 | Array(String) |
对象 | {"uid":"123","life_cycle_days":10,"hero_list": ["亚瑟","小乔"],"hero_skin_count":10} | 对象内的每个子属性(Key)都有自己的数据类型,取值说明请参考上面对应类型的普通属性对象内最多 100 个子属性,且 对象内 key+ value 总的字符数量不超过 60000 个 | Object |
对象组 | [{"uid":"123","life_cycle_days":10,"hero_list": ["亚瑟","小乔"],"hero_skin_count":10}, {"uid":"123","life_cycle_days":10,"hero_list": ["亚瑟","小乔"],"hero_skin_count":10}] | 对象组内的每个子属性(Key)都有自己的数据类型,取值说明请参考上面对应类型的普通属性对象组内最多 500 个对象,且对象组内 key+ value 总的字符数量不超过 60000 个 | Array(Object) |
- 数据接收时限
服务端数据和客户端数据的接收时间限制一致,都为:相对服务器时间的前 7 天至后 1 天
如有历史数据导入需求,请联系 DT 工作人员
3.4 其他注意事项
-
DT 系统会对近 1 小时内的事件数据根据
#event_syn
进行校验去重 -
对于数据类型为“日期和时间”的属性,不论用户传入什么时区,系统都会认为是 UTC 时间
-
用户属性操作的结果取决于服务端收到事件的时间
-
用户属性是用户具有节点意义的属性,不建议在短时间内进行频繁修改,对于需要频繁变更的属性,建议放在事件中作为事件属性
-
用户属性变更的结果取决于服务端收到数据的顺序,和
user_set
事件的事件时间无关,所以频繁的修改用户属性无法保证最终结果的正确 -
如果上报的属性类型与预期不一致,可以通过虚拟属性功能自主转换数据类型或联系 DT 工作人员进行处理
- 虚拟属性转换示例:任意类型属性转换为数值类型 →
cast(dt_e."复制的属性名" as int)
- 虚拟属性转换示例:任意类型属性转换为数值类型 →
-
如果数据传输有误,需要对数据进行删除,请联系 DT 工作人员进行处理