# 数据格式

神策分析支持多种不同语言的 SDK，这些 SDK 虽然在外部提供的接口上有所不同，但是在内部实现上都使用统一的数据格式，并且 [FormatImporter](https://54td.gitbook.io/shence/technical_guide/import_tool/format_importer) 、[LogAgent](https://54td.gitbook.io/shence/technical_guide/import_tool/log_agent) 、[BatchImporter](https://54td.gitbook.io/shence/technical_guide/import_tool/batch_importer) 和 [HDFSImporter](https://54td.gitbook.io/shence/technical_guide/import_tool/hdfs_importer) 都支持直接导入以文件形式存储的符合要求格式的数据，在这里，我们对数据格式进行一个更加细致的描述。

**注意：这里描述的是底层数据传输格式的定义，和具体 SDK 的调用接口无关**\
**注意：**[**$is\_login\_id 参数说明**](#81-isloginid-参数说明（布尔类型）)

## 1. 数据整体格式

日志文件是一行一个 JSON，物理上对应一条数据，逻辑上对应一个描述了用户行为的事件，或是描述一个或多个用户属性的 Profile 操作。

## 2. track：

记录一个 Event 及关联的 Properties。

数据样例：

```javascript
{
    "distinct_id": "123456",
    "time": 1434556935000,
    "type": "track",
    "event": "ViewProduct",
    "project": "ebiz_test",
    "time_free": true, //建议在导入历史数据时使用，SDK 采集的实时数据不建议使用
    "properties": {
        "$is_login_id":true,  //此参数请慎重使用，详细介绍请参考文档底部 8.1 $is_login_id 参数说明
        "$app_version":"1.3",
        "$wifi":true,
        "$ip":"180.79.35.65",
        "$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":640,
        "product_id":12345,
        "product_name":"苹果",
        "product_classify":"水果",
        "product_price":14.0
    }
}
```

对于上述字段的说明如下：

* distinct\_id：`类型是字符串`，对用户的标识，对未登录用户，可以填充设备标识、CookieID 等，对于登录用户，则应该填充注册账号；这里的例子，我们假设是一个未注册用户，所以填充的是一个设备编号；
* time：`类型是数值`，事件发生的实际时间戳，精确到毫秒；
* type：track 表明是记录一个 Event ，这里我们假设是一个商品浏览行为；
* event：事件名，需是合法的变量名，即不能以数字开头，且只包含：大小写字母、数字、下划线和 $,其中以 $ 开头的表明是系统的保留字段，自定义事件名请不要以 $ 开头；
* project：这条数据所属项目名，若不指定该参数，则需要使用该字段时取值 `default`，即默认项目。指定的项目必须是系统中已经存在的项目，否则这条数据将无效，更多项目相关请参见[多项目](https://54td.gitbook.io/shence/technical_guide/data_import/multi_project)；
* time\_free：可选字段，表示不根据事件发生时间过滤该事件。**只要出现 time\_free 这个 key 且 value 不为 null，将不再校验 time 是否在允许导入的时间范围内。**&#x5BFC;入历史数据时可能会用到该字段；
* properties：这个 Event 的具体属性，以 dict 的形式存在。其中**以$开头的表明是系统的保留字段，它的类型和中文名已经预先定义好了。自定义属性名需要是合法的变量名，不能以数字开头，且只包含：大小写字母、数字、下划线，自定义属性不能以 $ 开头；同一个名称的 property，在不同 event 中，必须保持一致的定义和类型；同一个名称的 property 大小写敏感，如果已经存在小写属性就不可再导入对应大写属性（比如元数据中有 abc 属性名，不能再传 ABC,Abc 等属性名），否则数据会校验失败不入库**。
  * $is\_login\_id：distinct\_id 对应的是否是一个注册 ID；
  * $app\_version：用户所使用的 App 的版本；
  * $wifi：这条事件发生时，用户是否在使用 wifi；
  * $ip：用户使用设备的 IP。若数据中出现 $ip，且数据中没有 $province 或 $city 字段，将使用该 IP 解析出省市信息填入缺失字段；
  * $province、$city：省、市，在没有填充这两个字段的时候，会根据 IP 进行解析；
  * $user\_agent：可选参数。如果传入该参数，则解析 User-Agent，解析结果包括：设备制造商、设备型号、操作系统、操作系统版本、浏览器、浏览器版本、爬虫名称（如果是爬虫）；
  * $screen\_width、$screen\_height：屏幕的宽和高；
  * product\_id、product\_name、product\_classify、product\_price：跟商品相关的一些具体属性。

## 3. track\_signup：

这个接口是一个较为复杂的功能，请在使用前先阅读[相关说明](http://www.sensorsdata.cn/manual/track_signup.html)，并在必要时联系我们的技术支持人员。

数据样例：

```javascript
{
    "distinct_id":"12345",
    "original_id":"2b0a6f51a3cd6775",
    "time": 1434557935000,
    "type": "track_signup",
    "event": "$SignUp",
    "project": "ebiz_test",
    "properties": {
        "$manufacturer":"Apple",
        "$model": "iPhone 5",
        "$os":"iOS",
        "$os_version":"7.0",
        "$app_version":"1.3",
        "$wifi":true,
        "$ip":"180.79.35.65",
        "$province":"湖南",
        "$city":"长沙",
        "$screen_width":320,
        "$screen_height":640
    }
}
```

这条数据表示，一个匿名 ID 为 2b0a6f51a3cd6775 的用户，成功完成了注册，注册后的注册 ID 是 12345。并且系统后台，会将 distinct\_id 为 2b0a6f51a3cd6775 的用户和 distinct\_id 为 12345 的用户，当做同一个用户对待。需要注意的是，此接口中的 original\_id 为必须字段，表示与注册 ID 进行关联的匿名 ID。

[FAQ: track\_signup 的作用是什么？](https://54td.gitbook.io/shence/import_tool/data_import_faq#12-tracksignup-的作用是什么？)

## 4. Profile 相关操作

Profile 相关操作，主要是用来设置用户的 Profile 的，提供了如下一系列接口：

### 4.1 profile\_set：

直接设置一个用户的 Profile，如果用户或者 Profile 的字段已存在，则覆盖，不存在则自动创建。

数据样例：

```javascript
{
    "distinct_id": "12345",
    "type": "profile_set",
    "time": 1435290195610,
    "project": "ebiz_test",
    "properties": {
        "$province":"湖南",
        "FavoriteFruits": [
            "苹果","香蕉","芒果"
        ],
        "Age":33,
        "$city":"长沙",
        "IncomeLevel": "3000~5000",
        "$name": "小明",
        "Gender":"男",
        "$signup_time": "2015-06-26 11:43:15.610"
    }
}
```

### 4.2 profile\_set\_once

直接设置一个用户的 Profile。与 profile\_set 接口不同的是，如果用户或者 Profile 的字段已存在，则这条记录会被忽略而不会覆盖已有数据，如果 Profile 不存在则会自动创建。因此，profile\_set\_once 比较适用于为用户设置首次激活时间、首次注册时间等只在首次设置时有效的属性。

数据样例：

```javascript
{
    "distinct_id": "12345",
    "type": "profile_set_once",
    "time": 1435290195610,
    "project": "ebiz_test",
    "properties": {
        "$province":"湖南",
        "FavoriteFruits": [
            "苹果","香蕉","芒果"
        ],
        "Age":33,
        "$city":"长沙",
        "IncomeLevel": "3000~5000",
        "$name": "小明",
        "Gender":"男",
        "$signup_time": "2015-06-26 11:43:15.610"
    }
}
```

### 4.3 profile\_increment：

增加或减少一个用户的某个 Numeric 类型的 Profile，如果用户不存在则自动创建, Profile 不存在则默认为 0。

数据样例：

```javascript
{
    "distinct_id": "12345",
    "type": "profile_increment",
    "time": 1435290200354,
    "project": "ebiz_test",
    "properties": {
        "Age": 1
    }
}
```

### 4.4 profile\_delete：

删除一个用户的整个 Profile。

数据样例：

```javascript
{
    "distinct_id": "12345",
    "type": "profile_delete",
    "time": 1437290200354,
    "project": "ebiz_test",
    "properties":{
    }
}
```

### 4.5 profile\_append：

向某个用户的某个数组类型的 Profile 添加一个或者多个值。

数据样例：

```javascript
{
    "distinct_id": "12345",
    "type": "profile_append",
    "time": 1437280200354,
    "project": "ebiz_test",
    "properties": {
        "FavoriteFruits": [
            "橘子","西瓜"
        ]
    }
}
```

### 4.6 profile\_unset：

将某个用户的某些属性值设置为空。另外，为了与其它接口保持一致，在提交的数据上，属性的值请设置为非 null 的任何值，例如 true。

数据样例：

```javascript
{
    "distinct_id":"12345",
    "type":"profile_unset",
    "time":1437280200354,
    "project": "ebiz_test",
    "properties":{
        "Age":true,
        "FavoriteFruits":true
    }
}
```

## 5. Item 相关操作

Item 相关操作，主要是用来设置 Item 的具体内容，提供了如下一系列接口：

### 5.1 item\_set：

直接设置一个 Item，如果 Item 的字段已存在，则覆盖，不存在则自动创建。

数据样例：

```javascript
{
  "type":"item_set",
  "item_id":"12",
  "item_type":"dub",
  "project": "ebiz_test",
  "properties":{
    "title":"because of u",
    "sub_title":"st",
    "xxx":"xxx"
  }
}
```

### 5.2 item\_delete：

删除整个 Item 内容。

数据样例：

```javascript
{
  "type":"item_delete",
  "item_id":"16",
  "item_type":"dub"
  "project": "ebiz_test",
}
```

## 6. 属性数据类型

### 6.1 注意问题

* 发送端使用 JSON 作为数据传输格式，本系统以 JSON 数据类型为基础再加以额外限制，定义了若干种数据类型，但 **不与 JSON 类型完全等价**，详见后文属性类型说明。
* (table\_name, property\_name) 二元组唯一确定一个属性，table\_name 为数据表的表名，如 users、events，可在自定义 SQL 查询中看到。这意味着同表同名属性类型必须相同，而不同表的同名属性类型可以不同。消息类型与所写入的数据表的关系如下表：

| 消息类型          | 目标数据表                                               |
| ------------- | --------------------------------------------------- |
| track         | events                                              |
| profile\_\*   | users                                               |
| track\_signup | 事件信息被写入 events 表，users 表中会记录 first\_id 和 second\_id |

* **一个属性的类型由首次导入时的类型决定**，后续导入时若类型不符，则尝试对数据进行类型转换，若无法转换或转换失败则**输入数据会被整条拒绝**。尝试进行的类型转换如下（空格不进行转换）：

| 目标类型\原始类型 | 数值型                       | 布尔值                   | 字符串                      | 字符串集合   | 日期时间    |
| --------- | ------------------------- | --------------------- | ------------------------ | ------- | ------- |
| 数值型       |                           | true -> 1; false -> 0 | 空字符串 "" 抛弃该属性; 其他按数值解析   |         |         |
| 布尔值       | 0 -> false; 非 0 值 -> true |                       | 字符串"true"、"false"转换为布尔类型 |         |         |
| 字符串       | 原值作为字符串                   | 原值作为字符串               |                          | 原值作为字符串 | 原值作为字符串 |
| 字符串集合     |                           |                       |                          |         |         |
| 日期时间      | 在一定区间内的按 UNIX 时间戳的秒或毫秒转换  |                       | 多种日期时间格式模式串解析            |         |         |

* 什么时候该使用数值类型的属性：
  * 需要进行聚合运算（例如求和、均值）或者按区间分组的值，典型的比如价格、时长、年龄等。
  * 除非有特殊需求，否则各类 ID（例如订单 ID）不建议作为数值类型存储。

### 6.2 神策分析属性数据类型定义

| 神策分析数据类型            | 中文名   | 基础 JSON 类型 | 额外限制                                                                                                                                | 示例                                                                          | 说明                                                                                |
| ------------------- | ----- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
| NUMBER              | 数值型   | number     | -9E15 到 9E15 小数点后最多保留3位                                                                                                             | 12 或 12.0                                                                   |                                                                                   |
| BOOL                | 布尔值   | bool       | 无                                                                                                                                   | true 或 false                                                                |                                                                                   |
| STRING              | 字符串   | string     | 使用 UTF-8 编码后最大长度 1024 字节，如需调整最大长度可以联系我们                                                                                             | "SensorsData"                                                               |                                                                                   |
| LIST                | 字符串数组 | list       | 字符串元素的数组，最大元素个数为 500，其中每个元素使用 UTF-8 编码后最大长度 255 字节；注意：1.12 之前的版本，在入库时会进行重排序和去重，1.12 及之后的版本默认保留原始数据的顺序。超过最大元素个数时，新入库的元素会淘汰最早入库的元素。   |                                                                             |                                                                                   |
| DATETIME            | 日期时间  | string     | <p>yyyy-MM-dd HH:mm:ss.SSS 或<br> yyyy-MM-dd HH:mm:ss 或<br> yyyy-mm-dd （时分秒按00:00:00处理）， 建议使用第一种，其中 SSS 为毫秒；年取值范围是 \[1900, 2099]</p> | <p>"2015-06-19 17:51:21.234"<br> "2015-06-19 17:51:21"<br> "2015-06-19"</p> | 有些语言的时间格式化库不直接提供毫秒格式化，如 Python 提供 us 而不提供 ms，如需自行编写程序生成数据请注意这点。                   |
| DATE （仅 <= 1.10 版本） | 日期    | string     | 格式为 yyyy-mm-dd，年取值范围是 \[1900, 2099]                                                                                                 | "2015-06-19"                                                                | 自 1.11 版本起，DATE 类型将作为 DATETIME 的一种格式存在（既时分秒为 00:00:00 的 DATETIME，且时分秒可省略），不再单设类型。 |

## 7. 预置属性

为了帮助使用者更方便地使用我们的产品，我们目前分别为 Event 和 Profile 提供了一些预置字段。

***注意:*** JavaScript SDK 预置属性较多，这里没有全部列出，详细说明请参考相关文档 [《JavaScript SDK》](https://github.com/hxxiaolong/wendang/tree/32bdd85c96b118df803b5923753b4f1908489069/js_sdk.html#62-%E9%A2%84%E7%BD%AE%E5%B1%9E%E6%80%A7) ***注意:*** 微信小程序 SDK 特有属性较多，这里没有全部列出，详细说明请参考相关文档[《微信小程序 SDK》](https://github.com/hxxiaolong/wendang/tree/32bdd85c96b118df803b5923753b4f1908489069/mp_sdk.html#6-%E9%A2%84%E7%BD%AE%E5%B1%9E%E6%80%A7)

Event 的预置字段有：

| 字段名称                           | 类型   | 说明                  | JS SDK 自动采集 | iOS SDK 自动采集 | Android SDK 自动采集 | 小程序 SDK 自动采集 | 服务端 SDK 自动采集 |
| ------------------------------ | ---- | ------------------- | :---------: | :----------: | :--------------: | :----------: | :----------: |
| $app\_version                  | 字符串  | 应用的版本               |      N      |       Y      |         Y        |       N      |       N      |
| $country                       | 字符串  | 国家                  |      Y      |       Y      |         Y        |       Y      |       N      |
| $city                          | 字符串  | 城市                  |      Y      |       Y      |         Y        |       Y      |       N      |
| $province                      | 字符串  | 省份                  |      Y      |       Y      |         Y        |       Y      |       N      |
| $lib                           | 字符串  | SDK类型，例如python、iOS等 |      Y      |       Y      |         Y        |       Y      |       Y      |
| $lib\_version                  | 字符串  | SDK版本               |      Y      |       Y      |         Y        |       Y      |       Y      |
| $manufacturer                  | 字符串  | 设备制造商，例如Apple       |      Y      |       Y      |         Y        |       N      |       N      |
| $model                         | 字符串  | 设备型号，例如iphone 8,4   |      Y      |       Y      |         Y        |       Y      |       N      |
| $os                            | 字符串  | 操作系统，例如iOS          |      Y      |       Y      |         Y        |       Y      |       N      |
| $os\_version                   | 字符串  | 操作系统版本，例如8.1.1      |      Y      |       Y      |         Y        |       Y      |       N      |
| $screen\_height                | 数值   | 屏幕高度，例如1920         |      Y      |       Y      |         Y        |       Y      |       N      |
| $screen\_width                 | 数值   | 屏幕宽度，例如1080         |      Y      |       Y      |         Y        |       Y      |       N      |
| $wifi                          | BOOL | 是否使用wifi，例如true     |      N      |       Y      |         Y        |       N      |       N      |
| $browser                       | 字符串  | 浏览器名，例如Chrome       |      Y      |       N      |         N        |       N      |       N      |
| $browser\_version              | 字符串  | 浏览器版本，例如Chrome 45   |      Y      |       N      |         N        |       N      |       N      |
| $carrier                       | 字符串  | 运营商名称，例如ChinaNet    |      N      |       Y      |         Y        |       N      |       N      |
| $network\_type                 | 字符串  | 网络类型，例如4G           |      N      |       Y      |         Y        |       Y      |       N      |
| $utm\_matching\_type           | 字符串  | 渠道追踪匹配模式            |      N      |      Y1      |        Y1        |       N      |       N      |
| $latest\_referrer              | 字符串  | 站外前向地址              |      Y      |       N      |         N        |       N      |       N      |
| $latest\_referrer\_host        | 字符串  | 站外前向域名              |      Y      |       N      |         N        |       N      |       N      |
| $latest\_utm\_source           | 字符串  | 最近广告系列来源            |      Y      |       N      |         N        |      Y5      |       N      |
| $latest\_utm\_medium           | 字符串  | 最近广告系列媒介            |      Y      |       N      |         N        |      Y5      |       N      |
| $latest\_utm\_term             | 字符串  | 最近广告系列字词            |      Y      |       N      |         N        |      Y5      |       N      |
| $latest\_utm\_content          | 字符串  | 最近广告系列内容            |      Y      |       N      |         N        |      Y5      |       N      |
| $latest\_utm\_campaign         | 字符串  | 最近广告系列名称            |      Y      |       N      |         N        |      Y5      |       N      |
| $latest\_search\_keyword       | 字符串  | 最近一次搜索引擎关键词         |      Y      |       N      |         N        |       N      |       N      |
| $latest\_traffic\_source\_type | 字符串  | 最近一次流量来源类型          |      Y      |       N      |         N        |       N      |       N      |
| $is\_first\_day                | 布尔值  | 是否首日访问              |      Y      |       Y      |         Y        |       Y      |       N      |
| $device\_id                    | 字符串  | 设备ID                |      Y6     |       Y      |         Y        |       N      |       N      |

Profile 的预置字段有：

| 字段名称                          | 类型       | 说明               | JS SDK 自动采集 | iOS SDK 自动采集 | Android SDK 自动采集 | 小程序 SDK 自动采集 | 服务端 SDK 自动采集 |
| ----------------------------- | -------- | ---------------- | :---------: | :----------: | :--------------: | :----------: | :----------: |
| $city                         | 字符串      | 用户所在的城市          |      N      |       N      |         N        |       N      |       N      |
| $province                     | 字符串      | 用户所在的省份          |      N      |       N      |         N        |       N      |       N      |
| $name                         | 字符串      | 用户名              |      N      |       N      |         N        |       N      |       N      |
| $signup\_time                 | Datetime | 注册时间             |      N      |       N      |         N        |       N      |       N      |
| $utm\_matching\_type          | 字符串      | 渠道追踪匹配模式         |      N      |      Y1      |        Y1        |       N      |       N      |
| $first\_visit\_time           | Datetime | 首次访问时间           |      Y3     |      Y4      |        Y4        |       N      |       N      |
| $first\_referrer              | 字符串      | 首次前向地址           |      Y3     |       N      |         N        |       N      |       N      |
| $first\_referrer\_host        | 字符串      | 首次前向域名           |      Y3     |       N      |         N        |       N      |       N      |
| $first\_browser\_language     | 字符串      | 首次使用的浏览器语言       |      Y3     |       N      |         N        |       N      |       N      |
| $first\_browser\_charset      | 字符串      | 首次浏览器字符类型（1.8支持） |      Y3     |       N      |         N        |       N      |       N      |
| $first\_search\_keyword       | 字符串      | 首次搜索引擎关键词（1.8支持） |      Y3     |       N      |         N        |       N      |       N      |
| $first\_traffic\_source\_type | 字符串      | 首次流量来源类型（1.8支持）  |      Y3     |       N      |         N        |       N      |       N      |
| $utm\_source                  | 字符串      | 首次广告系列来源         |      Y2     |      Y1      |        Y1        |       Y      |       N      |
| $utm\_medium                  | 字符串      | 首次广告系列媒介         |      Y2     |      Y1      |        Y1        |       Y      |       N      |
| $utm\_term                    | 字符串      | 首次广告系列字词         |      Y2     |      Y1      |        Y1        |       Y      |       N      |
| $utm\_content                 | 字符串      | 首次广告系列内容         |      Y2     |      Y1      |        Y1        |       Y      |       N      |
| $utm\_campaign                | 字符串      | 首次广告系列名称         |      Y2     |      Y1      |        Y1        |       Y      |       N      |

Item 的预置字段有：

| 字段名称           | 类型  | 说明          | JS SDK 自动采集 | iOS SDK 自动采集 | Android SDK 自动采集 | 小程序 SDK 自动采集 | 服务端 SDK 自动采集 |
| -------------- | --- | ----------- | :---------: | :----------: | :--------------: | :----------: | :----------: |
| $is\_valid     | 布尔值 | 该 item 是否有效 |      N      |       N      |         N        |       N      |       N      |
| $receive\_time | 数值型 | 该 item 到达时间 |      N      |       N      |         N        |       N      |       N      |

备注:

* 1: `$utm_` 开头的相关属性，由 App 渠道追踪功能自动采集，请参考相关文档 [《App 渠道追踪》](https://54td.gitbook.io/shence/technical_guide/track_installation)。
* 2: 新用户首次访问时，需要开启 autoTrack 且URL中带有UTM参数，才会收集，请参考相关文档 [《JavaScript SDK》](https://github.com/hxxiaolong/wendang/tree/32bdd85c96b118df803b5923753b4f1908489069/js_sdk.html)。
* 3: 新用户首次访问时，开启 autoTrack才会收集，请参考相关文档 [《JavaScript SDK》](https://github.com/hxxiaolong/wendang/tree/32bdd85c96b118df803b5923753b4f1908489069/js_sdk.html)。
* 4: 新用户首次启动App，如果调用了trackInstallation接口会自动给这个属性赋值。
* 5: 小程序sdk1.3版本支持
* 6: 如果sdk初始化时候配置了is\_track\_device\_id:true,就会采集

### 7.1 预置属性采集方式

* iOS 中，预置属性的采集方式大致如下：

```objectivec
  NSMutableDictionary *p = [NSMutableDictionary dictionary];
  UIDevice *device = [UIDevice currentDevice];
  NSString *deviceModel = [self deviceModel];
  struct CGSize size = [UIScreen mainScreen].bounds.size;
  CTCarrier *carrier = [[[CTTelephonyNetworkInfo alloc] init] subscriberCellularProvider];
  // Use setValue semantics to avoid adding keys where value can be nil.
  [p setValue:[[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] forKey:@"$app_version"];
  [p setValue:carrier.carrierName forKey:@"$carrier"];
  [p addEntriesFromDictionary:@{
                                @"$lib": @"iOS",
                                @"$lib_version": [self libVersion],
                                @"$manufacturer": @"Apple",
                                @"$os": [device systemName],
                                @"$os_version": [device systemVersion],
                                @"$model": deviceModel,
                                @"$screen_height": @((NSInteger)size.height),
                                @"$screen_width": @((NSInteger)size.width),
                                    }];
```

* Android 中，预置属性的采集方式大致如下：

```java
  {
    deviceInfo.put("$lib", "Android");
    deviceInfo.put("$lib_version", VERSION);
    deviceInfo.put("$os", "Android");
    deviceInfo.put("$os_version",
        Build.VERSION.RELEASE == null ? "UNKNOWN" : Build.VERSION.RELEASE);
    deviceInfo
        .put("$manufacturer", Build.MANUFACTURER == null ? "UNKNOWN" : Build.MANUFACTURER);
    deviceInfo.put("$model", Build.MODEL == null ? "UNKNOWN" : Build.MODEL);
    try {
      final PackageManager manager = mContext.getPackageManager();
      final PackageInfo info = manager.getPackageInfo(mContext.getPackageName(), 0);
      deviceInfo.put("$app_version", info.versionName);
    } catch (final PackageManager.NameNotFoundException e) {
      Log.e(LOGTAG, "Exception getting app version name", e);
    }
    final DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
    deviceInfo.put("$screen_height", displayMetrics.heightPixels);
    deviceInfo.put("$screen_width", displayMetrics.widthPixels);

    TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService(Context
        .TELEPHONY_SERVICE);
    String operatorString = telephonyManager.getSimOperator();

    if (operatorString == null) {
      // DO NOTHING
    } else if (operatorString.equals("46000") || operatorString.equals("46002")) {
      deviceInfo.put("$carrier", "中国移动");
    } else if (operatorString.equals("46001")) {
      deviceInfo.put("$carrier", "中国联通");
    } else if (operatorString.equals("46003")) {
      deviceInfo.put("$carrier", "中国电信");
    } else {
      deviceInfo.put("$carrier", "其他");
    }
  }
```

## 8. 限制

### 8.1 一般限制

1. 事件名（event 的值）和 属性名（properties 中 key 取值）都需是合法的变量名，即不能以数字开头，且只包含：大小写字母、数字、下划线和$；
2. 类型 type 字段的取值只能是上文列出几种（track, profile\_set 等），并且大小写敏感；
3. 属性 properties 字段必须存在，可以为空（ {} ）；
4. 事件 time 字段允许的范围是 1000000000000(2001-09-09 09:46:40) \~ 10000000000000(2286-11-21 01:46:40);
5. 本节 7.6 列出了保留属性名；

### 8.2 事件时间限制

导入不合理时间的用户事件将影响数据的准确性（如客户端时间错误导致导入未来的数据），故默认情况下对导入的事件时间进行了限制：

1. 使用客户端 SDK （iOS、Android）导入的数据，服务端默认只接收事件发生时间在接收时间向前 10 天内和未来向后 1 小时内的数据；
2. 使用后端语言 SDK （如 Java、Python 等）或导入工具（如 LogAgent、BatchImporter、HdfsImporter），默认只能导入事件时间当前向前 2 年内和未来向后 1 小时内的数据；

如果希望导入上述默认时间窗口之外的数据，可以联系值班同学修改窗口限制，或在数据中添加 `time_free` 字段（见本文档 2. track 样例）。

### 8.3 同名属性同类型

* 对 Event 属性，一个属性名，只能具有一种类型（不同的具体事件，同名属性类型也必须相同）；
* 对 Profile 属性，一个属性名，只能具有一种类型；
* 对于一个属性名，在 Event 和 Profile 中可以具有不同的类型；

### 8.4 属性长度限制

属性的数据类型，及特殊字段长度限制如下：

| 项目              | 限制                                |
| --------------- | --------------------------------- |
| 数据类型 NUMBER     | -9E15 到 9E15 小数点后最多保留3位           |
| 数据类型 STRING     | 最大长度 1024 字节                      |
| 数据类型 LIST       | 每个 LIST 中最多包含 500 个不大于 255 字节的字符串 |
| 用户 distinct\_id | 最大长度 255 字节                       |
| 用户 original\_id | 最大长度 255 字节                       |

### 8.5 属性数上限

Event / Profile 的属性建议合理设置，过多影响导入和查询性能，达到上限则导致导入异常。

| 建议值    | 硬上限  |
| ------ | ---- |
| 300 以内 | 2000 |

### 8.6 保留属性名

为了保证查询时属性名不与系统变量名冲突，设置如下保留属性名，请避免其作为属性名(properties 中的 key)使用：

```
date
datetime
distinct_id
event
events
first_id
id
original_id
device_id
properties
second_id
time
user_id
users
```

## 9. 常见问题

### 9.1 $is\_login\_id 参数说明（布尔类型）

常见使用场景：历史数据导入的 [events](https://www.sensorsdata.cn/manual/data_schema.html#2-track%EF%BC%9A) 或者 [users](https://www.sensorsdata.cn/manual/data_schema.html#41-profileset%EF%BC%9A) 数据，服务端 SDK 的 [track](https://www.sensorsdata.cn/manual/java_sdk.html#3-%E8%BF%BD%E8%B8%AA%E4%BA%8B%E4%BB%B6) 或 [profile](https://www.sensorsdata.cn/manual/java_sdk.html#5-%E8%AE%BE%E7%BD%AE%E7%94%A8%E6%88%B7%E5%B1%9E%E6%80%A7) 接口。

属性值含义：true ，表示这条数据中的 distinct\_id 字段的值为一个真实的 ID（例如客户的业务 ID），如果在这条数据进入数据库之前，此真实 ID 未和设备 ID 绑定，（绑定操作，前端可参考 login 方法，[以 JavaScript SDK 为例](https://www.sensorsdata.cn/manual/js_sdk.html#21-%E5%9C%A8%E7%99%BB%E5%BD%95%E5%92%8C%E6%B3%A8%E5%86%8C%E6%88%90%E5%8A%9F%E5%90%8E%EF%BC%8C%E8%B0%83%E7%94%A8sensorsloginuserid-%E6%9D%A5%E6%A0%87%E8%AF%86%E7%9C%9F%E5%AE%9E%E7%94%A8%E6%88%B7)。服务端可参考 tracksignup 方法，[以 Java SDK 为例](https://www.sensorsdata.cn/manual/java_sdk.html#41-%E7%94%A8%E6%88%B7%E6%B3%A8%E5%86%8C%E7%99%BB%E5%BD%95)，历史数据导入可参考本文档的 [tracksignup](https://www.sensorsdata.cn/manual/data_schema.html#3-tracksignup%EF%BC%9A) 接口。），那么这个真实 ID 会自关联，导致之后不能再和设备 ID 绑定。\
属性值含义：false，表示这条数据中的 distinct\_id 字段的值为一个设备 ID（即客户注册登录之前的标识用户的 ID），之后此设备 ID 还可以和一个真实 ID 绑定。
