# 数据模型

## 1. 数据模型简介

在神策分析中，我们使用“事件模型（Event 模型）”来描述用户在产品上的各种行为，这也是神策分析所有的接口和功能设计的核心依据。

简单来说，事件模型包括事件（Event）和用户（User）两个核心实体，在神策分析中，分别提供了接口供使用者上传和修改这两类相应的数据，在使用产品的各个功能时，这两类数据也可以分别或者贯通起来参与具体的分析和查询。对这两个概念，我们会在后文做具体的描述。

### 1.1 Event Model Vs. Page View

在传统的 Web 时代，通常使用 PV（Page View 的简写，也即页面访问量）来衡量和分析一个产品的好坏，然后，到了移动互联网以及 O2O 电商时代，PV 已经远远不能满足产品和运营人员的分析需求了。

在这个年代，每个产品都有着独一无二的核心指标用来衡量产品是否成功，这个指标可能是发帖数量、视频播放数量、订单量或者其它的可以体现产品核心价值的指标，这些都是一个简单的 PV 无法衡量的。

除此之外，PV 模型也无法满足一些更加细节的、更加精细化的分析。例如，我们想分析哪类产品销量最好，访问网站的用户的年龄和性别构成，每个渠道过来的用户的转化率、留存和重复购买率分别如何，新老用户的客单价、流水、补贴比例分别是多少等等。这些问题，都是以 PV 为核心的传统统计分析没办法解答的问题。

因此，神策分析采用事件模型作为基本的数据模型。事件模型可以给我们更多的信息，让我们知道用户用我们的产品具体做了什么事情。事件模型给予我们更全面且更具体的视野，指导我们做出更好的决策。

当然，采用神策分析的事件模型，依然是可以完成 PV 统计的，并且实现起来也很简单，使用 SDK 或者导入工具上传一个类似的接口即可：

```javascript
{
    "distinct_id": "2b0a6f51a3cd6775",
    "time": 1434556935000,
    "type": "track",
    "event": "PageView",
    "properties": { 
        "$ip" : "180.79.35.65",
        "user_gent" : "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.）",
        "page_name" : "网站首页",
        "url" : "www.demo.com",
        "referer" : "www.referer.com"
    }    
}
```

## 2. Event 实体

### 2.1 Event 的五要素

简单来说，一个 Event 就是描述了：一个用户在某个时间点、某个地方，以某种方式完成了某个具体的事情。从这可以看出，一个完整的 Event，包含如下的几个关键因素：

1. Who：即参与这个事件的用户是谁。在我们的数据接口中，使用 distinct\_id 来设置用户的唯一 ID：对于未登录用户，这个 ID 可以是 cookie、设备 ID 等匿名 ID；对于登录用户，则建议使用后台分配的实际用户 ID。同时，我们也提供了 track\_signup 这个接口，在用户注册的时候调用，用来将同一个用户注册之前的匿名 ID 和注册之后的实际 ID 贯通起来进行分析。
2. When：即这个事件发生的实际时间。在我们的数据接口中，使用 time 字段来记录精确到毫秒的事件发生时间。如果调用者不主动设置，则各个 SDK 会自动获取当前时间作为 time 字段的取值。
3. Where：即事件发生的地点。使用者可以设置 properties 中的 $ip 属性，这样系统会自动根据 ip 来解析相应的省份和城市，当然，使用者也可以根据应用的 GPS 定位结果，或者其它方式来获取地理位置信息，然后手动设置 $city 和 $province。除了 $city 和 $province 这两个预置字段以外，也可以自己设置一些其它地域相关的字段。例如，某个从事社区 O2O 的产品，可能需要关心每个小区的情况，则可以添加自定义字段“HousingEstate”；或者某个从事跨国业务的产品，需要关心不同国家的情况，则可以添加自定义字段“Country”。
4. How：即用户从事这个事件的方式。这个概念就比较广了，包括用户使用的设备、使用的浏览器、使用的 App 版本、操作系统版本、进入的渠道、跳转过来时的 referer 等，目前，神策分析预置了如下字段用来描述这类信息，使用者也可以根据自己的需要来增加相应的自定义字段。
   * `$app_version`：应用版本
   * `$city`： 城市
   * `$manufacturer`： 设备制造商，字符串类型，如"Apple"
   * `$model`： 设备型号，字符串类型，如"iphone6"
   * `$os`： 操作系统，字符串类型，如"iOS"
   * `$os_version`： 操作系统版本，字符串类型，如"8.1.1"
   * `$screen_height`： 屏幕高度，数字类型，如1920
   * `$screen_width`： 屏幕宽度，数字类型，如1080
   * `$wifi`： 是否 WIFI，BOOL类型，如true
