数据格式
|
收藏
神策分析支持多种不同语言的 SDK,这些 SDK 虽然在外部提供的接口上有所不同,但是在内部实现上都使用统一的数据格式,在这里,我们对数据格式进行一个更加细致的描述。
如果您使用非 SDK 采集数据,需要按照本章节中的数据格式来构造数据。
- 注意:这里描述的是底层数据传输格式的定义,和具体 SDK 的调用接口无关。
1. 数据整体格式
发送端使用 JSON 作为数据传输格式,本系统以 JSON 数据类型为基础,再加以特定的限制。
1.1. 事件数据举例
记录一个事件及关联的属性。
{
"distinct_id": "0f485d4daaadedae5f",
"anonymous_id":"0f485d4daaadedae5f",
"time": 1434556935000,
"type": "track",
"event": "ViewProduct",
"project": "ebiz_test",
"time_free": true, //建议在导入历史数据时使用,SDK 采集的实时数据不建议使用
"identities":{
"$identity_android_id":"0f485d4daaadedae5f"
},
"properties": {
"$app_version":"1.3",
"$wifi":true,
"$province":"湖南",
"$city":"长沙",
"$user_agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_2 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/58.0.3029.113 Mobile/14F89 Safari/602.1",
"$screen_width":320,
"$screen_height":568,
"product_id":12345,
"product_name":"苹果",
"product_classify":"水果",
"product_price":14.0
}
}
对于上述字段的说明如下:
- distinct_id:类型是字符串,对用户的标识,对未登录用户,可以填充设备标识、CookieID 等,对于登录用户,则应该填充注册账号;这里的例子,假设是一个匿名用户,所以填充的是一个设备 ID;
- login_id、anonymous_id:类型是字符串,对用户的标识,对未登录用户,只有 anonymous_id,而无 login_id 信息;
- time:类型是数值,事件发生的实际时间戳,精确到毫秒;
- type:表示一条数据的具体操作(小结部分会详细介绍),track 表明是记录一个事件 ,这里假设是一个商品浏览行为;
- event:事件名,需是合法的变量名,即不能以数字开头,且只包含:大小写字母、数字、下划线和 $,其中以 $ 开头的表明是系统的预置事件,自定义事件名请不要以 $ 开头,且 event 字段长度最大为 100;
- project:这条数据所属项目名,若不指定该参数,则需要使用该字段时取值 default,即默认项目。指定的项目必须是系统中已经存在的项目,否则这条数据将无效,更多项目相关请参见多项目;
- time_free:可选字段,表示不根据事件发生时间过滤该事件。只要出现 time_free 这个 key 且 value 不为 null,将不再校验 time 是否在允许导入的时间范围内。导入历史数据时可能会用到该字段;
- identities:全域用户关联业务中用户标识字段,可包含多个用户标识,具体可以参考全域用户关联;
properties:这个事件的具体属性,以 dict 的形式存在。其中以 $ 开头的表明是系统的预置属性,它的类型和中文名已经预先定义好了。
自定义属性名需要是合法的变量名,不能以数字开头,且只包含:大小写字母、数字、下划线,自定义属性不能以 $ 开头;
同一个名称的 property,在不同 event 中,必须保持一致的定义和类型;
同一个名称的 property 大小写不可以相同,如果已经存在小写属性就不可再导入对应大写属性(比如元数据中有 abc 属性名,不能再传 ABC,Abc 等属性名),否则数据会校验失败不入库。- $app_version:用户所使用的 App 的版本;
- $wifi:这条事件发生时,用户是否在使用 wifi;
- $province、$city:省、市,在没有填充这两个字段的时候,会根据 IP 进行解析;
- $user_agent:可选参数。如果传入该参数,则解析 User-Agent,解析结果包括:设备制造商、设备型号、操作系统、操作系统版本、浏览器、浏览器版本、爬虫名称(如果是爬虫);
目前是神策是通过 UA 判断并有一个默认的属性 $bot_name (爬虫名称),对于爬虫种类,不能提前把所有的种类都加进去,主流的爬虫神策都已识别,但是有两种情况无法判断:- 第一种:如果 UA 里没有标明、且会触发 JS 脚本的非法爬虫
- 第二种:如果爬虫没有触发 JS 脚本,那么也不会触发 SDK 的事件采集,所以本身就不会被统计到
- $screen_width、$screen_height:屏幕的宽和高;
- product_id、product_name、product_classify、product_price:跟商品相关的一些具体属性。
1.2. 用户关联事件数据举例
这个数据是一个较为复杂的功能,请在使用前先阅读 标识用户,并在必要时联系我们的技术支持人员。
{
"distinct_id":"130xxxx1234",
"original_id":"0f485d4d12345e5f",
"login_id":"130xxxx1234",
"anonymous_id":"0f485d4d12345e5f",
"time": 1434557935000,
"type": "track_signup",
"event": "$SignUp",
"project": "ebiz_test",
"identities":{
"$identity_android_id":"0f485d4d12345e5f",
"$identity_login_id":"130xxxx1234"
},
"properties": {
"$manufacturer":"Apple",
"$model": "iPhone5,2",
"$os":"iOS",
"$os_version":"7.0",
"$app_version":"1.3",
"$wifi":true,
"$ip":"180.79.35.65",
"$province":"湖南",
"$city":"长沙",
"$screen_width":320,
"$screen_height":568
}
}
这条数据表示,一个 Android ID 为 0f485d4d12345e5f 的用户,成功完成了注册,注册后的注册 ID 是 130xxxx1234。并且系统后台,会将 Android ID 为 0f485d4d12345e5f 的用户和注册 ID 为 130xxxx1234 的用户,当做同一个用户对待。
需要注意的是,此数据结构中的 distinct_id 和 original_id 为必须字段,其中 disitnct_id 与 login_id 的值相同,original_id 与 anonymous_id 的值相同。
注意:若需要使用该事件,首先需要确认神策系统当前项目的用户关联策略为 全域用户关联,若使用简易用户关联策略,该数据会被整条拒绝。
{
"time":1622199005123,
"type":"track_id_bind",
"distinct_id":"3335654b922c4686",
"anonymous_id":"3335654b922c4686",
"identities":{
"$identity_android_id":"3335654b922c4686",
"$identity_email":"test@163.com"
},
"event":"$BindID",
"properties":{
"$app_name":"Test",
"$device_id":"3335654b922c4686",
"$model":"Redmi Note 4X",
"$os_version":"7.0",
"$app_version":"1.0",
"$wifi":true,
"$network_type":"WIFI",
"$lib_method":"code",
}
}
这条数据表示,将一个 Android ID 为 3335654b922c4686 和一个邮箱为 test@163.com 尝试进行关联,关联成功后,后续两个 ID 独立上报事件时,在神策系统中都会被当做同一个用户。
注意:若需要使用该事件,首先需要确认神策系统当前项目的用户关联策略为 全域用户关联,若使用简易用户关联策略,该数据会被整条拒绝。
{
"time":1622199169262,
"type":"track_id_unbind",
"distinct_id":"3335654b922c4686",
"anonymous_id":"3335654b922c4686",
"identities":{
"$identity_email":"test@163.com"
},
"event":"$UnbindID",
"properties":{
"$app_name":"test",
"$device_id":"3335654b922c4686",
"$model":"Redmi Note 4X",
"$os_version":"7.0",
"$app_version":"1.0",
"$wifi":true,
"$network_type":"WIFI",
"$lib_method":"code",
}
}
这条数据表示,将邮箱为 test@163.com 从系统已有用户中解除关联,解除关联成功后,神策系统中,将没有用户关联 test@163.com 邮箱。
1.3. 用户数据举例
更新用户数据的相关操作,主要是用来更新、删除用户的属性
直接设置一个用户属性,如果属性的字段已存在则覆盖,不存在则自动创建。
{
"distinct_id": "12345",
"login_id":"12345",
"anonymous_id":"0f485d4da1111fe5f",
"type": "profile_set",
"time": 1435290195610,
"project": "ebiz_test",
"identities":{
"$identity_android_id":"0f485d4da1111fe5f",
"$identity_login_id":"12345"
},
"properties": {
"$province":"湖南",
"FavoriteFruits": ["苹果","香蕉","芒果"],
"Age":33,
"$city":"长沙",
"IncomeLevel": "3000~5000",
"$name": "小明",
"Gender":"男",
"$signup_time": "2015-06-26 11:43:15.610"
}
}
与 profile_set 数据不同,如果对应的属性字段已存在,则这条记录会被忽略而不会覆盖已有数据,如果属性不存在则会自动创建。
因此,profile_set_once 比较适用于为用户设置首次激活时间、首次注册时间等只在首次设置时有效的属性。
{
"distinct_id": "12345",
"login_id":"12345",
"anonymous_id":"0f485d4da1111fe5f",
"type": "profile_set_once",
"time": 1435290195610,
"project": "ebiz_test",
"identities":{
"$identity_android_id":"0f485d4da1111fe5f",
"$identity_login_id":"12345"
},
"properties": {
"$province":"湖南",
"FavoriteFruits": ["苹果","香蕉","芒果"],
"Age":33,
"$city":"长沙",
"IncomeLevel": "3000~5000",
"$name": "小明",
"Gender":"男",
"$signup_time": "2015-06-26 11:43:15.610"
}
}
增加或减少一个用户的某个 NUMBER 类型的属性值,比如给用户属性 age 的值加 1 。
如果用户表( users 表)中不存在这个用户,则会在用户表中自动创建该用户的记录,并设置该用户相应的属性值,在默认值 0 的基础上增加上传数据中的值。
{
"distinct_id": "12345",
"login_id":"12345",
"anonymous_id":"0f485d4da1111fe5f",
"type": "profile_increment",
"time": 1435290200354,
"project": "ebiz_test",
"identities":{
"$identity_android_id":"0f485d4da1111fe5f",
"$identity_login_id":"12345"
},
"properties": {
"age": 1
}
}
向某个用户的某个数组类型的属性,追加一个或者多个值。如果本次上传的值,与系统中已存在的值有重复,默认是不会去重的。如果本次上传的值,有重复项,也不会去重的。
{
"distinct_id": "12345",
"login_id":"12345",
"anonymous_id":"0f485d4da1111fe5f",
"type": "profile_append",
"time": 1437280200354,
"project": "ebiz_test",
"identities":{
"$identity_android_id":"0f485d4da1111fe5f",
"$identity_login_id":"12345"
},
"properties": {
"FavoriteFruits": ["橘子","西瓜"]
}
}
将某个用户的某些属性值设置为空,在上传的数据中,属性的值请设置为非 null 的任何值,例如 true。
{
"distinct_id":"12345",
"login_id":"12345",
"anonymous_id":"0f485d4da1111fe5f",
"type":"profile_unset",
"time":1437280200354,
"project": "ebiz_test",
"identities":{
"$identity_android_id":"0f485d4da1111fe5f",
"$identity_login_id":"12345"
},
"properties":{
"Age":true,
"FavoriteFruits":true
}
}
删除一个用户的记录。
{
"distinct_id": "12345",
"login_id":"12345",
"anonymous_id":"0f485d4da1111fe5f",
"type": "profile_delete",
"time": 1437290200354,
"project": "ebiz_test",
"identities":{
"$identity_android_id":"0f485d4da1111fe5f",
"$identity_login_id":"12345"
},
"properties":{
}
}
1.4. 物品数据举例
物品表数据举例,主要是用来增加、删除、更新数据表的相关内容,数据举例如下
创建/更新物品表中的某一行记录,如果该记录已存在则覆盖,不存在则自动创建。
{
"type":"item_set",
"item_id":"12",
"item_type":"dub",
"project": "ebiz_test",
"properties":{
"title":"because of u",
"sub_title":"st",
"xxx":"xxx"
}
}
删除物品表中的某一行记录。
{
"type":"item_delete",
"item_id":"16",
"item_type":"dub",
"project": "ebiz_test"
}
对上述字段的解释如下:
- type:item_set 表明是创建/更新某一行记录,item_delete 表示删除某一行记录;
- item_id:表示物品的 id;
- item_type:表示物品的类型,区分不同的物品表。需是合法的变量名,即不能以数字开头,且只包含:大小写字母、数字、下划线和 $,且 item_type 字段长度最大为 100;
- 注意,物品表是使用 item_id 和 item_type 作为联合主键;
- project:这条数据所属项目名,若不指定该参数,则需要使用该字段时取值 default,即默认项目。指定的项目必须是系统中已经存在的项目,否则这条数据将无效,更多项目相关请参见 多项目;
- properties:上报的物品的具体属性,以 dict 的形式存在。属性名需要是合法的变量名,不能以数字开头,且只包含:大小写字母、数字、下划线;
1.5. 小结
数据中 type 字段表示一条数据的具体操作,是记录用户的一次行为、更新用户的属性、或者是创建一条物品记录。故每条数据中必须要有 type 字段,如果缺失该字段,则数据会被系统整条拒绝无法入库。
type 以及对应操作见下表:
type 类型 | 对应的操作 |
---|---|
track | 数据导入 events 表,一行记录表示一个事件 |
track_signup | 数据导入 events 表,同时 users 表中会记录事件对应登录 ID 和匿名 ID |
track_id_bind、track_id_unbind | 数据导入 events 表,同时 users 中会增加或删除对应的 ID |
profile_* | 数据导入 users 表,一行记录表示一个用户 |
item_* | 数据导入 items表,一行记录表示一个物品 |
2. 属性数据类型
2.1. 属性数据类型自动识别规则
当一个属性在系统中未预先定义,则属性首次导入时,系统会根据首次导入的值,决定该属性在系统中的数据类型。
JSON 中的类型 | 示例值 | 导入后系统识别的数据类型 | 该类型在系统中的相关限制 |
---|---|---|---|
Number | 12 或 12.0 | NUMBER(数值型) | -9E15 到 9E15 小数点后最多保留3位 |
Bool | true 或 false | BOOL(布尔值) | 无 |
String | "SensorsData" | STRING(字符串) | 使用 UTF-8 编码后最大长度 1024 字节,超出后系统会进行截断,保留前 1024 字节内容,并正常入库 |
List | ["橘子","西瓜"] | LIST(字符串数组) | 默认是字符串元素的数组(传入的字符串不会去重),最大元素个数为 500,其中每个元素使用 UTF-8 编码后最大长度 255 字节。 如果需要调整 List 具体是数组还是集合,请联系神策技术支持。若 append 导致超过最大元素个数时,新入库的元素会淘汰最早入库的元素。 |
String |
| DATETIME(日期时间) | 建议使用第一种,其中 SSS 为毫秒;年取值范围是 [1900, 2199]
|
2.2. 属性数据类型转化规则
当一个属性在系统中创建,其对应的数据类型就已经确定,后续导入数据时若类型和系统中记录的类型不符,则尝试对数据进行类型转换,若无法转换或转换失败则 该数据会被整条拒绝 。
尝试进行的类型转换如下(空格表示不进行转换):
原始类型→ 目标类型↓ | 数值型 | 布尔值 | 字符串 | 字符串集合 | 日期时间 |
---|---|---|---|---|---|
数值型 | true -> 1; false -> 0 | 空字符串 "" 抛弃该属性; 其他按数值解析 | |||
布尔值 | 0 -> false; 非 0 值 -> true | 字符串"true"、"false"转换为布尔类型 | |||
字符串 | 原值作为字符串 | 原值作为字符串 | 原值作为字符串,如 ["Hello","World"] | 原值作为字符串 | |
字符串集合 | |||||
日期时间 | 在一定区间内的按 UNIX 时间戳的秒或毫秒转换 | 多种日期时间格式模式串解析 |
- 上述表格左侧的列对应目标类型,上方的行对应原始类型。目标类型对应元数据中的数据类型,原始类型是数据上传时的属性值类型
- 什么时候该使用数值类型的属性:
- 需要进行聚合运算(例如求和、均值)或者按区间分组的值,典型的比如价格、时长、年龄等。
- 除非有特殊需求,否则各类 ID(例如订单 ID)不建议作为数值类型存储。
3. 导入数据的限制
3.1. 一般限制
- 事件变量名(event 的值)和 属性变量名(properties 中 key 取值)都需是合法的变量名,即不能以数字开头,且只包含:大小写字母、数字、下划线和 $,且事件变量名和属性变量名最大长度都为 100,自定义的事件名或者属性名不能以$ 开头;
- 变量名不能与系统中已经存在的虚拟事件、虚拟属性的变量名重复;
- 系统对变量名大小写处理有特殊要求,字母内容完全一致,但是大小写不一致的变量名会被拦截;
- 类型 type 字段的取值只能是上文列出几种(track, profile_* 等),并且大小写敏感;
- 属性 properties 字段必须存在,可以为空( {} );
- 自定义的事件或者属性的变量名不可以与系统保留字段重名,本节列出了保留字段。
3.2. 事件时间限制
导入不合理时间的用户事件将影响数据的准确性(如客户端时间错误导致导入未来的数据),故默认情况下对导入的事件时间进行了限制:
- 使用客户端 SDK (iOS、Android、Web、小程序等)导入的数据,服务端默认只接收事件发生时间在向前 10 天内和未来向后 1 小时内的数据(相比于系统当前时间);
- 使用后端语言 SDK (如 Java、Python 等)或导入工具(如 LogAgent 等),默认只能导入事件时间当前向前 2 年内和未来向后 1 小时内的数据;
注意:
- 如果希望导入上述默认时间窗口之外的数据,可以联系值班同学修改窗口限制,或在数据中添加 `time_free` 字段(见本文档事件数据样例)。
关于事件时间的修正机制:
- 因为 App 端只能使用客户端的时间作为事件发生的时间,如果客户端时间不准确,会导致采集端数据有异常,因此神策默认开启时间修正机制:App 端发生事件时的时间 time 的值为 t1,发送数据时的时间_flush_time 的值为 t2 (客户端时间,且 _flush_time 不入库),服务端接收到数据的时间 $receive_time 时间为 t3 (服务端时间),如果 t3 - t2 > 60s 或 t2 > t3,则认为客户端的时间不准确,会对事件触发时间进行修正,修正后事件时间 t1‘=t1+(t3-t2) 。
以下场景不会修正事件发生的时间:- 如果数据是延迟上报(比如数据在发送之前用户强杀 App,导致部分数据未及时发送,会先缓存在本地,待下次打开 App,网络正常时会重新尝试发送本地的缓存数据),发送数据时的 _flush_time 时间是准确的,也不会修复事件触发的时间。
3.3. 属性在不同表中的限制
对事件表的属性,一个属性,只能具有一种类型(不同的具体事件,同名属性类型也必须相同);
对用户表的属性,一个属性,只能具有一种类型;
对物品表的属性,一个属性,只能具有一种类型;
对于一个属性名,在事件表、用户表、物品表中可以具有不同的类型。
3.4. 属性长度限制
属性的数据类型,及特殊字段长度限制如下:
项目 | 限制 |
---|---|
数据类型 NUMBER | -9E15 到 9E15 小数点后最多保留3位 |
数据类型 STRING | 使用 UTF-8 编码后最大长度 1024 字节,超出后系统会进行截断,保留前 1024 字节内容,并正常入库 |
数据类型 LIST | 每个 LIST 中最多包含 500 个不大于 255 字节的字符串 |
用户标识($identity_login_id 等) | 最大长度 255 字节 |
distinct_id、original_id | 最大长度 255 字节 |
3.5. 属性数上限
单个项目 事件表 / 用户表 / 物品表 的属性建议合理设置,过多影响导入和查询性能,达到上限则会导致导入异常。
建议值 | 硬上限 |
---|---|
300 以内 | 2000 |
3.6. 保留字段
为了保证查询时属性名不与系统变量名冲突,设置如下保留字段,请避免其作为事件名和属性名(properties 中的 key)使用:
保留前缀 | 保留字段 | 额外保留字段 | ||
---|---|---|---|---|
事件表 | 用户表 | 物品表 | ||
|
|
|
|
|
注:本文档内容为神策产品使用和技术细节说明文档,不包含适销类条款;具体企业采购产品和技术服务内容,以商业采购合同为准。