5. What：描述用户所做的这个事件的具体内容。在我们的数据接口中，首先是使用“event”这个事件名称，来对用户所做的内容做初步的分类。event的划分和设计也有一定的指导原则，我们会在后文详细描述。除了“event”这个至关重要的字段以外，我们并没有设置太多预置字段，而是请使用者根据每个产品以及每个事件的实际情况和分析的需求，来进行具体的设置，下面给出一些典型的例子：
   * 对于一个“购买”类型的事件，则可能需要记录的字段有：商品名称、商品类型、购买数量、购买金额、 付款方式等；
   * 对于一个“搜索”类型的事件，则可能需要记录的字段有：搜索关键词、搜索类型等；
   * 对于一个“点击”类型的事件，则可能需要记录的字段有：点击 URL、点击 title、点击位置等；
   * 对于一个“用户注册”类型的事件，则可能需要记录的字段有：注册渠道、注册邀请码等；
   * 对于一个“用户投诉”类型的事件，则可能需要记录的字段有：投诉内容、投诉对象、投诉渠道、投诉方式等；
   * 对于一个“申请退货”类型的事件，则可能需要记录的字段有：退货金额、退货原因、退货方式等。

### 2.2 Event 的划分和字段设计原则

为了更好地使用神策分析提供的强大、便捷的分析功能，我们强烈建议使用者花费一定的时间，梳理自己的数据使用需求，并据此做好 Event 的划分和字段设计。

在 Event 的划分和设计过程中，神策分析团队也会提供相应的技术支持和服务，除此之外，我们将一些基本的原则也在这里整理出来，期望对使用者有所帮助。

#### 2.2.1 客户端埋点 Vs. 在后端记录 Event

友盟、百度统计等传统分析工具，都是在客户端嵌入 SDK 进行埋点，但是，我们强烈推荐**在后端记录 Event**，这是出于以下一些考虑：

1. 很多行为，如下单等，他们的很多字段在前端（App 和 Web 界面）是拿不到的。甚至有些行为，如用户线下消费等，前端根本就没有提供相应的功能，就更拿不到对应的数据。
2. 后端修改程序更加方便便捷，如果是在 App 端记录数据，则每次修改都需要等待 App 的发版和用户更新；
3. App 端收集数据会有丢失的风险，并且上传数据也不及时。App 端为了避免浪费用户的流量，一般情况下，都是将多条数据打包，并且等待网络状况良好以及应用处于前台时才压缩上传，因此，自然会造成上传数据不及时，很有可能某一天的数据会等待好几天才传到服务器端，这自然会导致每天的指标都计算有偏差。同时，由于 App 端可以缓存的内容有限，用户设备的网络连接等问题，App 端收集的数据目前也没有太好的手段保证100%不丢失。

基于以上几点考虑，**除非某个行为只在前端发生，对后端没有任何请求，否则，我们建议永远只在后端收集数据**。

#### 2.2.2 Event 的划分原则

对产品划分 Event，我们有如下的一些建议：

1. 为了节约使用成本，应该从需求出发，只记录那些会分析到的 Event，这一点是与传统的 PV 分析产品一个很大的不同。记录 Event 是为了详细地了解用户是如何使用产品的，对于暂时不会分析到的那些使用情况，可以暂时先不记录。
2. Event 的数量不应过多，对于一个典型的用户产品，Event 的数量以不超过20个为宜。当然，这个只是我们对事件设计的一些原则性的建议，系统本身并没有这方面的限制。一些类似的用户操作，可以合并成一个 Event。例如，假设某个产品比较关心对一系列商品分类页的访问情况，那么，并不意味着每个商品分类页点击就应该划分成一个单独的 Event，而是可以划分出一个单独的“商品分类页访问” Event，然后再将不同的分类以字段的形式进行记录。
3. Event 不仅局限于用户在 App、Web 界面等前端的操作和使用，一些其它类型的用户行为，例如用户的电话投诉、用户在线下接收服务、用户在线下商家进行消费等，如果能够获取到相应的数据，并且数据分析也会用到，则也可以作为相应的 Event。

#### 2.2.3 字段设计原则

为每个 Event 进行字段设计，我们有如下的一些建议：

1. 先根据需求梳理分析的指标和维度，然后再从指标和维度倒推需要在每个 Event 记录的字段。
2. 神策分析是一个数据分析工具，并不是一个日志存储和备份系统，所以，一些用不到的字段，例如 Cookie 的完整内容、后端请求返回码等，就没有必要作为一个 Event 的字段来进行记录和收集了。
3. 预置字段中已经有的字段，则建议尽量复用预置字段。对所有预置字段的说明，可以参看[数据格式](https://54td.gitbook.io/shence/technical_guide/data_import/data_schema)中的相应说明。
4. 某个 Event 的某个字段的设计一旦确定，则不要再修改它的类型和取值含义。例如，一开始对于"Buy"这个 Event，我们设计了一个数值类型的字段"Money"，描述这个购买行为对应的购买金额是多少元，然而后面我们期望把它改成分，那么我们建议不如废弃掉"Money"字段并且增加一个新的字段叫"MoneyByCents"，而不是去改变"Money"的含义。

## 3. User 实体

### 3.1 记录和收集 User Profile

每个 User 实体对应一个真实的用户，用 distinct\_id 进行标识，描述用户的长期属性（也即 Profile），并且通过 distinct\_id 与这个用户所从事的行为，也即 Event 进行关联。

神策分析提供了一系列 profile\_xxx 类型的接口，用来对某个 user 的 Profile 进行记录和修改。

一般记录 User Profile 的场所，是用户进行注册、完善个人资料、修改个人资料等几种有限的场合，与 Event 类似，我们也强烈建议**在后端记录和收集 User Profile**。

应该收集哪些字段作为 User Profile，也完全取决于产品形态以及分析需求。简单来说，就是在能够拿到的那些用户属性中，哪些对于分析有帮助，则作为 Profile 进行收集。

### 3.2 字段记录在 Profile 还是 Event 的取舍

有些时候，我们可能会纠结，某个与用户相关的字段是应该记录在 Profile 还是记录在 Event，一个基本的原则就是，**Profile 记录的是用户的基本固定不变的属性**，例如性别、出生年份（请注意，记录的不是年龄而是出生年份）、注册时间、注册地域、注册渠道等。而还有一些字段，例如用户级别、设备类型、地域、是否是 Vip 等，虽然也是用户相关的字段，但是可能是会经常变化的，则应该在用户的某个 Event 发生的时候，作为 Event 的一个字段来进行记录。

## 4. Item 实体

### 4.1 Item 的使用场景

在 Event-User 模型中，出于性能和可解释性等各方面的考虑，Event 是被设计为不可变的。从逻辑上看似乎没有问题，因为 Event 代表的是历史上已经发生过的事件，一般来说不应该需要进行更新。

但是，在实际的应用过程中，并不一定是这么理想的状态。

如，在采集和分析中会发现：

* Event实体中一些基本信息中会有许多是不断变化的
* 埋点采集中，发现某些 Event 在最初的阶段采集到的数据不完善。

这时，可通过 Item 实体对 Event-User 模型进行补充。

这里的所谓 Item，在严格意义上是指一个和用户行为相关联的实体，可能是一个商品、一个视频剧集、一部小说等等。

### 4.2 神策推荐系统中的 Item 应用

### 4.3 神策分析纬度表中的 Item 应用
