You are on page 1of 370

用 画像:方 论与工程化解决方

宏田 著
ISBN:978-7-111-63564-2

本 版由机 工 出版社 2019年出版,电子版由华章分社(北


华章 文 有限公司,北 奥 博 行有限公司)全球范
内制 与 行。

版权 有, 权 究

客服 :+ 86-10-68995265

客服 :service@bbbvip.com

官方 :www.hzmedia.com.cn

新 博 @华章数媒

公 号 华章电子 ( 号:hzebook)

前言
1章 用 画像 础
1.1 用 画像是 么
1.1.1 画像 介
1.1.2 
1.2 数据
1.3 主要覆盖
1.4 开 阶 程
1.4.1 开 上 程
1.4.2  阶 关 出
1.5 画像应用的落
1.6  用 画像
1.6.1  景介
1.6.2 相关元数据
1.6.3 画像表 设计
1.7 定 画像
1.8 本章小
2章 数据
2.1 用 属 度
2.1.1 常见用 属
2.1.2 用 别
2.2 用 行为 度
2.3 用 消费 度
2.4 风险控制 度
2.5 社 属 度
2.6 其 常见 划分方
2.7  命名方
2.8 本章小
3章  数据存储
3.1 Hive存储
3.1.1 Hive数据 库
3.1.2 分区存储
3.1.3 
3.1.4 ID-MAP
3.2 MySQL存储
3.2.1 元数据 理
3.2.2 监控预警数据
3.2.3  集存储
3.3 HBase存储
3.3.1 HBase 介
3.3.2 应用 景
3.3.3 工程化
3.4 Elasticsearch存储
3.4.1 Elasticsearch 介
3.4.2 应用 景
3.4.3 工程化
3.5 本章小
4章  数据开
4.1  计 开
4.1.1 近30日购 行为
4.1.2 最近来访
4.2 规则 开
4.2.1 用 价
4.2.2 用 度
4.3  掘 开
4.3.1  景
4.3.2 特征 取及开
4.3.3 文本分词 理
4.3.4 数据 理
4.3.5 文本TF-IDF权重
4.3.6 朴 贝 斯分
4.4  计 开
4.4.1  建
4.4.2 Kafka 介
4.4.3 Spark Streaming集成Kafka
4.4.4  开 及工程化
4.5 用 特征库开
4.5.1 特征库规划
4.5.2 数据开
4.5.3 其 特征库规划
4.6  权重计
4.6.1 TF-IDF词空
4.6.2 时 衰减 数
4.6.3  权重
4.7  相 度计
4.7.1  景
4.7.2 数据开
4.8 组 计
4.8.1 应用 景
4.8.2 数据计
4.9 数据服务层开
4.9.1 推送至营
4.9.2 接 调用服务
4.10 GraphX 计 用
4.10.1  计 理论及应用 景
4.10.2 数据开
4.11 本章小
5章 开 调
5.1 数据 斜调
5.2  并小文件
5.3  存 数据
5.4 开 表
5.5 本章小
6章  程调度
6.1 crontab命令调度
6.2 Airflow工 平台
6.2.1  础
6.2.2 Airflow服务 成
6.2.3 Airflow安装
6.2.4 主要 功
6.2.5 工 调度
6.2.6  本实
6.2.7 常用命令行
6.2.8 工程化调度方
6.3 数据监控预警
6.3.1  监控预警
6.3.2 服务层预警
6.4 ETL 常排
6.5 本章小
7章 用 画像 化
7.1 即时 询
7.2  视 与 询
7.3 元数据 理
7.4 用 分 功
7.5  分 功
7.6 本章小
8章 用 画像应用
8.1  营分
8.1.1  分
8.1.2 用 分
8.1.3  分
8.1.4  斗分
8.1.5 客服话术
8.1.6  特征分
8.2  准营
8.2.1 短 / 件营
8.2.2 效 分
8.3  化推荐与服务
8.4 本章小
9章 实 详解
9.1 风控 诈预警
9.1.1 应用 景
9.1.2 用 画像切入
9.2 A/B 效 试
9.2.1  景
9.2.2 用 画像切入
9.2.3 效 分
9.3 用 生命 期划分与营
9.3.1 生命 期划分
9.3.2 不同阶 的用 触 略
9.3.3 画像 生命 期 的应用
9.3.4 应用
9.4 高价 用 实时营
9.4.1 项目应用 景
9.4.2 用 画像切入
9.4.3 HBase应用 景小
9.5 短 营 用
9.5.1  景
9.5.2 画像切入及其应用效
9.6 Session行为分 应用
9.6.1 关 用 行为分
9.6.2  景
9.6.3 特征 建
9.6.4 分 方 与 论
9.7  效 监 报表搭建
9.7.1  景
9.7.2  理
9.7.3  动报表 件
9.8  用 特征库 目
9.8.1  景
9.8.2 应用方 及效
9.9 本章小
附   用 画像项目规划文
前言
为 么写这本

我曾 知 “数据智 ”专 下面不定期 关 用 画像的文


章,也曾 知 开设 几期live直播,还曾 智 课平台开
设 列 课“用 画像解决方 ”。 同行 对画像 兴 的
朋友 时,我 现 家虽 来 、 草、零 、互 不
同行 , 公司对用 画像领 有建设需 , 且 家对
、 效率(ETL)、 监控、实时计 、画像 化、
务应用 景 应用方 方面 有进一步 解的兴 。 以我 对
这 年 用 画像的 验、 的“ ”进行 理 ,为数据开
、数据分 、运营、用 研究 岗位的工 提 一 参 。

写这 解决方 的一 晚,我有时 ,科 时代
飞速 展,如 有一 我不 这一行 ,该 么来 年 斗
的时光 ?2019年,我 3次从0到1开始搭建用 画像 ,从离
开 、用 数据分 、ETL调度、 计 开 ,到 数据服务
层、应用画像数据服务 务方、获 务 的 馈,这一
来, 程是痛 的,收获是 富的。 斗的日子 , 望一步
步 的 ,谨以此 不 昼 前的日子致敬。

本 特

开始 用 画像的时 我也不知 从 下 ,市面上介


Hive、Spark、HBase、MySQL、数据 库 数据相关 术的
, 是介 用 画像搭建开 的 少,甚至 有。 有相关
项目 验的 况下,我不知 如 这 数据组件 来搭建用
画像 。直到这两年,我 一 开 画像 ,一 理,
最终 成本 。

本 助数据 库实现一套用 画像 的方 。从实际工程


出 , 务 景,内容 盖开 离 理计 的 及
计 ,为读 的分 、开 、搭建用 画像 ,并 助该用
画像 为运营 制定运营用 的 略提 端到端的解决方 。
一套好的解决方 需要包 以下几 层面。

1) 层: 画像 的 层,本 首先介 画像数据 库


的 ,进一步介 数据存储的 术 , 么 景下 用
Hive、MySQL、HBase、Elasticsearch 工具存储数据,用 开
、 计 开 相应数据开 层面的内容,以及整 项目的开
程 阶 的关 出。

2) 层:介 整 方 是如 运 来的。本 主要涉及画像


的 程调度、数据 库 务 的 。

3) 务层:包 的前后端 互以及如 这套 应用


务服务层面。本 用 画像 化介 端 画像
的“代码”层面是如 进行 互操 的。

4)方 价 :包 上 后如 服务 务 景 生 务价
以及有待进一步完 的 方。

以上几 层面的内容 成 一套完整的用 画像解决方 ,这也


是本 章 覆盖的全 。

数据的最终目的是 出数据 库,应用到 务 营


来驱动营收 。

我 学习数据 库的时 学 Kimball的《数据 库工具 》,其


关 数据 库的34 子 的介 对我 ,其对 如 解决
特定 题并 成 化 有着 的方 论与解决方 。虽 面对
具 题的 理方 是 且 富 样的, 是 定的 化 有
利 速 到突破 , 成 好的开端。

本 可以帮助读 用 画像领 成一种 化 , 面对


一 具 项目时不 无从下 。如 建立 ?
包 ?如 设计存储画像 的表 ?如 开 ?画
像 涉及 数据存储工具?如 数据到服务层?如
对画像 进行监控?如 对整 画像 进行调度?如 画像
服务 务 景来驱动 ?这 是画像 的子 。
主要章 及内容

本 共9章, 章具 内容如下:

1章:主要讲用 画像的 础知识,包 搭建用 画像 需要


覆盖的 ,开 阶 程, 阶 的关 出,以及数据 库
、表 的设计 内容。 读本章可以帮助读 成 建用 画像
的一 整 化 。

2章: 务设定 ,本章 对 景,从常用的用


属 、行为、消费、风险控制这4 度设定 。本章提 的
可 盖 分刻画用 画像的应用 景,对 具 应用 ,读
可根据公司 务特 进行 对 的补充。

3章:讲解 相关数据的存储,包 Hive存储、MySQL存


储、HBase存储 Elasticsearch存储。不同的存储方 适用 不同的
景 务需要。

4章:也是本 的重 章 , 介 的 数据及相关 本的
开 是用 画像 建工 的重 。本章讲解 对常见的 计 、规则
、 掘 、 计 以及用 特征库 与用 相关的数据的
开 ,还进一步介 如 计 数据、 数据到服务层 的
开 。 GraphX 计 用 2度关 熟 的 介 如 度 掘
用 的关 关 。本章对 一小 进行 详细的讲解,并附有
套的代码计 程。

5章:讲解 开 程 常见的数据 斜调 、对小文件的读


取、 存 数据、开 表 调 工 。

6章:讲解 如 用开 ETL工具Airflow实现画像 相关
务的工程化上 调度,以及对数据的监控预警 调度 常的排 。

7章:画像 化是数据从数据 库 务服务的重要环 ,


画像 化可 务 用工具来分 用 ,将 务上定义的用
应用到 务 提 服务。本章为数据 、 务
提 解决方 的 。
8章:介 用 画像的应用 景,包 营分 、 准营 、
化推荐 应用方 ,方 务 、 理、数据分 师更好
解用 、触 用 。

9章: 景化介 用 画像实际应用的8 , 展


现 用 画像 为一种分 、触 用 的工具 实际 务上的应用方
应用 程。

主要读 对象

· 理:由 岗位 质对 术不是特别熟 ,可重 关


1、2、7、8、9章的内容。

·数据分 师:可以从 度对用 及用 进行分 ,可重


关 1、2、3、7、8、9章的内容。

·运营 :可重 关 2、8、9章的内容, 解画像 涉及


的 、应用 景及应用 略。

·数据开 :本 主要站 数据开 的角度对整 画像


进行 化介 。数据开 可完整 读本 章的内容。

·市 : 助画像 解用 的特征以及运营用
的 略方 ,可重 关 2、8、9章的内容。

勘误 支持

由 平有限, 难免 存 疏 , 请读 评 正。
为此,读 可 (892798505@qq.com)
(administer00001) 馈有关 题,我将尽全力为读 进行解 。

致谢

谢父 对我一 成 的支持。 谢机 工 出版社华章公司的


杨福川 师 李 师,这是我 二次与两位 师 , 次 与
是 么 ; 谢为本 写推荐的朋友 , 的专 建议让
本 更加 。最后, 谢 去一年 己的 一分 入,不断积
,将 数据 用 画像领 的工程化实现 应用方 成 。
1章 用 画像 础

1.1 用 画像是 么
互 步入 数据时代后,用 行为给 的 服务带来
一 列的改变 重 ,其 最 的变化 ,用 的一切行为
面前是可“ ”“分 ”的。 内 存 的原始数据
种 务数据,这是 营 动的真实记 ,如 更加有效 利用这
数据进行分 评 ,成为 更 数据 景的 题 。
随着 数据 术的 入研究与应用, 的关 日益 如 利
用 数据来为 细化运营 准营 服务, 要 细化运营,首先
要建立本 的用 画像。
1.1.1 画像 介
用 画像,即用 化, 收集用 的社 属 、消费
习 、 好特征 度的数据,进 对用 特征属 进
行刻画,并对这 特征进行分 、 计, 掘 价 ,从
象出用 的 全貌,如 1-1 示。用 画像可看 应用 数据
的根 ,是定 广 放与 化推荐的前 条件,为数据驱动运营
奠定 础。由此看来,如 从 数据 掘出有价 的 越
重要。

1-1  用 化

数据已 兴 年,其对 互 公司的应用来说已 如 、


电、空 对 的生 一样,成为不可 的重要组成 分。从
础设施建设到应用层面,主要有数据平台搭建及运 理、数据 库
开 、上层应用的 计分 、报表生成及可视化、用 画像建 、
化推荐与 准营 应用方 。

公司 数据 础建设上 入 ,也 不少报表,
务 觉 数据 报表 么区别,也 数据对 务
有 么帮助 价 ,究其原 ,其实是“数据静止 数据 库,是
的”。
用 画像可以帮助 数据“ 出”数据 库, 对用 进行
化推荐、 准营 、 化服务 样化服务,是 数据落 应用
的一 重要方 。数据应用 的层 划分如 1-2 示。

1-2 数据应用 的层 划分
1.1.2 
用 画像建 其实就是对用 “ ”,从对用 的方
来看,一 分为3种 (如 1-3 示):① 计 ;②规则
;③机 学习 掘 。

1-3 

下面我 介 这3种 的 的区别:

1. 计

这 是最为 础也最为常见的 , 如,对 用


来说,其 别、年龄、 市、星座、近7日 时 、近7日
数、近7日 次数 字 可以从用 册数据、用 访 、消费数据
计 出。该 成 用 画像的 础。

2.规则

该 用
行为及确定的规则 生。 如,对平台上“消
费 ”用 这一 径的定义为“近30 易次数≥2”。 实际开
画像的 程 ,由 运营 对 务更为熟 , 数据 对数据的
、分布、特征更为熟 , 此规则 的规则由运营 数
据 共同协 确定;

3.机 学习 掘

该 机 学习 掘 生,用 对用 的 属
行为进行预 判断。 如,根据一 用 的行为习 判断该用 是男
还是女 、根据一 用 的消费习 判断其对 的 好程度。
该 需要 掘 生。
项目工程实 ,一 计 规则 的 即可以 应用
需 , 开 占有 比 。机 学习 掘 用 预
景,如判断用 别、用 购 好、用 。一
,机 学习 开 期 ,开 成本 高, 此其开 占比
小。

更多书籍访问:www.j9p.com
1.2 数据
整 工程化方 , 赖的 础设施包 Spark、Hive、
HBase、Airflow、MySQL、Redis、Elasticsearch。除去 础设施 ,
主 还包 Spark Streaming、ETL、 端3 重要组成 分。
1-4 示是用 画像数 ,下面对其进行详细介 。

1-4 用 画像数

1-4下方虚 为常见的数据 库ETL加工 程,也就是将


日的 务数据、日 数据、 数据 ETL 程,加工到数据 库
对应的ODS层、DW层、DM层 。

的虚 即为用 画像建 的主要环 ,用 画像不是 生


数据的 , 是对 数据 库ODS层、DW层、DM层 与用 相关数
据的二次建 加工。 ETL 程 将用 计 写入Hive,由
不同数据库有不同的应用 景,后 需要进一步将数据同步到MySQL、
HBase、Elasticsearch 数据库 。
·Hive:存储用 计 、用 计 、用 特征
库计 。

·MySQL:存储 元数据,监控相关数据,导出到 务 的数
据。

·HBase:存储 上接 实时调用 数据。

·Elasticserch:支持 数据的实时 询分 ,用 存储用


计 、用 视分 需的用 数据(由 用 计
、用 视分 的条件 化成的SQL语句 条件嵌套 为 杂,
用Impala 行也需 费 时 )。

用 数据 Hive 加工完成后, 分 Sqoop同步到


MySQL数据库,提 用 BI报表展示的数据、 视分 数据、
服务数据;另一 分 同步到HBase数据库用 的 上 化推
荐。
1.3 主要覆盖
搭建一套用 画像方 整 来说需要 虑8 的建设,如 1-
5 示。

·用 画像 础:需要 解、明确用 画像是 么,包


,数据 库 是 么样子,开 程,表 设计,ETL设计 。
这 是 , 方 的规划, 有明确 方 后 好项目的
排期 入预 。这对 评 开 阶 重要 关 出
非常重要,重 可看1.4 。

·数据 :根据 务 理,包 用 属 、用 行为、


用 消费、风险控制 度的 。

· 数据存储: 相关数据可存储 Hive、MySQL、HBase、


Elasticsearch 数据库 ,不同存储方 适用 不同的应用 景。

· 数据开 :用 画像工程化的重 ,包 计 、规
则 、 掘 、 计 的开 ,以及 计 功 的开 ,
画像数据 务 的 ,提 接 服务 开 内容。
1-5 用 画像主要覆盖

·开 调 : 加工、 计 本上 调度后,为
短调度时 、 障数据的稳定 ,需要对开 的 本进行 代重
、调 。

· 程调度: 加工、 计 、同步数据到 务 、


数据监控预警 本开 完成后,需要调度工具 整套 程调度
来。本 讲解 Airflow这 开 ETL工具 调度画像相关 务 本上
的应用。

·用 画像 化:为 让用 数据更好 服务 务方,需


要以 化的 应用 务上。 化的 主要包 视 、
用 询、用 分 、 视分 。

·用 画像应用:画像的应用 景包 用 特征分 、短 、
件、站内 、Push消 的 准推送、客服 对用 的不同话术、 对
高价 用 的 速退货退 VIP服务应用。

本 内容安排也分别 这8 的内容来展开。方 读 更
解用 画像是如 从0到1搭建 来并提 服务、驱动用 实
现营收 的。
1.4 开 阶 程
本 主要介 画像 开 上 的 程以及 阶 的关 出。
1.4.1 开 上 程
用 画像建设项目 程,如 1-6 示。

1-6 用 画像建设项目 程

一阶 :目 解读

建立用 画像前,首先需要明确用 画像服务 的对象,


再根据 务方需 ,明确未来 建设目 用 画像分 后的预
期效 。

一 言,用 画像的服务对象包 运营 数据分 。


不同 务方对用 画像的需 有不同的 重 ,就运营 来说,
需要分 用 的特征、定位用 行为 好, 内容的 化
推送以提高 击 化率, 以画像的 重 就落 用 行为
好上;就数据分 来说, 需要分 用 行为特征, 好用
的 预警工 ,还可根据用 的消费 好 更有 对 的 准营

二阶 : 务分解与需 调研

一阶 的需 调研 目 解读,我 已 明确 用 画像
的服务对象与应用 景,接下来需要 对服务对象的需 重 ,
现有 务 “数据字典”规 实 的关 关
,明确分 度。就后文将要介 的 言,需要从用 属 画
像、用 行为画像、用 好画像、用 好画像 角度去进行
务建 。

三阶 :需 景讨论与明确

本阶 ,数据运营 需要根据与需 方的 , 出
用 画像需 文 , 该文 明确画像应用 景、最终开 出的
内容与应用方 ,并就该文 与需 方 并确认无误。

阶 :应用 景与数据 径确认

三 阶 明确 需 景与最终实现的 度、
后,数据运营 需要 务与数据 库 已有的相关表,明确
与 务 景相关的数据 径。 该阶 ,数据运营方需要 出
用 画像开 文 ,该文 需要明确应用 景、 开 的 、
涉及的数据库与表以及应用实施 程。该文 不需要再与运营方讨
论, 需面 数据运营 内 就开 实施 程 成一致 见即可。

阶 :特征 取与 数据落表

本阶 数据分 掘 需要根据前面明确的需 景进行


务建 ,写好HQL ,将相应的 写入 时表 ,并 取数据
验是 务 景需 。

六阶 : 下 数据验收与 试

数据 库 的 将相关数据落表后,设 定时调度 务,定


期 更新数据。数据运营 需要验收数 加工的HQL 是
需 ,根据 务需 取表 数据 看其是 理范 内,如
现 题要及时 馈给数据 库 调整代码 行为权重的数 。

七阶 : 上 布与效

六阶 ,数据 验收 后, Git进行版本 理,
上 。 用Git进行版本 理,上 后 持 应用效 及
务方 馈,调整 化 及相关权重 。
1.4.2  阶 关 出
为 证程序上 的准时 稳定 ,需要规划好 阶 的 务排
期 关 出。画像 的开 分为几 主要阶 ,包 前期
理、用 开 、ETL调度开 、 数据服务层、画像 端
开 、面 务方推广应用、为 务方提 营 略的解决方 ,
如表1-1 示。

表1-1 用 画像项目 阶 关 出
· 开 :根据 务需 应用 景 理 ,调研
务上定义的数据 径,确认数据来 ,开 相应的 。 开
整 画像项目 期 占有 比重。

·ETL调度开 : 理需要调度的 务 的 赖关 ,开 调
度 本及调度监控 警 本,上 调度 。

· 服务层接 :为 让画像数据 出数据 库,应用到用


上,需要 数据 库 务 的接 。

·画像 化:需要 理与 务 、术开 一 对


接 务需 功 实现 ,画 原 ,确定工 排期。
Java Web端开 完成后,需要数据开 对应的库表 入数
据。

·开 调 : 画像的数据 端搭建好 、 提 稳定服


务的 础上,为 让调度 务 行 来更加高效、提 服务更加稳
,需要对 计 本、调度 本、数据同步 本 相关计 务
进行重 化。

·面 务方推广应用:用 画像最终的价 出 是 务方应


用画像数据进行用 分 , 触 运营用 ,分 ROI,提升用
度 营收。 此,面 务 推广画像 的 用方 、提
对具 务 景的解决方 显 尤为重要。 该阶 ,相关 需
要撰写画像的 用文 ,提 务支持。
1.5 画像应用的落
用 画像最终的价 还是要落 运行,为 务带来实际价 。这
里需要开 的数据工程师 需 方相互协 ,将 应用到 务
。 则开 完 后,数据还是 留 数据 库 , 有为 务
决 带来积 用。

画像开 程 ,还需要开 组织数据分 、运营、客服


的 进行画像应用上的推广。对 数据分 来说,可
关 用 画像开 表、 字 以及字 的 径定义;对运
营、客服 务 来说,可 更关 用 定义的 径,如
Web端 用画像 进行分 、 定用 进行定 营 ,以及应用
务上数据的准确 及时 。

有 务 日常工 真正应用画像数据、画像 ,
更好 推动画像 的 代 化,带来 提升 营收 , 出
价 。
1.6  用 画像
这里 一 贯穿本 的实 来将 家更好 带入实际开
画像、应用画像 的 景 。本 主要介 景及相关的元数
据,以及开 可以设计的表 样 。

本 的开 工 , Spark计 擎,主要涉及的语言包
HiveQL、Python、Scala、Shell 。
1.6.1  景介
电 站 有 千万的 购用 ,
100 万种。用 平台上可进行 览、搜 、收藏、下单、购 行
为。 的运营需要解决两 题:一方面 、
资 的 景下,如 兼顾 目 的同时更好
消费 的需 ,为用 带来更 化的购物 验, 内容的 准推
荐,更好 提高用 的 击 化率;另一方面 用 规 不断 的
景下,运营方 虑建立用 预警机制,及时识别将要 的用
, 取运营措施挽 用 。

建立以来,数据 库 积 着 的 务数据、日 数据
及 数据。如 充分 掘 数据 库 的数据的价 ,有效支
持用 画像的建设,成为当前的重要工 。
1.6.2 相关元数据
本 ,可以获取的数据 其 分为: 务 数据 用
行为数据。其 务 数据是 用 平台上下单、购 、收藏物
、货物 送 与 务相关的数据;用 行为数据是 用 搜 条
、访 页面、 击 、提 表单 操 行为
生( 解 日 的 表 )的数据。

涉及数据 库 的表主要包 用 表、 订单表、


表、 目表、App端日 表、Web端日 表、 评论表 。下
面就用 画像建 程 用到的一 数据表 详细介 。

1.用 表

用 表(见表1-2)存放有关用 的 种 ,如用 姓名、


年龄、 别、电话号码、归属 。

表1-2 用 表(dim.user_basic_info)

2. 订单表
订单表(见表1-3)存放 订单的 ,包 订单
号、用 id、用 姓名、订单生成时 、订单状 。

表1-3  订单表(dw.order_info_fact)

3. 日 表

日 表(见表1-4)存放用 访 App时 击相关控件的


记 。 客 端 ,从日 数据 解 出来。

表1-4  日 表(ods.page_event_log)
4.访 日 表

访 日 表(见表1-5)存放用 访 App的相关 及用 的LBS


相关 , 客 端 ,从日 数据 解 出来。

表1-5 访 日 表(ods.page_view_log)

5. 评论表

评论表(见表1-6)存放用 对 的评论 。

表1-6  评论表(dw.book_comment)
6.搜 日 表

搜 日 表(见表1-7)存放用 App端搜 相关的日 数据。

表1-7 搜 日 表(dw.app_search_log)

7.用 收藏表

用 收藏表(见表1-8)记 用 收藏 的数据。

8.购物 表

购物 表(见表1-9)记 用 将 加入购物 的数据。

表1-8 用 收藏表(dw.book_collection_df)
表1-9 购物 表(dw.shopping_cart_df)
1.6.3 画像表 设计
表 设计也是画像开 程 需要解决的一 重要 题。

表 设计的重 是要 虑存储 、如 存储(数据分


区)、如 应用(如 取 )这3 方面的 题。

不同 务 景有不同的设计方 ,这里提 两种设计 :一是


日全 数据的表 ;二是 日 数据的表 。

Hive需要对 入进行全盘 描来 询条件, 用分区可


以 化 询。对 用 这种日加工数据,随着时 的推移,分区
数 的变动也是 匀的。

日全 数据,即该表的日期分区 记 着 止到当 的全 用
数据。 如,“select count(*)from userprofile where
data='20180701'”这条语句 询的是userprofile表 止到2018年7月
1日的全 用 数据。日全 数据的 势是方 询, 是不 探
更细 度的用 行为。

日 数据,即该表的日期分区 记 着当日的用 行为数


据。 如,同样是“select count(*)from userprofile where
data='20180701'”,这条语句 询的是userprofile表 2018年7月1
日记 的当日用 行为数据。日 数据可视为ODS层的用 行为画
像, 应用时还需要 该 数据 进一步的建 加工。

下面详细介 这两种表 的设计方 。

1.日全 数据

日全 数据表 , 对应的日期分区 插入 止到当 为止


的全 数据,用 进行 询时, 需 询最近一 的数据即可获 最
新全 数据。下面以一 具 的日全 表 的 子来进行说明。

CREATE TABLE `dw.userprofile_attritube_all `(


`userid` string COMMENT 'userid',
`labelweight` string COMMENT ' 权重',)
COMMENT 'userid 用 画像数据'
PARTITIONED BY ( `data_date` string COMMENT '数据日期', `theme` string COMMENT '二
主题', `labelid` string COMMENT ' id')

这里userid表示用 id,labelweight表示 权重,theme表示


归属的二 主题,labelid表示一 id。 “日期+ 归
属的二 主题+ id”的方 进行分区,设 三 分区字 更 开
询数据。该表 下的 权重 虑 计 的权重,
如:历 购 额 对应的权重为 额数 ,用 近30日访 数
为对应的 数,该权重 的计 未 虑 为 杂的用 行为次数、行
为 、行为 今时 杂 况。

表名末尾 加“_all”的规范化命名 ,可直观看出这是


一 日全 表。

如,对 主题 为“ ”的 ,插入“20190101”日的
全 数据,可 语句:insert overwrite table
dw.userprofile_userlabel_all
partition(data_date='20190101',theme='member',
labelid='ATTRITUBE_U_05_001')来实现。 询 止
到“20190101”日的被 上 的用 ,可 语句:select
count(distinct userid)from dw.userprofile_userlabel_all
where data_date='20190101'来实现。具 的开 程 4.1 详细
讲解。

2.日 数据

日 数据表,即 的日期分区 插入当 务运行 生的


数据,用 进行 询时 限制 询的日期范 ,就可以 出 特定
时 范 内被 上特定 的用 。下面以一 具 的日 表
的 子来说明。

CREATE TABLE dw.userprofile_act_feature_append (


labelid STRING COMMENT ' id',
cookieid STRING COMMENT '用 id',
act_cnt int COMMENT '行为次数',
tag_type_id int COMMENT ' 码',
act_type_id int COMMENT '行为 码')
comment '用 画像-用 行为 表'
PARTITIONED BY (data_date STRING COMMENT '数据日期')
这里,labelid表示 名称;cookieid表示用 id;act_cnt表
示用 当日行为次数,如用 当日 览 三 3次,则 上次
数为3;tag_type_id为 ,如 婴、3C、数码 不同 ;
act_type_id表示行为 ,如 览、搜 、收藏、下单 行为。分区
方 为 日期分区,插入当日数据。

表名末尾 加“_append”的规范化命名 ,可直观看出这


是一 日 表。

如, 用 “20180701”日 览 3C电子 4次
(act_cnt),即给该用 (userid) 上 对应的三
(tagid), (tag_type_id)为3C电子 ,行为
(act_type_id)为 览。这里可以 对 行为 两 字
度表的方 ,对数据进行 理。 如对 行为
(act_type_id)字 ,可以设定1为购 行为、2为 览行为、3为收
藏行为 , 行为 表 以数 定义用 行为 , 度表
护 数 对应的具 义。

该日 数据表可视为ODS层用 行为 明细。 询 程 ,
如对 用 id为001的用 , 询其 “20180701”日
到“20180707”日被 上的 ,可 命令:select*from
dw.userprofile_act_feature_append where userid='001'and
data_date>='20180701'and data_date<='20180707' 询。

该日 的表 记 用 的行为带来的 , 未计
用 上 的权重,计 权重时还需 进一步建 加工。
权重 详见4.6 的内容。

3.关 宽表设计

用 画像表 如 设计, 有一定要 的 定的 ,


务需要、 应用即可。下面 两 宽表设计的 ,提 另
一种解决方 的 。

用 属 宽表设计(见表1-10),主要记 用 本属 。
表1-10 用 属 宽表设计
用 日 宽表设计(见表1-11),主要记 用 访 的

表1-11 用 日 宽表设计
1.7 定 画像
本 重 讲解如 运用 数据定 刻画用 画像, 对 用
的刻画除 定 度 ,定 刻画也是常见 。定 画像 见
用 研究 运营 岗位, 电话调研、 络调研 卷、当面 入访
谈、 上 三方权威数据 方 收集用 ,帮助其理解用 。这
种定 调研相比 数据定 刻画用 来说,可以更 确 解用
需 行为特征, 这 样本 是有限的, 出的 论也不一定 代
表 分用 的观 。

制定调研 卷表,我 可以收集用 本 以及设 一


景,专访用 络 收调研 卷, 分 卷数据后获取
用 的画像特征。目前市 上“ 卷星” 三方 卷调 平台可提
用 卷设计、 接 放、 集数据 、调研 分 一
列功 ,如 1-7 示。
1-7  调研 卷示 ( “ 卷星”)

根据 收的调研 卷,可 计数据进一步分 用 画像特征


(如 1-8 示)。
1-8  收的调研 卷( “ 卷星”)
1.8 本章小
本章主要介 用 画像的一 础知识,包 画像的 介、
、整 画像 的数据 ,开 画像 主要覆盖的8
,以及开 程 的 阶 关 出。初步介 画像 的轮廓
貌,帮助读 对 如 设计画像 、开 期、画像的应用方
有宏观的初步的 解。本 后面的章 将 1.3 画像 覆盖
的8 次展开。
2章 数据
数据 是建立用 画像的关 环 ,也是 开 前要
进行的工 ,具 来说就是需要 的 务 况设定相关的

互 相关 建立用 画像时一 除 用 度
(userid)建立一套用 ,还 用 用设 度
(cookieid)建立相应的 。 cookieid 度的 应用也
容易理解,当用 有登 账 访 设 时,也可以 用
设 上的行为对该设 推送相关的广 、 服务。

建立的用 可以分为 计 、规则 机 学习


掘 ,相关内容 1.1.2 有详细介 。从建立的 度来看,
可以将其分为用 属 、用 行为 、用 消费 风险控制
常见 。

下面详细介 用 的 成及应用 景。
2.1 用 属 度

2.1.1 常见用 属
用 属 是刻画用 的 础。常见用 属 包 :用 的年
龄、 别、安装时 、 册状 、 市、省 、 登 、历 购
状 、历 购 额 。

用 属 度的 建成后可以提 客服电话服务,为运营
解用 本 况提 帮助。

用 属 包 计 、规则 、机 学习 掘 。
计 的开 为 单,机 学习 掘 将 4.3 具
进行讲解。本 主要介 常见用 属 主要包 的 度。表
2-1给出 常用的用 属 度 。

表2-1 用 属 度 示
表2-1对 相同的一 ,需要判断 的关 为
互斥关 还是非互斥关 。 如, 判断 别时,用 别为男的
况下就不 同时为女, 以 为互斥关 ; 判断用 是
黑名单内时,用 既可 短 黑名单 ,也可 同时 件黑名单
, 以这种就为非互斥关 。

对 根据数 进行 计、分 的 开 相对容易。 如,用


的“ 别”“年龄”“ 市”“历 购 额” 确定 的 。
对规则 的 进行开 前则首先需要进行数据调研。 如,对
用 价 度划分(RFM),如 确定一 用 是重要价 用 还是一
价 用 ,对 用 度的划分如 确定是高 、 、低
还是已 ,需要 数据调研 况给出科学的规则并进行划
分。 4.2 ,将 两 介 规则 如 开 。
2.1.2 用 别
用 别可细分为 别 购物 别两种。

别是 用 的实际 别,一 可 用 册 、 写
调 卷表单 径获 。该 需要从相应的表 取数据即
可,加工 来 为方 。

用 购物 别是 用 购 物 时的 别取 。 如,一位实际
别为男 的用 ,可 常给妻子购 女 的衣物、包 ,
么这位用 的购物 别则是女 。
2.2 用 行为 度
用 行为是另一种刻画用 的常见 度, 用 行为可以 掘
其 好 特征。常见用 行为 度 (见表2-2)包 :用 订单相
关行为、下单/访 行为、用 近30 行为 、用 高频 时
、用 购 、 击 好、营 敏 度 相关行为。

表2-2 用 行为 度 示
2.3 用 消费 度
对 用 消费 度 的建设,可从用 览、加购、下
单、收藏、搜 对应的 入 , 越细越 确,给用 推荐
营 的准确 越高。如 2-1 示,根据用 相关行为对应
建设 ,本 确到 三 。

表2-3为用 消费 度的 设计。
2-1 用 消费 度 理
表2-3 用 消费 度 示
这里 一 景来介 建用 消费 度的 的应用。 女
装 动期 , 运营 需要 出平台上的 质用 ,并
短 、 件、Push 进行营 ,可以 “ 览”“收
藏”“加购”“购 ”“搜 ”与该女装相关 ”的 来 出
可 对该女装 兴 的 用 ,进一步组 其 (如“
别”“消费 额”“ 度” ) 出对应的高质 用 ,推送
到对应 。 此将 象成 后,可 +行为的组
应用方 到目 用 。
2.4 风险控制 度
互 的用 可 到薅 、 刷单、 贷 诈 行
为的用 ,为 防止这 用 给平台带来损 风险,互 公司需
要 风险控制 度 建 相关的 ,有效监控平台的不 用
。 公司 务方 , 如可从账号风险、设 风险、 贷风险
度入 建风控 度 。下面详细介 一 常见的风险控制
度的 示 ,如表2-4 示。

表2-4 风险控制 度 示
2.5 社 属 度
社 属 用 解用 的家庭成 、社 关 、社 好、社
程度 方面, 这 可以更好 为用 提 化服务。
表2-5是常用的社 属 度 示 。

表2-5 社 属 度 示

日常 用社 软件时,我 可以 现社 软件 的 广
我 的社 特征进行 化推送。如 2-2 示, 我
市、 常 及近期收藏的电 相关文章, 朋友 给我推
送 相关电 营 的广 。如 2-3 示, 我的星座 年龄
,推送 我 特征的婚庆摄 广 。
2-2 朋友 广 – 位 ( )

2-3 朋友 广 – 星座( )
2.6 其 常见 划分方
本章前5 从用 属 、用 行为、用 消费、风险控制、社 属
共 度划分归 用 。 对用 的归
并不局限 此, 应用 景对 进行归 也是常见的 划分
方 。 2-4展示 具 的画像 应用 景划分。

从 务 景的角度出 ,可以将用 归为用 属 、用


行为、营 景、 细分、 好细分、用 分层 度。
度可细分出二 、三 。

·用 属 :包 用 的年龄、 别、设 号、安装/ 册状


、 刻画用 静 特征的属 。

·用 行为:包 用 的消费行为、购 后行为、近N日的访 、


收藏、下单、购 、 后 相关行为。
2-4 画像 应用 景划分

· 好细分:用 对 、 价 、 营 、购
的 好 、不同营 方 方面的 好特征;

·风险控制:对用 从征 风险、 用设 的风险、 平台消费


程 生的 题 度 其风险程度;

· 务专用:应用 种 务上的 ,如A/B 试 、Push


·营 景:以 景化进行分 ,根据 务需要 建一 列营


景, 用 的 需 ,如差 化客服、 景用 、再营 用

· 细分: 识用 的常住 市、居住 、工


,应用 用 理位 进行推荐的 景 ;

·用 分层:对用 生命 期、RFM、消费 平 、 度
进行分层划分。

本 提 一种从 务 景的角度出 对 进行归 的解


决方 。为读 建 提 另 一种参 度。
2.7  命名方
为 对诸 进行集 理,需要对 对应的
id进行命名。 如,对 别为“男”的用 上
“ATTRITUBE_U_ol_001”, 别为“女”的用 上
“ATTRITUBE_U_01_002”。下面我 详细介 如 建立 这套
命名方 。

对 一 ,可以从 主题、刻画 度、 、一 归
角度入 来确定 的 一名称,如 2-5 示。

2-5 用 命名 度

· 主题:用 刻画属 种 的 ,如 属 、行为


属 、用 消费、风险控制 种 ,可分别用ATTRITUBE、
ACTION、CONSUME、RISKMANAGE 单词表示 主题。

·用 度:用 刻画该 是 用 一 识(userid)


上,还是 用 用的设 (cookieid)上。可用U、C 字 分别
识userid cookieid 度。

· : 可划分为 计 、规则 。其 计
开 可直接从数据 库 主题表建 加工 成,规则 需要
公司 务 数据 况, 开 需要对数据 机 学习的 理
到相应的 。

·一 度: 主题 下面,进一步细分 度来刻画
用 。
参照上面的命名 度 命名方 ,下面 几 子来讲 如
命名 。

对 用 的 别 , 主题是 属 ,用 度为
userid, 属 。给男 用 上
“ATTRITUBE_U_01_001”,给女 用 上
“ATTRITUBE_U_01_002”,其 “ATTRITUBE”为 属 主
题,“_”后面的”U”为userid 度,“_”后面“01”为一 归 ,
最后面的“001” “002”为该一 下的 明细,如 是划分
高 低 用 的,对应一 下的明细可划分
为“001”“002”“003”。

一命名后, 护一 码表记 id名称、 义及


径 主要 ,后期方 元数据的 护 理。本 介 的
命名方 可 为开 程 的一种参 方 。
2.8 本章小
本章主要介 如 务 景去搭建刻画用 的数据
。其 2.1 到2.5 介 一种从用 属 、用 行为、用 消
费、风险控制 社 属 5 度建立用 的 ,2.6 提
一种 应用 景搭建 的 。2.7 介 一种规范化
命名 的解决方 ,可 证对 一 务 上 一的 id。

对 互 来说,其存储的 用 访 日 数据 分
用 操 的行为特 ; 对 来说则可以更 从用 属
度去 富 。
3章  数据存储
画像 搭建的 程 ,数据存储的 术 是非常重要的一
项内容,不同的存储方 适用 不同的应用 景。本章主要介 用
Hive、MySQL、HBase、Elasticsearch存储画像相关数据的应用 景及
对应的解决方 。
3.1 Hive存储
本 内容主要介 用Hive 为数据 库的应用 景时,相应的
库表 如 设计。
3.1.1 Hive数据 库
建立用 画像首先需要建立数据 库,用 存储用 数据。
Hive是 Hadoop的数据 库工具, 赖 HDFS存储数据,提 的SQL
语言可以 询存储 HDFS 的数据。开 时一 用Hive 为数据
库,存储 用 特征库 相关数据。

“数据 库 父”W.H.Inmon 《Building the Data


Warehouse》一 定义数据 库是“一 面 主题的、集成的、非易
的、随时 变化的、用来支持 理 决 的数据集 ”。

·面 主题: 务数据库 的数据主要 对事务 理, 务


是相互分离的, 数据 库 的数据是 照一定主题进行组
织的。

·集成:数据 库 存储的数据是从 务数据库 提取出来的,


并不是对原有数据的 单 制, 是 取、 理、 换
(ETL) 工 。 务数据库记 的是 一项 务 理的 账。这
数据不适 进行分 理,进入数据 库 前需要 一 列计 ,
同时 一 无关分 理的数据。

·非易 : 务数据库 一 存储短期数据, 此其数据是不


稳定的,记 的是 数据变化的瞬 。数据 库 的数据 表
示 去 一时刻的数据,主要用 询、分 ,不像 务 的数
据库一样 常 改,一 数据 库 建完成后主要用 访 ,不进行
改 删除。

·随时 变化:数据 库关 的是历 数据, 时 顺序定期从


务库 日 库里面 入新的数据进行 加,带有时 属 。

数据 取到数据 库的 程如 3-1 示。
3-1 数据 取到数据 库

数据 库建 的 程 ,主要涉及事实表 度表的建 开
( 3-2)。

事实表主要 务 程设计,就应用 景来看主要包 事务事


实表, 期 照事实表 计 照事实表:

·事务事实表:用 描 务 程, 务 程的单一
务 程可进一步分为单事务事实表 事务事实表。其 单事务事实
表分别记 务 程,如下单 务记入下单事实表,支 务记
入支 事实表。 事务事实表 同一 表 包 不同 务 程,如
下单、支 、 收 务 程记 一 表 , 新 字 来判断
属 一 务 程。当不同 务 程有着相 时可 虑将 务
程放到 事务事实表 。

· 期 照事实表: 一 确定的时 隔内对 务状 进行度


。 如 看一 用 的近1年 额、近1年购物次数、近30日登
数 。

· 计 照事实表:用 看不同事件 的时 隔, 如分
用 从购 到支 的时 、从下单到订单完 的时 。一 适用
有明确时 期的 务 程。
3-2 数据 库建

度表主要用 对事实属 的 方面描 , 如, 度包


的价 、 、 牌、原厂家、 号 方面 。 度表开
的 程 , 常 到 度 变化的 况,对 变化 一
用:①重写 度 ,对历 数据进行覆盖;② 留 条记 ,
插入 度列字 加以区分;③开 日期分区表, 日分区数据记 当
日 度的属 ;④开 表 时 变化进行全 存储 方 进行
理。 画像 主要 用Hive 为数据 库,开 相应的 度表
事实表来存储 、 、应用到服务层的相关数据。
3.1.2 分区存储
如 将用 开 成一 的宽表, 这 宽表下放几十种
, 么 该画像宽表的ETL 将 费 时 , 且不
这 宽表 新 。

要解决这种ETL 费时 的 题,可以从以下几 方面着 :

·将数据分区存储,分别 行 ;

· 本 调 ;

· 一 共同的数据来 开 表。

下面介 一种用 分表、分区存储的解决方 。

根据 的 属 、行为属 、用 消费、风险控
制、社 属 度分别建立对应的 表进行分表存储对应的
数据。如 3-3 示。

· 属 表:dw.userprofile_attritube_all;

·行为属 表:dw.userprofile_action_all;

·用 消费表:dw.userprofile_consume_all;

·风险控制表:dw.userprofile_riskmanage_all;

·社 属 表:dw.userprofile_social_all
3-3 用 数据ETL 示

如创建用 的 属 宽表:

同样的,用 其 id 度(如cookieid、deviceid、registerid
)的 数据存储,也可以 用上面 的表 。

上面的创建 设立 属 度的宽表开 相关的用


,为 提高数据的插入 询效率, Hive 可以 用分区表的方
,将数据存储 不同的目 。 Hive 用select 询时一
描整 表 有数据,将 费 时 描不是当前要 询的数
据,为 描表 关 的一 分数据, 建表时 入 partition的
。 询时,可以 Hive的分区机制来控制一次 历的数据 。
3.1.3 
3.1.2 的 ,用 的 插入到相应的分区下面,
是对一 用 来说, 上的全 存储 不同的分区下
面。为 方 分 询,需要将用 上的 理。 接
3.1.2 的 ,下面讲解 的开 (见 3-4)。

后将一 用 上的全 到一 字 ,
表 设计如下:

CREATE TABLE `dw.userprofile_userlabel_map_all`(


`userid` string COMMENT 'userid',
`userlabels` map<string,string> COMMENT 'tagsmap',)
COMMENT 'userid 用 '
PARTITIONED BY ( `data_date` string COMMENT '数据日期')

3-4  数据

开 udf函数“cast_to_json”将用 上的 成json字
, 行命令将 分区存储的 进行 :
insert overwrite table dw.userprofile_userlabel_map_all partition(data_date=
"data_date")
select userid,
cast_to_json(concat_ws(',',collect_set(concat(labelid,':',labelweight))))
as userlabels
from “用 度的 表”
where data_date= " data_date "
group by userid

后用 的存储 如 3-5 示

3-5  数据

将用 上的 进行 询 计 。 如, 画像
, 入用 id后 直接 询该表,解 id 对应的 权重
后,即可 前端展示该用 的相关 (如 3-6 示)。

3-6 用 询
3.1.4 ID-MAP
开 用 的时 ,有项非常重要的内容——ID-MApping,即
用 不同来 的 识 数据 识别为同一 主 。用 的
属 、行为相关数据分散 不同的数据来 , ID-MApping
用 不同 景下的行为 来,消除数据孤岛。 3-7展示 用
与设 的 对 关 。 3-8展示 同一用 不同平台 的行为
示 。

3-7 用 设 的 对 关
3-8  同一 用 不同平台 行为

来说,用 未登 App的状 下, App站内访 、搜 相


关内容时,记 的是设 id(即cookieid)相关的行为数据。 用
登 App后,访 、收藏、下单 相关的行为记 的是账号id(即
userid)相关行为数据。虽 是同一 用 , 其 登 未登 设
时记 的行为数据 是未 的。 ID-MApping userid
cookieid的对应关 ,可以 用 登 、未登 设 时 捕获其行
为 。

下面 一 介 如 Hive的ETL工 完成ID-Mapping的
数据 工 。

变化 是 表设计 常见的一种方 , 度并不是不变


的,随时 也 生 变化。如用 的 机号、 可
随用 的状 变化 改变,再如 的价 也 随时 变化 调整上
的价 。 此 设计用 、 表时 虑用 变化 来开
。同样, 设计ID-Mapping表时,由 一 用 可以 设 上
登 ,一 设 也 被 用 登 , 以 虑用 变化 表来记
这种不同时 的状 变化( 3-9)。
3-9 ID-Mapping 表

表是 对 变化 表的一种设计方 ,记 一 事物从开
始到当前状 的全 状 变化 。

上 , 表记 userid 一次关 到不同cookieid


的 况。如userid为44463729的用 , 20190101这 登 设 ,
6号 变换 另一 设 登 。其 start_date表示该记 的开始
日期,end_date表示该记 的 束日期,当end_date为99991231时,
表示该条记 当前仍 有效。

首先需要从 表 访 日 表里面获取到cookieid userid同


时出现的访 记 。下面 ,ods.page_event_log是 日
表,ods.page_view_log是访 日 表,将获取到的userid cookieid
插入cookieid-userid关 表(ods.cookie_user_signin) 。代
码 行如下:

INSERT OVERWRITE TABLE ods.cookie_user_signin PARTITION (data_date =


'${data_date}')
SELECT t.*
FROM (
SELECT userid,
cookieid,
from_unixtime(eventtime,'yyyyMMdd') as signdate
FROM ods.page_event_log -- 表
WHERE data_date = '${data_date}'
UNION ALL
SELECT userid,
cookieid,
from_unixtime(viewtime,'yyyyMMdd') as signdate
FROM ods.page_view_log -- 访 日 表
WHERE data_date = '${data_date}'
) t
创建ID-Map的 表,将 新 到ods.cookie_user_signin表
的数据与 表历 数据 比 ,如 有变化 新 数据则进行更
新。

CREATE TABLE `dw.cookie_user_zippertable`(


`userid` string COMMENT '账号ID',
`cookieid` string COMMENT '设 ID',
`start_date` string COMMENT 'start_date',
`end_date` string COMMENT 'end_date')
COMMENT 'id-map 表'
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'

创建完成后, ETL调度将数据更新到ID-Mapping 表 ,
务 行如下。

INSERT OVERWRITE TABLE dw.cookie_user_zippertable


SELECT t.*
FROM (
SELECT t1.user_num,
t1.mobile,
t1.reg_date,
t1.start_date,
CASE WHEN t1.end_date = '99991231' AND t2.userid IS NOT NULL THEN
'${data_date}'
ELSE t1.end_date
END AS end_date
FROM dw.cookie_user_zippertable t1
LEFT JOIN ( SELECT *
FROM ods.cookie_user_signin
WHERE data_date='${data_date}'
)t2
ON t1.userid = t2.userid
UNION
SELECT userid,
cookieid,
'${data_date}' AS start_date,
'99991231' AS end_date
FROM ods.cookie_user_signin
WHERE data_date = '${data_date}'
) t

数据写入表 ,如 3-9 示。

对 该 表,可 看 日(如20190801)的 照数据。

select *
from dw.cookie_user_zippertable
where start_date<='20190801' and end_date>='20190801'
如,目前存 一 记 userid cookieid关 关 的表, 是
为 对 的记 (即一 userid对应 条cookieid记 ,以及一条
cookieid对应 条userid记 )。这里可以 表的日期来 看
时 userid对应的cookieid。 看 用 (如32101029)
(如20190801)关 到的设 id( 3-10)。

select cookieid
from dw.cookie_user_zippertable
where userid='32101029' and start_date<='20190801' and end_date>='20190801'

3-10  用 表 记

上 可看出用 ‘32101029’ 历 曾登 3 设 , 限
定时 可 到特定时 下用 的登 设 。

开 需要 关 userid与cookieid的 对 关 ,如 不
加条件限制就 关 , 可 数据 题。

实际应用 , 到许 需要将userid cookieid 关 的


况。 如,需要 userid 度开 出该用 近30日的购 次数、购
额、登 时 、登 数 。前两 可以 容易 从相应
的 务数据表 根据 加工出来, 登 时 、登 数的数据存
储 相关日 数据 ,日 数据表记 的userid与cookieid为 对
关 。 此 务需 开 时,要确定好 径定义。

本 介 将userid cookieid 的一种解决方


,实 还存 需要将用 不同平台 (如Web端 App端)行为
的应用 景。
3.2 MySQL存储
MySQL 为关 数据库, 用 画像 可用 元数据 理、监控
预警数据、 集存储 应用 。下面详细介 这3 应用 景。
3.2.1 元数据 理
Hive适 数据 的 理 ,对 小的数据,MySQL
具有更 的读写速度。Web端 读写MySQL数据库 有更 的速度,
方 的定义、 理。

7.2 7.3 ,我 介 元数据 入 询功 ,将相应


的数据存储 MySQL 。用 的元数据表 设计 7.3 进行
详细的介 。这里给出 平台 视 (如 3-11 示) 元数据
理页面(如 3-12 示)。

3-11 平台 视
3-12  理

平台 视 的 元数据可以 护 MySQL关 数据库 ,


的 、 询 理。
3.2.2 监控预警数据
MySQL还可用 存储 对ETL 的监控 。从整 画像调度
的关 来看,需要监控的环 主要包 对 的 出 、
服务层数据同步 况的监控 主要 景。 3-13 示是用 画像调度
主要 ,下面详细介 。

3-13 用 画像调度 主要

1. 计 数据监控

主要用 监控 ETL的数据 是 出现 常,如 有 常


况则 出 警 件,同时暂 后面的ETL 务。

2.服务层同步数据监控

服务层一 用HBase、Elasticsearch 为数据库存储 数


据 上调用,将 相关数据从Hive数 服务层同步的 程 ,
有出现差 的可 , 此需要记 相关数据 Hive 的数 及同步到
对应服务层后的数 ,如 数 不一致则触 警。

对画像的数据监控 ,调度 完相应的 ,就将该


的监控数据插入MySQL ,当 验 务判断 到触 警 时, 送
警 件,同时 断后 的调度 务。待开 解决 题后,可重
后 调度。
3.2.3  集存储
集可以用来存储 视分 用的 、 服务用的用
、当日记 数 ,用 验 数据是 出现 常。

有的 上 务 用MySQL、Oracle 关 数据库存储数据,
如短 、消 推送 。 画像数据与 上 务 时,
需要 虑将存储 Hive 的用 相关数据同步到 务 ,此
时MySQL可用 存储 集。

Sqoop是一 用来将Hadoop 关 数据库 的数据相互 移的工


具。它可以将一 关 数据库(如MySQL、Oracle、PostgreSQL )
的数据导入Hadoop的HDFS ,也可以将HDFS 的数据导入关 数
据库 。

下面 一 来讲解如 用Sqoop将Hive 的 数据 移
到MySQL 。

电 、 险、 融 公司的客服 的日常工 内容 一是对目


用 (如已 用 、高价 用 )进行主动 呼,以此
用 来平台进行购 购。这里可以 助用 画像 实现该功

将Hive 存储的与用 相关的数据同步到客服 ,首先


Hive 建立一 记 用 相关 的表
(dw.userprofile_userservice_all)。设 日期分区以 日期
取当前 的需要。

CREATE TABLE `dw.userprofile_userservice_all `(


`user_id` string COMMENT 'userid',
`user_sex` string COMMENT 'user_sex',
`city` string COMMENT 'city',
`payid_money` string COMMENT 'payid_money',
`payid_num` string COMMENT 'payid_num',
`latest_product` string COMMENT 'latest_product',
`date` string COMMENT 'date',
`data_status` string COMMENT 'data_status')
COMMENT 'userid 用 客服数据'
PARTITIONED BY ( `data_date` string COMMENT '数据日期')
MySQL 建立一 用 接收同步数据的表
(userservice_data)。

CREATE TABLE `userservice_data` (


`user_id` varchar(128) DEFAULT NULL COMMENT '用 id',
`user_sex` varchar(128) NOT NULL COMMENT '用 别',
`city` varchar(128) DEFAULT NULL COMMENT ' 市',
`payid_money` varchar(128) DEFAULT NULL COMMENT '消费 额',
`payid_num` varchar(128) DEFAULT NULL COMMENT '消费次数',
`latest_product` varchar(128) DEFAULT NULL COMMENT '最近购 ',
`date` varchar(64) NOT NULL COMMENT ' 日期',
`data_status` varchar(64) DEFAULT '0' COMMENT '0:未 ,1: ,2:成功,3: 败',
PRIMARY KEY (`user_id`),
) ENGINE=InnoDB AUTO_INCREMENT=2261628 DEFAULT CHARSET=utf8 COMMENT='用 客服数据
表';

Python 本调用shell命令,将Hive 的数据同步到MySQL


。 行如下 本:

# -*- coding: utf-8 -*-


import os
import MySQLdb
import sys
def export_data(hive_tab, data_date):
sqoop_command = "sqoop export --connect
jdbc:mysql://10.xxx.xxx.xxx:3306/mysql_database --username username --password
password --table mysql_table --export-dir hdfs://nameservice1/user/hive/warehouse
/dw.db/" + hive_tab + "/data_date=" + data_date + " --input-fields-terminated-by
'\001'"
os.system(sqoop_command)
print(sqoop_command)

if __name__ == '__main__':
export_data("dw.userprofile_userservice_all", '20181201')

其 用到 sqoop从Hive导出数据到MySQL的命令:

sqoop export
--connect 定JDBC 接字 ,包 IP 端 数据库名称 \
--username JDBC 接的用 名\
--passowrd JDBC 接的密码\
--table 表名\
--export-dir 导出的Hive表, 对应的是HDFS \
--input fileds-terminated-by ‘,’ 分隔 号

同步后MySQL 的数据如 3-14 示。


3-14 同步到MySQL 的数据
3.3 HBase存储

3.3.1 HBase 介
HBase是一 高 、列存储、可 、实时读写的分布 存储
,同样运行 HDFS 上。与Hive不同的是,HBase 数据库上实
时运行, 不是 MapReduce 务,适 进行 数据的实时 询。

画像 Hive里 出的 集数据可同步到HBase数据
库,用 上实时应用的 景。

下面介 几 本 :

·row key:用来表示 一一行记 的主 ,HBase的数据是 照


row key的字典顺序进行全局排列的。访 HBase 的行 有3种方 :

· 单 row key访 ;

· row key的正则访 ;

·全表 描。

由 HBase rowkey对数据进行 , rowkey由 度限制的


不 将 询条件 接 rowkey , 此HBase无 像关 数据
库 样根据 种条件对数据进行 。一 ,HBase需建立二
来 根据 杂条件 询数据的需 。

Rowkey设计时需要 三 原则:

· 一 原则:rowkey需要 证 一 ,不存 重 的 况。
画像 一 用用 id 为rowkey。

· 度原则:rowkey的 度一 为10-100bytes。

·散列原则:rowkey的散列分布有利 数据 衡分布
RegionServer,可实现负 衡。
·columns family: 列 ,HBase 的 列 归属 列
。列 是表的schema的一 分, 须 用表 前定义。划分
columns family的原则如下:

·是 具有相 的数据 ;

·是 具有相 的访 。

常用的 删改 命令如下。

1)创建一 表, 定表名 列 名:

create '<table name>','<column family>'

2) 描表 数据,并显示其 的10条记 :

scan '<table name>',{LIMIT=>10}

3) 用get命令读取数据:

get '<table name>','row1'

4)插入数据:

put '<table name>','row1','<colfamily:colname>','<value>'

5)更新数据:

put '<table name>','row ','Column family:column name','new value'

6) 删除表 前先将其禁用, 后删除:

disable '<table name>'


drop '<table name>'
下面 一 来介 HBase 画像 的应用 景 工程化
实现方 。
3.3.2 应用 景
运营 为 进未 册的新安装用 册、下单,计划
App首页弹窗(如 3-15 示) 放 包 券的方 进行 导。
该 景 可 画像 实现对应功 。

务 上, 运营 组 用 (如“未 册用
” “安装 今 数”小 ×× ) 出对应的用 , 后
将对应 推送到“广 ”( 功 详见7.4 ),这样
画像 的ETL调度完成后对应 数据就被推送到HBase数据库进行
存储。 条件的新用 来访App时,由 接 读取HBase数据库,
询到该用 时为其推送该弹窗。

下面 工程 来讲解HBase 该触 用 景 的应用方

3-15 App弹窗推送内容( “ 刻”App)
3.3.3 工程化
运营 画像 (详见 7章) 根据 务规则定义组 用
出用 ,并将该 上 到广 (如 3-16
示)。

3-16 将待运营 上 到广

务 好规则后,下面我 来看 数据调度层面是如
运行的。

用 数据 ETL将 用 上的 后插入到目 表
,如dw.userprofile_userlabel_map_all(详见3.1.3 )。 后
数据存储为 用 id,以及 上对应的 集 ,数据 如
3-17 示。

3-17 userid用 数据

接下来需要将Hive 的数据导入HBase, 上接 实时调用库


数据。
HBase的服务 主从服务 (如 3-18 示),
同一时刻 有一 HMaster 状 ,当 的Master挂掉后,
Backup HMaster 动接 整 HBase集 。 同步数据前,首先需要判
断HBase的当前 是 台机 。

3-18 HBase的主从服务

行如下 本:

# 判断
global activenode
for node in ("10.xxx.xx.xxx","10.xxx.xx.xxx"): # 两台机 为Master,判断 台HMaster

command = "curl http://"+ str(node) + ":9870/jmx?
qry=Hadoop:service=NameNode,name=NameNodeStatus"
status = os.popen(command).read()
print("HBase Master status: ".format(status))
if ("active" in status):
activenode = node

行完毕后,可 的“State”字 判断当前 状 (


为“active”,不 为“standby”),如 3-19 示。
3-19 HBase当前 状

为 免数据 写入一 region,造成HBase的数据 斜 题。 当


前HMaster 的 上,创建预分区表:

create 'userprofile_labels', { NAME => "f", BLOCKCACHE => "true" , BLOOMFILTER =>
"ROWCOL" , COMPRESSION => 'snappy', IN_MEMORY => 'true' }, {NUMREGIONS =>
10,SPLITALGO => 'HexStringSplit'}

将待同步的数据写入HFile,HFile 的数据以key-value 对方
存储, 后将HFile数据 用BulkLoad 写入HBase集 。Scala
本 行如下:

import org.apache.hadoop.fs.{FileSystem, Path}


import org.apache.hadoop.HBase.client.ConnectionFactory
import org.apache.hadoop.HBase.{HBaseConfiguration, KeyValue, TableName}
import org.apache.hadoop.HBase.io.ImmutableBytesWritable
import org.apache.hadoop.HBase.mapreduce.{HFileOutputFormat2,
LoadIncrementalHFiles}
import org.apache.hadoop.HBase.util.Bytes
import org.apache.hadoop.mapreduce.Job
import org.apache.spark.sql.SparkSession

object Hive2HBase {
def main(args: Array[String]): Unit = {
// 入日期参数 当前 的master
val data_date = args(0)
val node = args(1) //当前 的 ip

val spark = SparkSession


.builder()
.appName("Hive2HBase")
.config("spark.serializer","org.apache.spark.serializer.KryoSerializer")
.config("spark.storage.memoryFraction", "0.1")
.config("spark.shuffle.memoryFraction", "0.7")
.config("spark.memory.useLegacyMode", "true")
.enableHiveSupport()
.getOrCreate()

//创建HBase的
val conf = HBaseConfiguration.create()
conf.set("HBase.zookeeper.quorum", "10.xxx.xxx.xxx,10.xxx.xxx.xxx")
conf.set("HBase.zookeeper.property.clientPort", "8020")

//为 预防hfile文件数 无 进行导入,设 参数


conf.setInt("HBase.hregion.max.filesize", 10737418240)
conf.setInt("HBase.mapreduce.bulkload.max.hfiles.perRegion.perFamily", 3200)

val Data = spark.sql(s"select userid,userlabels from


dw.userprofile_usergroup_labels_all where data_date='${data_date}'")
val dataRdd = Data.rdd.flatMap(row => {
val rowkey = row.getAs[String]("userid".toLowerCase)
val tagsmap = row.getAs[Map[String, Object]]("userlabels".toLowerCase)
val sbkey = new StringBuffer() // 对MAP 化 a->b 'a':'b'
val sbvalue = new StringBuffer()
for ((key, value) <- tagsmap){
sbkey.append(key + ":")
val labelght = if (value == ""){
"-999999"
} else {
value
}
sbvalue.append(labelght + ":")
}
val item = sbkey.substring(0,sbkey.length -1)
val score = sbvalue.substring(0,sbvalue.length -1)
Array(
(rowkey,("f","i",item)),
(rowkey,("f","s",score))
)
})

// 将rdd 换成HFile需要的
val rdds = dataRdd.filter(x=>x._1 != null).sortBy(x=>(x._1,x._2._1,
x._2._2)).map(x => {
//KeyValue的实 为value
val rowKey = Bytes.toBytes(x._1)
val family = Bytes.toBytes(x._2._1)
val colum = Bytes.toBytes(x._2._2)
val value = Bytes.toBytes(x._2._3.toString)
(new ImmutableBytesWritable(rowKey), new KeyValue(rowKey, family, colum,
value))
})

//文件 存 hdfs的位
val locatedir = "hdfs://" + node.toString +
":8020/user/bulkload/hfile/usergroup_HBase_" + data_date

// locatedir生成的Hfile文件
rdds.saveAsNewAPIHadoopFile(locatedir,
classOf[ImmutableBytesWritable],
classOf[KeyValue],
classOf[HFileOutputFormat2],
conf)
//HFile导入到HBase
val load = new LoadIncrementalHFiles(conf)
//HBase的表名
val tableName = "userprofile_labels"
//创建HBase的 接,利用默认的 文件,读取HBase的master
val conn = ConnectionFactory.createConnection(conf)
//根据表名获取表
val table = conn.getTable(TableName.valueOf(tableName))

try {
//获取HBase表的region分布
val regionLocation = conn.getregionLocation(TableName.valueOf(tableName))
//创建一 hadoop的mapreduce的job
val job = Job.getInstance(conf)
//设 job名称, 命名
job.setJobName("Hive2HBase")
// 出文件的内容KeyValue
job.setMapOutputValueClass(classOf[KeyValue])
//设 文件 出key, outkey要用ImmutableBytesWritable
job.setMapOutputKeyClass(classOf[ImmutableBytesWritable])
// HFileOutputFormat2的
HFileOutputFormat2.configureIncrementalLoad(job, table, regionLocation)
//开始导入
load.doBulkLoad(new Path(locatedir), conn.getAdmin, table, regionLocation)
} finally {
table.close()
conn.close()
}
spark.close()
}
}

提 Spark 务,将HFile 数据bulkload到HBase 。 行完成


后,可以 HBase 看到该数据已 写入“userprofile_labels”
( 3-20)。

3-20 HBase 存储 数据

接 询HBase 数据时,由 HBase无 像关 数据库


样根据 种条件对数据进行 ( SQL语言 的where 条
件)。一 HBase需建立二 来 根据 杂条件 询数据的需
,本 用Elasticsearch存储HBase 数据( 3-21)。

组 询对应的用 景 ,首先 组 的条
件 Elasticsearch 询对应的 数据, 后 数据去
HBase 获取rowkey对应的数据(Elasticsearch 的documentid
HBase 的rowkey 设计为用 id)。
3-21  Elasticsearch存储的HBase二 方

为 免从Hive HBase 入数据时 , HBase数据同步完


成后,还需要 验HBase Hive 数据 是 一致,如出现 的 动
则 送 警 。

下面 Python 本来看该HBase状 表数据 验 :

# 询Hive 数据
def check_Hive_data(data_date):
r = os.popen("Hive -S -e\"select count(1) from
dw.userprofile_usergroup_labels_all where data_date='"+data_date+"'\"")
Hive_userid_count = r.read()
r.close()
Hive_count = str(int(Hive_userid_count)
print "Hive_result: " + str(Hive_count)
print "Hive select finished!"

# 询HBase 数据
def check_HBase_data(data_date):
r = os.popen("HBase org.apache.hadoop.HBase.mapreduce.RowCounter
'userprofile_labels'\" 2>&1 |grep ROWS")
HBase_count = r.read().strip()[5:]
r.close()
print "HBase result: " + str(HBase_count)
print "HBase select finished!"

# 接 DB,将 询 插入表
db = MySQLdb.connect(host="xx.xx.xx.xx",port=3306,user="username",
passwd="password", db="xxx", charset="utf8")
cursor = db.cursor()
cursor.execute("INSERT INTO service_monitor(date, service_type, Hive_count,
HBase_count) VALUES('"+datestr_+"', 'advertisement',
"+str(Hive_userid_count)+","+str(HBase_count)+")")
db.commit()
本 将userid 为rowkey存入HBase,一方面 组 的
景 可以支持条件 询 用 ,另一方面可以支持单 用
的 询, 如 看 id用 上的 ,以 运营 决定是 对其
进行运营操 。

HBase 离 数 环 的服务 如 3-22 示。

3-22 HBase离 数 服务
3.4 Elasticsearch存储

3.4.1 Elasticsearch 介
Elasticsearch是一 开 的分布 全文 擎,可以近 实时
存储、 数据。 且可 展 好,可以 展到上百台服务 ,
理PB 别的数据。对 用 询、用 计 、用
视分 这 对 应时 要 高的 景,也可以 虑 用
Elasticsearch进行存储。

Elasticsearch是面 文 数据库,一条数据 这里就是一 文


,用json 为文 。为 更 晰 理解Elasticsearch 询的一
,将其 关 数据库的 进行对照,如 3-23 示。

关 数据库 询数据时可 数据库、表、行、列来


定位 的内容, Elasticsearch (index)、
(type)、文 (document)、字 来定位 内容。一
Elasticsearch集 可以包 (数据库),也就是说,其 包
(表),这 包 的文 (行), 后
文 包 的字 (列)。Elasticsearch的 互可以 用
Java API,也可以 用HTTP的RESTful API方 。

3-23 Elasticsearch与关 数据库的对比
3.4.2 应用 景
HBase的存储方 并 有解决数据的高效 题。 实际应
用 , 常有根据特定的几 字 进行组 后 的应用 景,
HBase 用rowkey 为一 ,不支持 条件 询,如 要对库里的
非rowkey进行数据 询,往往需要 MapReduce 分布
进行计 ,时 延 上 比 高,难以同时 用 对 杂条件
询 高效率 应这两方面的需 。

为 既 支持对数据的高效 询,同时也 支持 条件 进
行 杂 询,需要 HBase上 建二 ,以 对应的需要。 本
我 用Elasticsearch存储HBase的 ,以支持 杂高效
的 询功 。

主要 询 程包 :

1) Elasticsearch 存放用 条件的数据,并将rowkey也


存储进去;

2) 用Elasticsearch的API根据组 的条件 询出rowkey的


集 ;

3) 用上一步 到的rowkey去HBase数据库 询对应的 (见


3-24)。

HBase数据存储数据的 放 Elasticsearch ,实现 数据


的分离。 Elasticsearch documentid是文 的 一 识,
HBase rowkey是记 的 一 识。 工程实 ,两 可同时 用用
平台上的 一 识(如userid deviceid) 为rowkey
documentid,进 解决HBase Elasticsearch 关 的 题。
3-24  Elasticsearch存储的HBase二 方

下面 用Elasticsearch解决用 计 分 应用 景的
来 解这一 程。

对 后的用 表
dw.userprofile_userlabel_map_all(3.1.3 ) 的数据进行 ,
掉一 无效字 , 到导入Elasticsearch的条件,如 3-25
示。

3-25  数据

后将dw.userprofile_userlabel_map_all数据写入
Elasticsearch ,Scala代码如下:

object HiveDataToEs {

def main(args: Array[String]): Unit = {

val spark = SparkSession.builder()


.AppName("EsData")
.config("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
.config("spark.dynamicAllocation.enabled", "false")
.config("es.index.auto.create", "true")
.config("es.nodes", "10.xx.xx.xx")
.config("es.batch.write.retry.count", "3") // 默认重试3次
.config("es.batch.write.retry.wait", "5") // 次重试 待时 为5秒
.config("thread_pool.write.queue_size", "1000")
.config("thread_pool.write.size", "50")
.config("thread_pool.write.type", "fixed")
.config("es.batch.size.bytes", "20mb")
.config("es.batch.size.entries", "2000")
.config("es.http.timeout","100m")
.enableHiveSupport()
.getOrCreate()

val data_date = args(0).toString


import spark.sql
val hiveDF = sql(
s"""
| SELECT userid, tagsmap FROM dw.userprofile_userlabel_map_all where
data_date = '${data_date}'
""".stripMargin) // dw.userprofile_userlabel_map_all 3.1.3 讲 ,是
用 的表

val rdd = hiveDF.rdd.map {


row => {
val userid = row.getAs[String]("userid")
val userlabels = row.getAs[Map[String, Object]]("userlabels")
Map("userid" -> userid, "userlabels" -> userlabels)
}
}
EsSpark.saveToEs(rdd , "userprofile/tags", Map[String,String]("es.mApping.id"-
>"userid")
spark.stop()
}
}

工程 赖如下:

<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch-hadoop</artifactId>
<version>6.4.2</version>
</dependency>

将该工程 包 后提 务, 入日期分区参数“20190101”
行。提 命令“spark-submit--class com.example.HiveDataToEs--
master yarn--deploy-mode client--executor-memory 2g--num-
executors 50--driver-memory 3g--executor-cores 2 spark-hive-
to-es.jar 20190101”。

务 行完毕后,当日userid 度的用 数据全 导入


Elasticsearch 。 用RESTfulAPI 询包 的用 ,可实
时 到 ,如 3-26 示。
# 询命令
GET userprofile/tags/_search
{
"size":0,
"aggs": {
"tagcounts": {
"terms": {
"field": "tags.ACTION_U_01_003"
}
}
}
}

3-26 Elasticsearch 询 的

从 可以看到,用 (total)为100000000 ,包
“ACTION_U_01_003”的用 有2500000 (doc_count)。
询 index 看 :

# 询命令
GET userprofile/_search
{
"query":{
"match_all": {}
}
}

询 如 3-27 示。

3-27 Elasticsearch 询 index数据

的计 分 景 , 的 代,前期 用Impala
进行计 ,一 费几十秒到几分 的时 , 用Elasticsearch
后,实现 对 计 的秒 应。
3.4.3 工程化
下面 一 工程 来讲解实现画像 “用
” “ 分 ”功 对用 计 秒 应的一种解决方 。

的ETL调度 ,需要将Hive计 的 数据导入


Elasticsearch 。如 3-28 示, 调度完成且 验后(
3-28 的“ 监控预警” 务 行完成后),将 数据同步到
Elasticsearch 。

与Elasticsearch数据同步完成并 验后, MySQL


护的状 表 插入一条状 记 ,表示当前日期的Elasticsearch数据
可用, 上计 用 的接 则读取最近日期对应的数据。如
为调度延 方面的原 , 有及时将当日数据导入
Elasticsearch ,接 也 读取最近一 对应的数据,是一种可行的
方 。

如,数据同步完成后 MySQL状
表“elasticsearch_state” 插入记 (如 3-29 示),当日数据
出正常时,state字 为“0”, 出 常时为“1”。 3-29 1月
20日导入的数据出现 常,则“state”状 字 1, 上接 描
该状 记 位后不读取1月20日数据, 是取用最近的1月19日数据。
3-28 工程化调度 导入Elasticsearch

3-29 Elasticsearch状 记 表

为 免从Hive Elasticsearch 入数据时 生数据 ,


状 表更新状 位前需要 验Elasticsearch Hive 的数据 是
一致。下面 Python 本来看数据 验 :
# 询Hive 的数据
def monitor_hive_data(data_date):
hive_user = " select count(1) from dw.userprofile_userlabel_map_all where
data_date='{}' ".format(data_date)
user_count = os.popen("hive -S -e \"" + hive_user + "\"").read().strip()
return user_count

# 询es 的数据
def monitor_es_data(data_date):
userid_search = "curl http://10.xxx.xxx.xxx:9200/_cat/count/" + data_date +
"_userid/"
userid_num = str(os.popen(userid_search).read()).split(' ')[-1].strip()
return userid_num

# 比 Hive es 的数据,如 验,更新MySQL状 位


def update_es_data(data_date):
'''
data_date: 询数据日期
'''
esdata = monitor_es_data(data_date) # 询es 的数据
hivedata = monitor_hive_data(data_date) # 询Hive 的数据
print("esdata ======>{}".format(esdata))
print("hivedata ======>{}".format(hivedata))

# 更新MySQL状 位
if (esdata[0] == hivedata[0] ):
db = MySQLdb.connect(host="10.xx.xx.xx", port=3306, user="username",
passwd="password",
db="userprofile", charset="utf8")
cursor = db.cursor()
try:
select_command = "INSERT INTO `elasticsearch_state` VALUES ('"+
str(data_date) +"', 'elasticsearch', '0', '2');"
cursor.execute(select_command)
db.commit()
except Exception as e:
db.rollback()
exit(1)

上面介 工程化调度 时将Hive 的用 数据 入


Elasticsearch , 后 务 画像 端计 视分
时(如 3-30 示), RESTful API访 Elasticsearch进行计
(如 3-31 示)。
3-30 画像 端计

3-31 用 计
3.5 本章小
本章讲解 用Hive、MySQL、HBase Elasticsearch存储 数
据的解决方 ,包 :Hive存储数据相关 表、 计 表的表
设计以及ID-Mapping的一种实现方 ;MySQL存储 元数据、监控
数据及 集数据;HBase存储 上接 实时调用的数据;
Elasticsearch存储 用 计 视分 。存储 程
涉及如下相关表。

·dw.userprofile_attritube_all:存储 属 度的
表;

·dw.userprofile_action_all:存储行为属 度的 表;

·dw.userprofile_consume_all:存储用 消费 度的 表;

·dw.userprofile_riskmanage_all:存储风险控制 度的
表;

·dw.userprofile_social_all:存储社 属 度的 表;

·dw.userprofile_userlabel_map_all: 用 度 的
表;

·dw.userprofile_usergroup_labels_all:存储计 后 数据
的表。

面 不同的工程 景 用不同的存储方 ,本章 “工程 景


+ ”的 介 一种可实现的用 存储解决方 。
4章  数据开
数据开 是用 画像 搭建 最主要的环 ,主要包 离
开 、实时 开 、用 特征库开 、 计 、 数
据服务层 开 内容。

离 开 主要2章讲的数据 开 计 、
规则 、 掘 展开;实时 主要 对给用 展现实
时 强的 景开 相关数据,如首页新 弹窗、新 包 景;
用 特征库 用 的 次行为明细记 相关数据,如用 览、搜
、收藏、下单 行为明细,一 该特征库 日 时 分区; 计
应用 数据服务层 前, 务方需要组 用 的 来 出对应
, 计 功 组 划分出对应的 ; 数据服务
层将 务方根据 务规则 定出来的用 推送到不同的 务
去。

下面10 小 分别对这 常见的开 内容 详细介 。


4.1  计 开
计 是 计用 相关数 、客观描 用 状 的 ,
如用 的年龄、 重、 计购 额、 计购 次数、近30日登 次
数 。

4.1 ~4.2 离 开 相关的 ,将用 相关的


插入到userid 度的行为 表 。这里再 顾一下3.1.2 讲的表
设计。

userid 度的用 表可 日分区,设计为如下 :

CREATE TABLE `dw.userprofile_action_all `(


`userid` string COMMENT 'userid',
`labelweight` string COMMENT ' 权重')
COMMENT 'userid 用 画像数据'
PARTITIONED BY ( `data_date` string COMMENT '数据日期', `labelid` string COMMENT
' id')

userid 度的 数据 插入到该表
(dw.userprofile_attribute_all) 。

本 以开 用 近30日购 行为相关 为 ,介 如 将相关


数据建 加工到画像表 。
4.1.1 近30日购 行为
对近30日购 行为这 二 目进行 解,可将其 解为: 订单 (对应
“ACTION_U_01_001”)、 额(对应 “ACTION_U_01_002”)、加入购物 次数(对应
“ACTION_U_01_003”)这3 ,下面看如 将 开 插入用 表 。

首先将需要计 的 从目 表 取出来。

select 'ACTION_U_01_001' as labelid, # 订单 id


cast(user_id as string) as userid,
count(distinct order_id) as labelweight # 订单
from dw.order_info_fact # 订单表
where pay_status = 1 # 订单状 是已支
and to_date(add_time) >= "month_day_ago" # 日期 30日前
and to_date(add_time) <= "yesterday_date" # 日期小 昨
union all
select 'ACTION_U_01_002' as labelid, # 额 id
cast(user_id as string) as userid,
sum(order_total_amount) as labelweight # 额
from dw.order_info_fact
where pay_status = 1 # 订单状 是已支
and to_date(add_time) >= "month_day_ago"
and to_date(add_time) <= "yesterday_date"
union all
select 'ACTION_U_01_003' as labelid, # 加入购物 事件次数 id
cast(userid as string) as userid,
count(distinct eventid) as labelweight # 加入购物 事件次数
from ods.page_event_log # 行为事件表
where data_date >= "month_day_ago"
and data_date <= "yesterday_date"
and eventkey = 'add_to_shoppingbag' # 行为事件名称为“加入购物 ”
and userid is not null # 用 id为非空

该 代码 证 将近30日的 有相应行为的用 上, 要 到 获取用 最


新状 ,还需要 一层全 接关 。 常见的 子, 用 前 购 3单 ,如 昨 购 2
单,则今 最新的状 是3+2=5单,替换掉前 3单的权重 ,如 昨 有购 行为,则权重 仍为3。
这里 full outer join(全 接)的方 ,当用 有最新状 时,获取最新状 ,如 有最新状
则仍 留原来状 的 。 全 接的代码示 如下。

user_consume_acts = "insert overwrite table dw.userprofile_action_all


partition(data_date="start_date_str",labelid="${labelid}")
select nvl(t2.labelid, t1.labelid) aslabelid,
nvl(t2.userid, t1.userid) as userid,
nvl(t2.labelweight, t1.labelweight) aslabelweight
from (
select * from dw.userprofile_userlabel_all
where data_date=" "old_date_partition"
and labelid='${labelid}'
) t1 # 前日数据分区 存储的用
full outer join (
# 这里插入的是上一 代码
) t2 # 昨日 务运行 生的新的用
on (t1.userid = t2.userid and t1.labelid = t2.labelid) "

该 本 “old_date_partition”参数为设 的一 日期变 , 日 入的数 不同。最后一行的


关 用用 id id共同 为主 。

#!/usr/bin/env python
# encoding: utf-8

from pyspark import SparkContext,SparkConf


from pyspark.sql import SparkSession
import sys
import datetime

def main():
start_date = sys.argv[1]
start_date_str = str(start_date)
format = "%Y%m%d"

strptime, strftime = datetime.datetime.strptime, datetime.datetime.strftime


old_date_partition = strftime(strptime(start_date_str, format) - datetime.timedelta(1), format)
month_day_ago = strftime(strptime(start_date_str, format) - datetime.timedelta(30), format)

# python 初始化Spark
spark = SparkSession.builder.AppName("latest_30_acts").enableHiveSupport().getOrCreate()
spark.sql(user_consume_acts) # user_consume_acts 对应 二 代码 行的语句

if __name__ == '__main__':
main()

该 代码 对 二 代码 一层Spark封装,可将 二 的HiveSQL语句提 到Spark集 上 行。


提 Spark 务计 该 “spark-submit--master yarn--deploy-mode client--driver-memory 1g--
executor-memory 2g--executor-cores 2--num-executors 50 userprofile_latest_30days_label.py
start-date”。其 spark-submit的参数说明如下:

·deploy-mode: 本 (Client) 动Driver还是 集 上(Cluster) 动Driver;

·driver-memory:Driver端内存 小;

·executor-memory:Executor端内存 小;

·executor-cores: Executor核数;

·num-executors: 动Executor的数 ;

·class:如 是JAR Scala程序的jar包,该参数对应应用程序的主 ,对 提 的Python 本,不


用提 该参数。

务 行完成后将数据插入Hive数据表 ,如 4-1 示。

4-1 用 近30日购 行为
4.1.2 最近来访
本小 再介 一 最近一次来访 今 数(对应
“ACTION_C_02_001”)的开 。

最近一次来访 今 数从用 的访 日 表
(ods.page_view_log) 取, 本 行如下:

# 获取cookie最近一次访 日期
user_cookie_relation =
" select t.cookie_id as cookieid,
t.last_visit_time as last_date
from ( select cookie_id,
last_visit_time,
row_number() over(partition by cookie_id order by
last_visit_time desc) as rank
from ods.page_view_log
where data_date = " start_date_str "
and cookie_id is not null
) t
where t.rank =1
having cookie_id is not null "

returned = spark.sql(cookie_last_visit).cache() # 存数据


returned.createTempView("cookie_last_visit") # 册视

将上一步 册到视 的数据插入cookie的用 表 , 行如


下 本:

# 将数据插入到cookie 表
last_visit =
"insert overwrite table dw.userprofile_action_all
partition(data_date="data_date",labelid='${labelid}')
select 'ACTION_C_02_001' as labelid,
cookieid,
datediff(to_date("data_date"),concat(substr(last_date,1,4),'-
',substr(last_date,5,2),'-',substr
(last_date,7,2))) as labelweight
from user_cookie_relation # 上一步骤 册的视
group by 'ACTION_C_02_001',
cookieid,
datediff(to_date("data_date"),concat(substr(last_date,1,4),'-',
substr(last_date,5,2),'-',
substr(last_date,7,2)))"

# 开 sparksession
spark =
SparkSession.builder.appName("cookieid_latest_visit").enableHiveSupport().getOrCr
eate()
spark.sql(last_visit)

提 Spark 务计 该 “spark-submit--master yarn--


deploy-mode client--driver-memory 1g--executor-memory 2g--
executor-cores 2--num-executors 50
userprofile_latest_visit.py start-date”。

务 行完成后将数据插入Hive数据表 ,如 4-2 示。

4-2 用 最近一次来访 今 数 数据
4.2 规则 开
规则 一 是
根据 务运营上的需要, 务层面制定规
则的 。这 带有一 为主观判断的 , 以 开 前
需要先进行数据调研,摸 本平台上 务数据的 况, 后再根据运
营 务规则开 相关 。

除 由数据开 写 本开 ,还可以根据设定的规
则, 用 平台上的行为进行 动 。比如用 触 的50
行为记 ,有40 记 是3C ,我 给用 上“数码
”的 。根据规则, 动化 重要的是 本平台 务数据
况设定好规则,同时也需要建立 试账号来 验 动 的准确

下面两小 相关 开 的 来介 规则 的开 。
4.2.1 用 价
RFM 是衡 用 价 的重要工具 方 ,RFM 主要由3 础 组成:(1)最
近一次消费(Recency),是 用 上一次购 时 ;(2)消费频率(Frequency),是
用 一定时 内的消费次数;(3)消费 额(Money),是 用 一定时 内 计
消费的 额。这3 础 进行组 可以划分出8 ,如表4-1 示。

表4-1 RFM用 价

开 对应的 前需要进行数据调研。根据对数据 库 取的用 消费相关数据进


行分 后 出用 这3 度的 数 上划分的界限。

本 根据对这3 度的数据调研, 到用 最近一次 易时 的分布 况,如


4-3 示。

4-3  平台用 最近一次 易时 分布(示 数据)

根据 计用 的占比,可 照二八比 进行划分,将最近一次 易时 今0,到90


日的用 划分为“近”,将最近一次 易时 今90日以上的用 划分为“远”。

本 用 近一年 易订单 的分布 况如 4-4 示。


4-4  平台用 近一年 易订单 分布(示 数据)

根据 计用 的占比, 二八比 进行划分,将历 易订单 3单以下的用 划


分为低频,将 易订单 3单及以上的用 划分为高频。

用 历 易 额分布 况如 4-5 示。

4-5  平台用 历 易 额分布(示 数据)

根据用 近一年 易 额 况,将 易 额 300元以下的用 划分为“低额”,将


易 额 300元的用 划分为“高额”。

上面从3 度对用 的数据调研,对这3 度进行 叉分 (R≤90为“近”,


R>90为“远”,F≤3为“低频次”,F>3为“高频次”,M≤300为“低额”,M>300为“高
额”),划分出以下8 ,如 4-6 示。

4-6  平台用 RFM 度的划分(示 数据)

对 务数据进行调研后开 相关 。首先从用 消费订单表


(dw.user_consume_order_info)里面获取用 最近一次消费 今 数、 计消费次数、
计消费 额这3 度的数据,并 册视 “user_rfm_info”。 行如下代码:

# 用 RFM 度数据
user_rfm_info = " select user_id,
last_1y_orders,
last_1y_order_amount,
last_payid_date
from dw.order_info_fact
where data_date = "start_date_str "
and last_order_paid_time is not null
group by user_id,
last_1y_orders,
last_1y_order_amount,
last_payid_date"

根据前面的数据调度 出的 论, 照最近一次购 今 数90 、购 次数3次、消


费 额500元来对用 3 度的价 进行高低层次的划分。将划分的 册到视
“user_rfm” 。

user_rfm = " select user_id,


case when datediff("+"'"+date_str+"'"+",latest_payid_date)<90 then '近'
else '远' end as latestday,
case when latest_1y_paid_orders < 3 then '低频'
else '高频' end as latest_ly_orders,
case when latest_1y_paid_order_amount < 500 then '低额'
else '高额' end as latest_ly_order_amount
from user_rfm_info

最后将 用 3 度的 分 况划分到8 去,将 插入到用 表


, 行如下 本。

insert_table = "insert overwrite table dw. userprofile_attritube_all


partition(data_date="start_date_str",labelid='${lableid}')
select case
when latestday = '近' and latest_1y_orders = '高频' and latest_1y_order_amount = '高额' then
'ATTRITUBE_U_06_001'
when latestday = '远' and latest_1y_orders = '高频' and latest_1y_order_amount = '高额' then
'ATTRITUBE_U_06_002'
when latestday = '近' and latest_1y_orders = '低频' and latest_1y_order_amount = '高额' then
'ATTRITUBE_U_06_003'
when latestday = '远' and latest_1y_orders = '低频' and latest_1y_order_amount = '高额' then
'ATTRITUBE_U_06_004'
when latestday = '近' and latest_1y_orders = '高频' and latest_1y_order_amount = '低额' then
'ATTRITUBE_U_06_005'
when latestday = '远' and latest_1y_orders = '高频' and latest_1y_order_amount = '低额' then
'ATTRITUBE_U_06_006'
when latestday = '近' and latest_1y_orders = '低频' and latest_1y_order_amount = '低额' then
'ATTRITUBE_U_06_007'
else 'ATTRITUBE_U_06_008' end as labelid,
user_id as userid,
'' as labelweight
from user_rfm " # user_rfm 是上一步 册的视

将上面3 本的 行 “userprofile_RFM_value.py” 行:

#!/usr/bin/env python
# encoding: utf-8

# ATTRITUBE_U_06_001 重要价 用 ATTRITUBE_U_06_002 重要 持用


# ATTRITUBE_U_06_003 重要 展用 ATTRITUBE_U_06_004 重要挽留用
# ATTRITUBE_U_06_005 一 价 用 ATTRITUBE_U_06_006 一 持用
# ATTRITUBE_U_06_007 一 展用 ATTRITUBE_U_06_008 一 挽留用
from pyspark import SparkContext,SparkConf
from pyspark.sql import SparkSession
import sys
import datetime
def main():
start_date = sys.argv[1]
start_date_str = str(start_date)
user_rfm_info = "用 RFM 度数据 视 "
user_rfm = "将用 3 度 分 视 "
insert_table = "插入用 到目 表"
spark = SparkSession.builder.AppName("user_rfm_model").enableHiveSupport().getOrCreate()
returned_df1 = spark.sql(user_rfm_info).cache()
returned_df1.createTempView("user_rfm_info") # 册视 用 RFM 度上数据
returned_df2 = spark.sql(user_rfm).cache()
returned_df2.createTempView("user_rfm") # 册视 将用 RFM划分到8
spark.sql(insert_table)

if __name__ == '__main__':
main()

提 Spark 务计 该 “spark-submit--master yarn--deploy-mode client--


driver-memory 1g--executor-memory 2g--executor-cores 2--num-executors 50
userprofile_userid_RFM_value.py start-date”。

行完 务后, 询“SELECT*FROM dw.userprofile_attritube_all WHERE


data_date="20190115"AND labelid
in('ATTRITUBE_U_06_001','ATTRITUBE_U_06_002','ATTRITUBE_U_06_003')LIMIT
5”, 到如 4-7 示的 。

4-7  询用 价
4.2.2 用 度
务 景 , 常需要根据用 的 况给用 上高
、 、低 、 ,如 划定时 范 ,如将××
未访 的用 定义为 用 ,将×× 内 ×次的用 定义为高
用 ,需要 务数据调研 况来确定数 。

下面 一 用 度 的 来进行介 。

首先需要划分用 的 期, 期内,根据用 的
况进一步将其划分为高 、 、低 。 务上划分用
的 期时有 种方 。 如:

1)根据用 访率来划分:初始日期 定的一 首次访 用 ,


观察后 时 内该 用 仍有访 行为的占初始用 的比 。随着时
的推移,该比 降低。当曲 出现明显下降时可划分为
期(如 4-8 示)。

2) 计用 最后一次访 与 数 二次访 的时 隔,可


认为 这 时 隔后用 本不 再访 ,即用 已 。
后 计 时 内用 数的占比, 计占比 到一定比 时可认为
分用 这 时 后已 。根据 4-8 示的用 访率曲
,可认为30日为用 的 期。
4-8 用 访率曲 (示 数据)

从 4-8可以看出,用 5 以后 访率下降速度减 , 访
率已 低 10%且后 趋势 持平稳。 5 为 即为用
期, 的关 是用 有访 App的行为。

从 4-9还可以看出,用 最后一次访 与 数 二次访 隔30


日以上的用 占比不 10%,可认为 这 访 时 隔的用 已
,即最后一次访 今30日以上的用 可认为已 。

根据上面介 的划定用 期的方 ,这里 定 该公司的


务 景 30日为用 期,近30日 有访 行为的用 划定为
已 用 。 30日 期内,进一步根据用 访 数来对用
度进行划分。
4-9 用 最后一次访 与 数 二次访 的时 隔(示 数
据)

对数据的调研分 ,从 4-10可以看出, 10日以上的用


占近30日访 用 的20%, 照二八划分的方 这 用 划为高
用 ,进一步 5~10日的用 划分为 用 , 1~5
日的用 划分为低 用 。另 ,从GMV占比 客单价来看,占20%
的高 用 贡献 近60%的GMV,客单价明细高 、低 用

4-10 用 数(示 数据)

根据数据调研分 的 ,以30日为界划分 期,将最后一


次访 今 30日的用 划定为已 用 ,30日内 10~30 的
用 划定为高 用 ,30日内 5~10 的用 划定为 用
,30日内 少 5 的用 划定为低 用 。根据划分的 径开
相应的 , 行如下 本:

计 近30日有 访 行为的用 及其访 数,并 册 时视


“user_active”。

# 近30日全 用
user_active = " select t.user_id,
count(*) as visit_num
from (select user_id,
data_date
from ods.user_visit_info
where data_date >= "month_day_ago"
and data_date <= "start_date "
and user_id is not null
group by user_id,
data_date
) t
group by t.user_id "

将视 的数据插入到用 表
dw.userprofile_attribute_all , 行如下代码:
user_active_status = " insert overwrite table userprofile_attritube_all
partition(data_date="data_date",labelid='${labelid}')
select t.labelid,
t.user_id as userid,
t.tagweight as labelweight
from (
select user_id,
case when visit_num <=5 then 'ACTION_U_05_001'
when visit_num >5 and visit_num<=10 then 'ACTION_U_05_002'
else 'ACTION_U_05_003' end as tagid,
visit_num as labelweight
from user_active
) t

将上面的两 本的 行
userprofile_active_churn_label.py 行:

#!/usr/bin/env python
# encoding: utf-8

from pyspark import SparkContext,SparkConf


from pyspark.sql import SparkSession
import sys
import datetime

# ACTION_U_05_003 高
# ACTION_U_05_002
# ACTION_U_05_001 低

def main():
format = "%Y%m%d"
start_date = sys.argv[1]
start_date = str(start_date)
strptime, strftime = datetime.datetime.strptime, datetime.datetime.strftime
date_str = datetime.datetime.strftime(datetime.date.today()-
datetime.timedelta(days=1),'%Y-%m-%d')
month_day_ago = strftime(strptime(start_date, format) -
datetime.timedelta(30), format)

user_active = "近30日全 用 视 "


insert_user_active = "插入用 到目 表"

spark =
SparkSession.builder.AppName("user_active_churn_label").enableHiveSupport().getOrC
reate()
returned_df1 = spark.sql(user_active).cache()
returned_df1.createTempView("user_active") # 册视
spark.sql(insert_user_active)

if __name__ == '__main__':
main()

提 Spark 务计 该 “spark-submit--master yarn--


deploy-mode client--driver-memory 1g--executor-memory 2g--
executor-cores 2--num-executors 50
userprofile_active_churn_label.py start-date”。

行完 务后, 询“SELECT*FROM
dw.userprofile_attritube_all WHERE data_date="20190101"and
labelid
in('ACTION_U_05_001','ACTION_U_05_002','ACTION_U_05_003')
LIMIT 5”, 到如 4-11 示的 。

4-11  询用 度
4.3  掘 开
掘 需要应用 掘用 相关特征,一 用 相关的
掘 可以包 预 用 男女 别、预 用 击下单、判断用
已 将要 、判断用 购 好 。

由 掘 需要进行数据调研, 用 行为特征进行特征工
程开 、 参数调 以及上 工程化调度 开 环 ,一 开
期 。

本 一 给平台上文章 的 来讲解 掘 的开

4.3.1  景
目 站上积 与疾病主题相关的文章、帖子 文本数
据。由 历 原 ,这 文章 有 内容归 ,也 有 上相应的
,不 对内容进行 理。现 为 对文章 主题进行分 ,方
后期给 读相关文章的用 上对应的 ,需要先对 历 文
章、帖子( 4-12) 分 整理,同时对 文章 上与其主题相关
的 。

对 站内的全 历 文章、帖子数据进行如下操 :

1)根据已 划定的文章内容 ,将这 未 分 的文章 动


划分到相应 下。

2)为支持文章的集 化 理,根据文章内容 动为 文章 上
与其主题相关的 。

4-12 文章 别划分
4.3.2 特征 取及开
机 学习以 计理论为 础, 对已知的训练数据 计
分 从 获 规 ,再运用规 对未知数据 预 。 文本分 题
上的 本 是: —— 工对一 文 进行准确分 , 为训练
集样本;训练——计 机从 好的文 集 掘出 有效分 的
规则,生成分 ;分 ——将生成的分 应用 待分 的文 集
,从 获 文 的分 。

首先对待分 的文章 切词 理,将切好的词语写入 定的 径


下。对文本进行分 是需要 特征的, 到数据后 么 取具有区
分度的特征 关 的一步。本 用Bunch方 建文本特征。

本 的文章 动分 的 程如 4-13 示。

4-13 文章分 数据建 程

文章分 并 的建 主要包 以下步骤:

1)对以划分好 的文本集(训练集) 待划分 的文本集


( 试集)进行文本的分词 理, 文本 句划分为单 词组;

2)将步骤1 切好的词组放入词包 , 展成 , 成bag


of word;
3)应用TF-IDF 计 训练集文 文章的TF-IDF权重矩
阵;

4) 用朴 贝 斯分 方 对训练集数据进行训练, 到参数对
试集数据进行分 理。

用到的 数据 理 术包 文本分词、TF-IDF 、
朴 贝 斯分 。
4.3.3 文本分词 理
分词是将 的字序列 照一定的规范重新组 成词序列的
程, 文分词将一 字序列(句子)切分成一 独立的单词。为
建词空 ,首先需要对待分 文本 切词 理,将切好后的
词语写入 定的 径下。 这里,我 用Python 的jieba工具对文
本进行分词,同时 用jieba.analyse.extract_tags方 ( TF-
IDF ) 取文章的主题 。

对训练集 试集数据进行切词 理后,将切词后的文本写入


定文件 ,代码 行如下(文件cut_words.py):

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import os
import jieba
import jieba.analyse # 导入提取关 词的库

# 对训练集 试集文本 进行切词 理,对 试集数据 上主题


# 存至文件
def save_file(save_path, content):
with open(save_path, "a",encoding= 'utf-8',errors='ignore') as fp:
fp.write(content)
# 读取文件
def read_file(file_path):
with open(file_path, "r",encoding= 'utf-8',errors='ignore') as fp:
content = fp.readlines()
# print(content)
return str(content)

# 取 试集的主题关 词
def extract_theme(content):
themes = []
tags = jieba.analyse.extract_tags(content, topK=3, withWeight=True, allowPOS=\
['n','ns','v','vn'],withFlag=True)
for i in tags:
themes.append(i[0].word)
return str(themes)

def cast_words(origin_path, save_path, theme_tag):


'''
train_words_path: 原始文本 径
train_save_path: 切词后文本 径
:return:
'''
file_lists = os.listdir(origin_path) #原文 径

for dir_1 in file_lists: # 到文件


file_path = origin_path + dir_1 + "/" #原始文件 径
seg_path = save_path + dir_1 + "/" #切词后文件 径

if not os.path.exists(seg_path):
os.makedirs(seg_path)

detail_paths = os.listdir(file_path)
for detail_path in detail_paths: # 到文件 下具 文件 径
full_path = file_path + detail_path #原始文件下 文 径
file_content = read_file(full_path)
file_content = file_content.strip() # replace("\r\n", " ")
# 删除换行
file_content = file_content.replace("\'", "")
file_content = file_content.replace(" \ n ", "")

content_seg = jieba.cut(file_content) # 为文件内容分词

if theme_tag is not None:


print("文件 径:{} ".format(theme_tag + detail_path))
theme = extract_theme(" ".join(content_seg)) #theme为该文章主题关

print("文章主题关 词:{} ".format(theme))
save_file(theme_tag + detail_path, theme) # 将训练集文章的主题关 词
存到 存储 径

save_file(seg_path + detail_path, " ".join(content_seg)) # 将 理后的文


件 存到分词后语料目

if __name__ == "__main__":
# 对训练集进行分词
train_words_path = './train_words/'
train_save_path = './train_segments/'
cast_words(train_words_path,train_save_path,theme_tag=None)

# 对 试集进行分词 取文章主题
train_words_path = './test_words/'
train_save_path = './test_segments/'
theme_tag_path = './theme_tag/' #存放 试集文章主题 径
cast_words(train_words_path, train_save_path, theme_tag=theme_tag_path)

行程序后,训练集 试集对应文件 下未 理的原始文


被切词 理,并将切词后的文本写入新建立的文件 下( 4-14)。
4-14 切词后的文本文件
4.3.4 数据 理
为 后 生成词 空 ,这 分词后的文本 需要
换成文本 并对象化。这里 用Scikit-Learn库 的Bunch数
据 ,将文本存储成 。Bunch是一 “字典” 的数据,
实 化Bunch的时 定义Bunch 包 的key , 用时为key参
数赋 value 。

本 定义:Bunch(label=[],filepath=[],contents=
[])。其 参数:

·label: 训练集 文本归属的 别,如:“ 尿病”“


癌”“白癜风”。

·filepath: 文件的存储 径。

·contents: 存训练集 试集 一种 别下的文本内容。

代码 行如下(文件word_to_bunch.py):

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import os
import pickle
import time
from sklearn.datasets.base import Bunch

'''
label: 文章
filepath: 文章 径
contents: 分词后的文章
'''
def read_file(file_path):
with open(file_path, "r",encoding= 'utf-8',errors='ignore') as fp:
content = fp.readlines()
return str(content)

def word_to_bunch(train_save_path, train_bunch_path):


bunch = Bunch(label=[], filepath=[], contents=[])
all_labels = os.listdir(train_save_path)
for label in all_labels:
detail_path = train_save_path + label + '/'
all_details = os.listdir(detail_path)
for all_detail in all_details:
file_detail_path = detail_path + all_detail # 文件具 径
bunch.label.append(label)
bunch.filepath.append(file_detail_path)
contents = read_file(file_detail_path)
bunch.contents.append(contents)
with open(train_bunch_path, "wb+") as fp:
pickle.dump(bunch, fp)
print("创建完成")

if __name__ == "__main__":
train_save_path = './train_segments/'
train_bunch_path = "train_bunch_bag.dat"
word_to_bunch(train_save_path, train_bunch_path)

test_save_path = './test_segments/'
test_bunch_path = "test_bunch_bag.dat"
word_to_bunch(test_save_path, test_bunch_path)

该程序 将 文 的 、存储 径、文章内容写入Bunch数据


, 后面对训练集、 试集数据的建 、分 。 行完程序
后生成train_bunch_bag.dat test_bunch_bag.dat数据文件。
4.3.5 文本TF-IDF权重
该步骤 将上一步存储的 化数据 建成一 TF-IDF词 空
,空 的词 来 该训练集, 词的权重矩阵也 一并 存下
来。 建 的 程 需要 将训练集的词 空 赋 给 试
集,代码 行如下(文件tfidf_space.py):

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

from sklearn.feature_extraction.text import TfidfVectorizer


from sklearn.feature_extraction.text import TfidfTransformer
import pickle
from sklearn.datasets.base import Bunch

# 读取bunch对象
def read_bunch(path):
with open(path, "rb") as fp:
bunch = pickle.load(fp) # joblib 同样可用 存储 文件
return bunch

# 读取文件对象
def read_file(path):
with open(path, "rb") as fp:
bunch = fp.read()
return bunch

# 写入bunch对象
def write_bunch(path,bunch):
with open(path, "wb") as fp:
pickle.dump(bunch,fp)

# 训练集
def train_tfidf_space(stopword_path, train_bunch_path, train_tfidf_data):
'''
stopword_path: 用词 径
train_bunch_path: 训练集语料 径
train_tfidf_data: 训练集tfidf数据 径
'''
bunch = read_bunch(train_bunch_path)
stopwords = read_file(stopword_path).splitlines() # 读取 用词
tfidf_space = Bunch(label=bunch.label, filepath=bunch.filepath,
contents=bunch.contents, tdm=[], space={})
vectorizer = TfidfVectorizer(stop_words=stopwords, sublinear_tf=True,
max_df=0.5)
tfidf_space.tdm = vectorizer.fit_transform(bunch.contents)
tfidf_space.space = vectorizer.vocabulary_
write_bunch(train_tfidf_data,tfidf_space)

# 试集
def test_tfidf_space(stopword_path, test_bunch_path, test_tfidf_data,
train_tfidf_data):
'''
stopword_path: 用词 径
test_bunch_path: 试集语料 径
test_tfidf_data: 试集tfidf数据 径
train_tfidf_data: 训练集tfidf数据 径,将训练集的词 空 赋 给 试集
'''
bunch = read_bunch(test_bunch_path)
stopwords = read_file(stopword_path).splitlines() # 读取 用词
tfidf_space = Bunch(label=bunch.label, filepath=bunch.filepath,
contents=bunch.contents, tdm=[], space={})
train_bunch = read_bunch(train_tfidf_data) #训练集tfidf数据
tfidf_space.space = train_bunch.space # 将训练集的词 空 赋 给 试集
vectorizer = TfidfVectorizer(stop_words=stopwords, sublinear_tf=True,
max_df=0.5, vocabulary=train_bunch.space)

tfidf_space.tdm = vectorizer.fit_transform(bunch.contents)
write_bunch(test_tfidf_data, tfidf_space)

if __name__ == '__main__':
# 训练集数据 理
stopword_path = "./chinese_stop_words.txt" # 用词表的 径
train_bunch_path = './train_bunch_bag.dat'
train_tfidf_data = './train_tfdifspace.dat'
train_tfidf_space(stopword_path, train_bunch_path,train_tfidf_data)

# 试集数据 理
test_bunch_path = './test_bunch_bag.dat'
test_tfidf_data = './test_tfidfspace.dat'
test_tfidf_space(stopword_path, test_bunch_path,
test_tfidf_data,train_tfidf_data)

行该程序 将训练集 试集数据 换为TF-IDF词 空


的实 ,其 space表示词 空 ,tdm表示训练集 试集数
据的TF-IDF权重矩阵。前文提到, 行程序时需要 将训练集的
词 空 赋 给 试集数据,该 的 试集函数的
test_tfidf_space 实现。

行完程序后生成train_tfidfspace.dat test_tfidfspace.dat
数据文件。
4.3.6 朴 贝 斯分
一 的 分 方 可应用 文本分 ,常用的分 包
朴 贝 斯分 、支持 机分 。

本 对文本分 ,从 度、 率 F- 度 三 角度进行
评价。 设a表示分 将 入文本正确分 到 别的 数;b表
示分 将 入文本 误分 到 别的 数;c表示分 将 入
文本 误 排除 别 的 数;d表示分 将 入文本正确
排除 别 的 数;则该分 的 率、正确率 F-
度 的计 公 如下:

· 度:p=a/(a+b)×100%

· 率:r=a/(a+c)×100%

·F- 度 :F=(2×p×r)/(p+r)

从 行 来看, 度为0.941、 率为0.933、F- 度 为


0.933,分 效 还 不 的。

该 程代码 行如下(文件nbayes.py):

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import pickle
from sklearn.naive_bayes import MultinomialNB
import warnings
from sklearn import metrics
warnings.filterwarnings("ignore")

# 读取bunch对象
def read_bunch(path):
with open(path, "rb") as fp:
bunch = pickle.load(fp) # joblib 同样可用 存储 文件
return bunch

# 分 存至文件
def save_file(save_path, content):
with open(save_path, "a",encoding= 'utf-8',errors='ignore') as fp:
fp.write(content)

# 朴 贝 斯分
def nbayes_classify(train_set, test_set):
'''
train_set: 训练集样本数据
test_set: 试集样本数据
:return: 试集样本分
'''
clf = MultinomialNB(alpha=0.5)
clf.fit(train_set.tdm, train_set.label) # 训练
predict = clf.predict(test_set.tdm)
return predict

def classification_result(actual, predict):


print(' 度:{0:.3f}'.format(metrics.precision_score(actual,
predict,average='weighted')))
print(' :{0:0.3f}'.format(metrics.recall_score(actual,
predict,average='weighted')))
print('f1-score:{0:.3f}'.format(metrics.f1_score(actual,
predict,average='weighted')))

if __name__ == '__main__':
# 导入训练集
train_path = './train_tfdifspace.dat'
train_set = read_bunch(train_path)

# 导入 试集
test_path = "./test_tfidfspace.dat"
test_set = read_bunch(test_path)

predict = nbayes_classify(train_set, test_set) #


classification_result(test_set.label, predict)
print('-' * 100)

# 存 径
save_path = './classify_file.txt'
for label, filename, predict in zip(test_set.label, test_set.filepath ,
predict): #test_set
print(filename, "\t实际 别:",label,"\t-->预 别:", predict)
save_content = filename + "\t实际 别:" + label + "\t-->预 别:" + predict
+ '\n'
save_file(save_path, save_content) # 将分 写入txt

行 程后可 Pycharm控制台下看到 行效 ,如 4-15 示。


4-15 文本分 行效

至此,文本分 程 的数据 理方 就介 完
,下面 4-16的文件 再 单 顾下 。

4-16 文件
4.4  计 开
前面3 介 的是离 的开 ,即 次ETL 务,一 为T+1日
的数据。本 内容介 实时 数据的开 。 实时订单分 ,
给首次登 App的新 用 弹窗推送、 放 包,实时分 用
景并进行推送 有广 的应用,这里 用Spark Streaming开 相关
的实时数据。

更多书籍访问:www.j9p.com
4.4.1  建
Spark Streaming是Spark Core API的 展,支持实时数据 的
理,并且有可 展、高 、容 的特 。数据可以从Kafka、
Flume 来 获取,可以 用map、reduce、window 高 函
数对 务 进行 理。最后, 理后的数据被推送到文件 、数
据库 (如 4-17 示)。

内 Spark Streaming接收实时数据 并将数据分成 batch


次, 后由Spark 擎进行 理, 生成 。Spark
Streaming提 一 高层 象,称为Discretized Stream
Dstream,它表示 的数据 。Dstream可以 Kafka、Flume 来
的数据 创建,也可以 其 Dstream上应用高 操 来创建
(如 4-18 示)。

4-17 Spark Streaming计 ( Spark官 )

4-18 Spark Streaming 理数据的特 ( Spark官 )


4.4.2 Kafka 介
Kafka的核 功 是 为分布 消 件。Kafka集 由
Broker server组成,其 ,消 的 送 称为Producer;消 的消费
称为Cousumer;Broker是消 理的 , Broker组成Kafka集
;Topic是数据主题,用来区分不同的 务 ,消费 订 不
同的Topic来消费不同主题的数据, Topic 被分为
Partition,Partition是topic的分组, Partition 是一 有序
列;offset用 定位消费 Partition 消费的位 。

Kafka对 用Topic ,生 Topic里写入消 ,消费 从


Topic 读取消 。一 Topic由 Partition组成。

生 Brokers 定的Topic 写消 ,消费 从Brokers里面


取 定的Topic消 , 后进行 务 理。

4-19表示 一 Topic 写入数据,写入的数据被 加到


Partition的尾 。当Consumer消费消 时, Partition下的
Offset 从小到 的顺序 前驱动。

4-19 offset写入记

Consumer消费消 时,还需要 定这 Consumer属


Consumer Group(如 4-20 示), Consumer Group消费一
Topic下的 有Partition数据。 Consumer实 属 一
Consumer Group, 一条消 被同一 Consumer Group里的一
Consumer实 消费,不同的Consumer Group可以同时消费同一条数
据。开 时需要 对应的代码 定Groupid。

4-20 不同的Consumer Group消费消
4.4.3 Spark Streaming集成Kafka
Spark Streaming可以 Receiver Direct两种 来集成
Kafka。

Receiver 下,Spark Streaming 为Consumer 取Kafka


的数据,将获取的数据存储 Executor内存 。 可 为数据
造成内存 出, 以 用预写日 机制(Write Ahead Log)将
出 分写入到HDFS上。 接收数据 ,当一 Receiver不 及时接收
有的数据时,再开 其 Receiver接收,它 须属 同一
Consumer Group,这样可以提高Streaming程序的 (如 4-21
示)。整 来说,Receiver 效率 低,容易 数据, 生 环
用 少。

4-21 Receiver 消费数据

Direct 下,Spark Streaming直接读取Kafka的topic 的


有Partition,获取Offset 。Spark Streaming 有一
Inputdstream,这 Dstream的 一 分区对应着Kafka 需要消费的
Topic的 一 分区,并且从Kafka 读取数据。 Direct 下,是
Spark Streaming 己 消费的Offset,消除 与Zookeeper不一致
的 况, 理 出 程 Exactly-once (如 4-22 示)。

4-22 Direct 消费数据

对比来看,Receiver 是 Zookeeper来 接Kafka 列的,


Direct 则直接 接Kafka 来获取消 。Receiver 消费
Topic 的offset是 存 Zookeeper ,Direct 消除 与
Zookeeper不一致的 况, Direct 可以 Spark Streaming应
用完全 到Exactly-once语义 况。

Spark Streaming对Kafka的集成有两 版本,一 是0.8版本,另


一 是0.10以上的版本,0.10以后 留 Direct 。这里介 的
是 Direct 开 Spark Streaming程序。
4.4.4  开 及工程化
实时 的 理 程主要包 4 分:

·读取数据 ,这里讲解消费Kafka 的数据;

·解 数据,即解 消费的Kafka数据;

·将解 后的数据存储到 定位 (如MySQL、HDFS、HBase


);

·存储消费的Offset,Direct 下需要 存消费到的位 。

1.主函数

首先导入 需的 赖:

import com.alibaba.fastjson.JSON
import com.utils.{KafkaParaUtils, ParamsUtils, SparkUtils}
import org.apache.spark.streaming.kafka.HasOffsetRanges
import org.joda.time.DateTime

主函数里,首先创建一 StreamingContext对象,这是Streaming
功 的主要入 。StreamingContext对象从现有SparkConf对象 创
建。这里设 batch时 隔为5秒。

object MainWorkflow {

def main(args: Array[String]): Unit = {


val sparkConf = new SparkConf().setAppName("STREAMING-WORKFLOW ")
.set("spark.testing.memory","2147480000")
.set("spark.streaming.kafka.maxRatePerPartition","200")
val sc = new SparkContext(sparkConf)
val ssc = new StreamingContext(sc, Seconds(5)) // 时 隔5秒
// 入Kafka的Topic,从Kafka 取数据
val message = new
SparkUtils(ssc).getDirectStream(ParamsUtils.kafka.KAFKA_TOPIC)
// 记 offset 移
message.foreachRDD( rdd => {
println(" =====================> count: " + rdd.map(x => x + "1").count())

val offsetRanges = rdd.asInstanceOf[HasOffsetRanges].offsetRanges // 获取



/**
* OffsetRange 是对topic name、partition id、fromOffset(当前消费的开始 移)、
untilOffset(当前消费的 束 移)的封装
* * 以OffsetRange 包 的 有:topic名字、分区ID、开始 移、 束 移
*/
// 更新 移
KafkaParaUtils.updateOffset(offsetRanges, ParamsUtils.kafka.KAFKA_GROUPID)
// 印 移
println("OffsetRange =====> ")
for (offset <- offsetRanges) {
println(offset.topic, offset.partition, offset.fromOffset,
offset.untilOffset)
}
}

// 对Message的 务 理,下 代码详细介

// 开始计
ssc.start()
ssc.awaitTermination()
}
}

上面的程序 ,将从Kafka 读取的数据赋给Message, 后记


Offset的 移 。这里 印出Offset 移 包 Topic主题、分
区id、开始 移 束 移 (如 4-23 示)。

4-23 印出当前消费的topic是“countly_imp”,partitionid
为0~11, 三列记 的是本次消费前的 移 , 列记 的是本次
消费后的 移 。

将从Kafka 获取的数据进行 务 理,解 后存入 定的库表


。示 代码如下:

// 务 理
val parameter = message.flatMap( line=> {
// 来
val src = try{
JSON.parseObject(line._2).getJSONObject("c").get("src")
} catch {
case ex:Exception => "(unknown)"
}

val cookieid = try {


new
DateTime(JSON.parseObject(line._2).getJSONObject("i").getLong("timestamp")*1000).t
oDateTime //将Json字 化为相应的对象 .getString("kid")
} catch {
case ex: Exception => "(unknown)"
}
//组 成一 字
val data = src + "##" + cookieid
Some(data) //some是一定有 的, some.get获取 ,如 有 , 报 常
}).map(_.split("##")).map(x => (x(0),x(1)))

4-23 Offset 移

2.从Kafka 读取数据

上面的主函数 定义 从Kafka 读取数据的方


getDirectStream:

val message = new SparkUtils(ssc).getDirectStream(ParamsUtils.kafka.KAFKA_TOPIC)

接下来 代码介 getDirectStream方 的实现方 。

消费 消费Kafka的Offset数据记 Zookeeper , 开
Streaming程序消费Kafka数据时,先从Zookeeper 最近一次消费
的Offset位 ,如 有记 当前Topicid+Groupid消费 消费Offset的
位 ,则从记 开始 消费Offset。如 有记 ,则从当前
Offset最 开始消费。代码 实现如下:

class SparkUtils(ssc: StreamingContext){


def getDirectStream(topics: String): InputDStream[(String,String)] ={
val groupId = ParamsUtils.kafka.KAFKA_GROUPID
// 获取offset位
val fromOffsetMap = KafkaParaUtils.readOffSet(groupId, topics.toString)
println(s"fromOffsetMap----------------==>${fromOffsetMap.size}")
val size = fromOffsetMap.size // 读取到的Offset 小
// 计 Offset存储记 的 小,如 有记 则从记 消费Offset,如 有记 则从Offset当前位
最 开始消费
val inputDS : InputDStream[(String, String)] = if (size > 0){
val messageHandler = (mmd: MessageAndMetadata[String,String]) => (mmd.key,
mmd.message)
KafkaUtils.createDirectStream[String, String, StringDecoder, StringDecoder,
(String,String)](
ssc, ParamsUtils.kafka.KAFKA_PARAMS, fromOffsetMap, messageHandler)
} else {
KafkaUtils.createDirectStream[String, String, StringDecoder, StringDecoder](
ssc, ParamsUtils.kafka.KAFKA_PARAMS, topics.split(",").toSet)
}
inputDS
}
}

上 从Zookeeper 获取Offset位 的方
KafkaParaUtils.readOffSet的实现 如下:

// 读取Kafka的Offset 移
def readOffSet(groupId:String, topic:String): Map[TopicAndPartition, Long] = {
println("------------> 读取 移 ")
val zkClient = getZKClient
// Kafka分区
val OffsetMap = collection.mutable.Map.empty[TopicAndPartition, Long]
try {
val partitionSeq = KafkaFunction.kafkaPartitionByTopic(zkClient, topic)
partitionSeq.map { p =>
// 默认 径
// println(s"zKGroupTopicDirs:
${KafkaFunction.zKGroupTopicDirs(groupId,topic)}\t;") //zKGroupTopicDirs
val offsetPath = offsetPathFun(topic, groupId, p)
println(s"offsetPath: ${offsetPath}")

// 移 询
val offsetTP = KafkaFunction.offsetStatTuple(zkClient,offsetPath)
println(s"offsetTP:${offsetTP}")

if (offsetTP != null) {
OffsetMap.put(TopicAndPartition(topic, p), offsetTP._1.toLong)
}
}
} finally {
zkClient.close()
}
OffsetMap.toMap
}

对应 ,将消费后当前的Offset 移 存储到Zookeeper ,实现


如下:
//更新 移
def updateOffset(offset:Seq[OffsetRange], groupId:String): Unit ={
val zkClient = getZKClient
try {
offset.foreach{ off =>
val offsetPath = offsetPathFun(off.topic, groupId, off.partition)
println(s"offsetPath: ${offsetPath}")
KafkaFunction.updatePersistentData(zkClient, offsetPath, off.untilOffset)
}
} catch {
case ex: Exception => ex.printStackTrace()
} finally {
zkClient.close()
}
}

开 调试完成后,将Scala工程 jar包并提 Spark 务。可看到


Streaming实时读取 上数据(如 4-24 示)。

从上面的监控 可以看出,Streaming程序设定为 20s 取一


次kafka数据,目前已运行16小时,完成 2996 次数据的消费。
表 ,“Input Rate”代表 秒接收数据的数 ,目前 致20~30/
条 秒;“Scheduling Delay”代表调度延 时 ,目前实时消费数
据还 有延 ;“Processing Time”代表 理 次数据 用的时

4-24 Streaming yarn监控
4.5 用 特征库开
为进一步从 度 富用 特征, 掘用 的相关行为,除
开 用 ,一 还 开 用 的特征库。一方面为 化
推荐、 准营 、 分 应用提 层数据,另一方面也可以
削减不同 特征 建时的冗 加工。

单来说,用 特征库就是对用 一次的不同行为(如 览、


收藏、搜 、购 )及该行为对应的 ( )进行详细
的记 ,以 从用 的行为特征 掘用 的 好。与开 用
相比,用 特征库可以对数据进行 计,从 度分 用 特
征, 用 则“相对静 ” 记 用 当前的状 。

如,用 常 览 购 奶 、尿不 、婴儿 ,则她


可 是一 孩子的妈妈;用 常 览、收藏、 搞笑、 子 视
频,可用 掘用 的内容 爱 好;用 对女装、 甲 的
览、购 、收藏 行为数据, 用 别分 的 掘 时 有效。
用 画像建 的 程 ,为 高效 掘用 特征,需要进行用 特
征库的规划 开 。
4.5.1 特征库规划
用 与 相关行为的日 数据包 用 对 行为的明细。
下面 一 用 特征库的 建 进行说明。该用 行为特征库规
划ER 如 4-25 示。

4-25 用 行为特征库规划ER

根据应用需要,创建表dw.cookie_feature_event_append来 建
用 特征,表 如表4-2 示。

表4-2  建用 特征表
·cookie_id:用 访 id。

·goods_id: id,用 行为对应的 。

·goods_name: 名称,用 行为对应的 。

·tag_type: ,可以 归属的三 进行划分,


如 戏本、 薄本、机 盘 表示不同的3C 。

·event_value:用 当日行为次数 计 ,如用 日 览


牌 记本电 3次,该字 记 为3。

·data_date:数据日期, 日进行分区。

·act_name:用 行为事件名称,如 击、搜 、提 。

该表 的act_name事件名称对应的数据来 可 致分为3种 :

1) 日 数据:用 访 页面时 击 、搜
关 词 日 上报记 ;

2)访 日 数据:用 访 页面,访 时 可以


从访 日 数据 掘;

3)订单数据:用 订单及订单里面的 。

其 ,事件名称可以 一 表来记 用 不同的行为事件,


行为事件划分 越细,用 平台的行为捕捉 越全面,如表4-3
示。
表4-3 记 用 不 行为事件的 表
4.5.2 数据开
数据开 程 ,主要从订单表、访 日 表、 日 表 对
用 当日的行为(加购、 击、 览、 ) 取数据, 后
加 到用 特征库对应表(本
dw.cookie_feature_event_append)的当日分区下,如 4-26 示。

4-26 用 行为特征库开

本 ods.page_event_log是 日 表,从 日 表 获
取用 击相关行为的事件;从订单表dw.order_info_fact 获取
cookieid当日与相关的订单数据;从cookie的访 日 表
ods.page_view_log 获取cookieid当日访 详 页相关数据。

根据用 行为事件进行数据开 ,分别插入用 行为特征库 ,


分代码示 如下(scala语言):

1.用 加购行为带来的

// 用 加购行为带来的
val AddToBagBehavior = (dateStr: String) =>
s"""
| INSERT INTO dw.cookie_feature_event_append PARTITION(data_date='${dateStr})
| SELECT t1.cookieid AS cookie_id,
| t1.product_id AS tag_id,
| t1.product_name AS tag_name,
| 'product' AS tag_type_id,
| count(1) AS act_num,
| t2.eventkey AS act_name
| FROM dw.order_info_fact t1
| INNER JOIN ods.page_event_log t2
| ON (t1.cookieid=t2.cookieid and t1.product_id=t2.product_id)
| WHERE t2.data_date='${dateStr}'
| AND t1.cookieid <> ''
| AND t1.product_id <> ''
| AND t2.eventkey IN
| ('$addtobag_click', // 加购 击
| '$addtobag_picture_click ', // 加购 片 击
| '$shopping_minus_click ', // 购物 击减号
| '$shopping_plus_click ', // 购物 击加号
| '$addtobag_submit_click', // 加购物 提
| '......')
| GROUP BY t1.cookieid,
| t1.product_id,
| t1.product_name,
| t2.eventkey
""".stripMargin

2.用 击行为带来的

// 击行为事件
val ClickBehavior = (dateStr: String) =>
s"""
| INSERT INTO dw.cookie_feature_event_append PARTITION (data_date='${dateStr})
| SELECT cookieid AS cookie_id,
| product_id AS tag_id,
| product_name AS tag_name,
| 'product' AS tag_type_id,
| count(1) AS act_num,
| eventkey AS act_name
| FROM ods.page_event_log
| WHERE data_date='${dateStr}'
| AND cookieid <> ''
| AND product_id <> ''
| AND eventkey IN
| ('$product_click', // 物 击
| '$pageview_brand_click', // 详 页 牌 击
| '$pageview_brandgoods_click', // 详 页 牌推荐 击
| '$pageview_details_click', // 详 页detail 看
| '$pageview_gallery_click', // 详 页 片 击
| '......')
| GROUP BY cookieid,
| product_id,
| product_name,
| eventkey
""".stripMargin

3.用 搜 行为带来的
// 搜 行为事件
val SearchBehavior = (dateStr:String) =>
s"""
| INSERT INTO dw.cookie_feature_event_append
PARTITION(data_date='${dateStr})
| SELECT cookieid AS cookie_id,
| product_id AS tag_id,
| product_name AS tag_name,
| 'product' AS tag_type_id,
| count(1) AS act_num,
| eventkey AS act_name
| FROM ods.page_event_log
| WHERE data_date='${dateStr}'
| AND cookieid <> ''
| AND product_id <> ''
| AND eventkey IN
| ('$search_product', // 搜 击
| '$search_result', // 搜 关 词 击
| '......')
| GROUP BY cookieid,
| product_id,
| product_name,
| eventkey
""".stripMargin

提 Spark 务 行后,数据刷到用 特征库对应表(本


dw.cookie_feature_event_append)可看到数据 如 4-27 示。

4-27 用 行为特征库数据

下面 两 询 子。

1: 询近7日 览 (id=6926512)详 页 10次的用


, 取这 分用 对其进行 营 , 询语句如下:
select cookieid
from dw.cookie_feature_event_append
where data_date >= ‘20180201’
and data_date <= ‘20180208’
and event_name = ‘$goodsdetail_view’
and goodsid = 6926512
having sum(act_num)>=10

2: 询近7日 览、收藏、关 “ 婴” 的用 ,
取这 分用 对其进行消 推送营 , 询命令如下:

select cookieid
from dw.cookie_feature_event_append
where data_date >= ‘20180201’
and data_date <= ‘20180208’
and tag_type = ‘ 婴’
and event_name in
(‘$goodsdetail_view’,‘$wishlist_add’,‘$goods_click’,‘$addtobag_click’)

用 特征库,数据分 师 数据开 可以从 度


取用 行为数据进行 掘。

特征库的开 程 ,除 从用 度开 特征库,同样也
对 、 家 开 相应的特征库。 特征库可以更方 对用
、 、 家建 ,并分 特征及进行 应用。
4.5.3 其 特征库规划
除 要对用 特征库进行开 ,也需要 本公司的 进行特
征库的规划与开 。

下面提 一种 特征库的开 度设计方 ,如表4-4 示。


特征库的开 可以从 目、价 、曝光 、 击、加购、
、 额、评论、退货 度展开。

表4-4  特征库设计方 示
4.6  权重计
用 平台上的不同行为具 到用 层面有着不同的行为权
重。 本 景 ,用 购 的行为权重要比用 加到购
物 、收藏 、 览 的行为权重 次要高。具 到
层面,需要用 画像建 与运营 密切 , 务 景
给不同的行为 定权重( 本 是 杂程度越高的行为价 越
),同时需要 虑 本 全 的权重属 。下面介
主观权重 分 TF-IDF 的 权重计 方 。
4.6.1 TF-IDF词空
TF-IDF是一种 计方 ,用以评 一 字 词相对 一 文件集
一 语料库 的其 词语的重要程度。字词的重要 随着它 文件
集 出现的次数的 加成正比 加,同时随着它 语料库 出现的频
率成 比下降。 本章介 的 ,对 用 来说,其 上同
一 出现的次数越 ,该 对 这 用 来说越重要,该
全 用 的 有 生的 集 出现的次数越 ,该 的重
要 越低。

用TF-IDF方 来表示 (Tag,T) 用 (User,P) 的


关 :其 w(P,T)表示一 T被用 记 用 P的次数,
TF(P,T)表示这 记次数 有 记用 P的 占的比 ,
TF计 公 如下:

一定程度上,这 比 映 用 P被认为与 T有关 的度


。这 度 越 说明 更 况下用 P与 T 的关 越
密。

IDF(P,T)表示 T的稀 程度,即这 全 用 的


有 出现的 率。对一 T来说,如 它本 出现的 率就比
小,却被用来 记用 P,这 用 P与 T 的关 更加
密。IDF的计 公 如下:
这样,用 P T 的关 数为TF(P,T) IDF(P,T)
的 积,计 公 为:

rel(P,T)=TF(P,T)×IDF(P,T)

一 单的 子:如 4-28 示,A~C代表用 ,a~e代表


,数字代表A~C用 上该 的 数。以用 A为 ,A 上有a、
b、d、e 4 共4+3+0+5+3=15 ,a 对A用 的TF 为4/15。全
用 共有a 4+5+0=9 ,全 用 的全 为
4+5+3+6+5+5+6+3+4=41 ,a 的IDF 为41/9。A用 上的a
TF×IDF 为4/15×41/9=1.21。

至此, TF-IDF 出 用 与 的权重关 。 是


此时计 用 的权重还 有 束,当前的 权重是未 虑 务
景, 虑用 与 的关 出来的,这显 是不 的。

4-28 TF-IDF 计 权重示
4.6.2 时 衰减 数
当用 数据 到 的密集程度后,用 上 的 对应的属
表现出 高的稳定 ,这种稳定 与用 期行为 成的 真
实特征相匹 。 是也存 变化的适应 的 题。

如, 用 主要从事软件开 , 此其 电 站上
的搜 、收藏、购 行为主要集 与 程相关的内容上。 ,
如 该用 近期内 为运营 岗位,则其近期的 览与搜 就 突变
为与运营相关的内容。 是,将用 画像的属 描 从 程 为运营
并不 由此立刻实现,仍需要 时 的用 行为的积 ,直至 运营
下积 比 程更 的子分 。 是 换期 , 仍对用
推送 程相关 ,这显 离 用 的真实关 内容。

为解决这 题,我 入 时 衰减这 参数,根据 生时


的先后为用 行为数据分 权重。时 衰减是 随着时 的推移,用
的历 行为 当前行为的相关 不断减 , 建立与时 衰减相关
的函数时,我 可套用牛顿冷却定 数学 。牛顿冷却定 描 的
景是:一 的物 一 度比其 度低的环 下,这
的物 的 度是要降低的, 物 的 度要上升,最后物 的
度 的 度 到平衡, 这 平衡的 程 , 物 的 度
F(t)随着时 t的 现 数 衰减,其 度衰减公 为:

F(t)=初始 度×exp(–× 隔的时 )

其 ,为衰减常数,可 归计 出。 如: 定45分 后
物 度为初始 度的0.5 ,即0.5=1×exp(–×45),
=0.1556。

用 画像的应用 ,用 的 行为 随时 衰减, 行
为不 随时 衰减。一 来说,用 操 的 杂程度越高,其行为随
时 衰减的 越小,我 可视该 行为不随时 衰减(如下单、
购 行为)。对 随时 衰减的行为, 计 行为权重时需 虑时
,衰减方 可套用牛顿冷却定 ;对 不随时 衰减的行为则不
虑时 的 ,如表4-5 示。
表4-5 用 行为受时 的
4.6.3  权重
用 的权重最终还是需要进一步 的 务 景、
离当前时 、用 行为 生该 的行为次数 ,最终 到用
权重的 分公 :

用 权重=行为 权重×时 衰减×用 行为次数×TF–IDF计


权重

公 参数的 义如下:

·行为 权重:用 览、搜 、收藏、下单、购 不同行


为对用 言有着不同的重要 。一 言,操 杂度越高的行为
权重越 。该权重 一 由运营 数据分 主观给出。

·时 衰减:用 行为受时 不断减 ,行为时 现


越远,该行为对用 当前行为来说 义越小。

·行为次数:用 权重 计,用 与该 生的
行为次数越 ,该 对用 的 越 。

·TF-IDF计 权重:由 对用 的重要 与该


全 的重要 的 积 出 的客观权重 。

权重的计 公 ,可以对用 特征库


(dw.cookie_feature_event_append)的行为数据计 权重,
出与用 行为相关 最 的 。
4.7  相 度计
根据 的相关关 进行 也是画像开 常 到的一
题。如 务 景对 进行有效 ,不同的公司 务
景有不同的 理方 。本 内容 一 来介 如 对用
上的 建“同现矩阵”的方 对 进行 。
4.7.1  景
同现矩阵是 的关 程度,这种关 程度由用
上的 决定。这里的同现是 同时出现,即一 用 被
上A 的同时被 上B 。如 有 用 同时被 上A、B ,
么A、B 可 种相关 ( 4-29 示)。

4-29  相关 计 (示 )

从 4-30 可以看到,当前有 用 , 用
上 被 上 一 。 B C 用 上同时出现,
此可以初步认为 B C存 一定程度上的相关 。
熟知的“ 尿布”的 子,一家 市 现 用 消费 同时
购 尿布, 是将尿布 摆 一 出 , 现这两种
的 加 。该 景 这两种 / 同时出现 用
的 上, 么我 可以初步认为这两种 / 存 一定程度上的相
关 。
4-30  用 到 相关 (示 )

本 ,用 医疗 上的行为 给其带来诸 ,
的 可以划分为医生、医院、科室、疾病、药 不同种
。现 需要对疾病 到其对应的科室下面。

根据同现矩阵的方 ,对4.5 创建的用 行为特征库 数据进行


度 掘,根据用 行为 的相关 ,对疾病 进行 。

用 行为特征库表 设计:

CREATE TABLE `dw.cookie_feature_event_append`(


`cookie_id` string COMMENT 'cookie_id',
`tag_id` string COMMENT ' id',
`tag_name` string COMMENT ' 名称',
`tag_type_id` string COMMENT ' 务 来划分 ',
`act_num` string COMMENT '行为次数',
`act_name` string COMMENT '事件名称 如 / 赏/加购/ 击/收藏/ 览 行为')
COMMENT '用 行为特征库'
PARTITIONED BY (`data_date` string COMMENT '数据日期')
4.7.2 数据开
首先从用 行为特征库 取 一时 内被 上“疾病”
的用 明细数据,明细数据 包 用 id、疾病 关

create table dw.tag_relation_function_01


as
select cookie_id,
tag_id,
tag_name,
act_num,
tag_type_id,
act_name
from dw.cookie_feature_event_append --用 行为特征库
where data_date >='2019-01-01'
and data_date <='2019-04-01'
and tag_type_id ='疾病' -- A 疾病

取同一时 内被 上“科室” 的用 明细数


据。

create table dw.tag_relation_function_02


as
select cookie_id,
tag_id,
tag_name,
act_num,
tag_type_id,
act_name
from dw.cookie_feature_event_append --用 行为特征库
where data_date >='2019-01-01'
and data_date <='2019-04-01'
and tag_type_id ='科室' -- B 科室

计 “疾病” 下 疾病 对应的用 数。

create table dw.tag_relation_function_03


as
select tag_id,
tag_name,
count(distinct cookie_id) user_num
from dw.tag_relation_function_01
计 “科室” 下 科室 对应的用 数。

create table dw.tag_relation_function_04


as
select tag_id,
tag_name,
count(distinct cookie_id) user_num
from dw.tag_relation_function_02

计 同时被 上疾病 科室 的用 数的同现矩阵(见


4-31)。

4-31 疾病与科室的同现矩阵(示 )

本 如下:

--计 疾病、科室两 共同关 数的同现矩阵:


create table dw.tag_relation_function_05
as
select t.tag_id_1, -- 疾病 id
t.tag_name_1, -- 疾病 名称
t.tag_type_id_1, -- ‘疾病’
t.tag_id_2,
t.tag_name_2, -- 科室 名称
t.tag_type_id_2, -- 科室
t.num -- 共有 少
from (
select t1.tag_id as tag_id_1,
t1.tag_name as tag_name_1,
t1.tag_type_id as tag_type_id_1,
t2.tag_id as tag_id_2,
t2.tag_name as tag_name_2,
t2.tag_type_id as tag_type_id_2,
count(distinct t2.user_id) as num
from dw.tag_relation_function_01 t1
cross join dw.tag_relation_function_02 t2
where t1.tag_id <> t2.tag_id
group by t1.tag_id,
t1.tag_name,
t1.tag_type_id,
t2.tag_id,
t2.tag_name,
t2.tag_type_id
) t

用 相 度函数计 两两 的相关 。 相 度函数


空 两 角的 来衡 两 差 的 小,
越接近1,表明两 的相 越 。 本 景 一 单
子: 疾病 被 10000 用 上, 科室 被
20000 用 上,有5000 用 的 上同时有该疾病 科室
,则该疾病 科室 的相 度为5000/sqrt(10000×20000)。
本 如下:

-- 用 相 度函数计 两两 的相关
create table dw.tag_relation_function_06
as
select t1.tag_id_1, --疾病 id
t1.tag_name_1, --疾病 名称
t1.tag_type_id_1, --疾病
t2.user_num_1, --疾病 数
t1.tag_id_2,
t1.tag_name_2,
t1.tag_type_id_2 ,
t3.user_num_2, --科室 数
t1.num as num, --同时有两 的用 数
(t1.num/sqrt(t2.user_num_1 * t3.user_num_2)) as power,
row_number() over(order by (t1.num/sqrt(t2.user_num_1 * t3.user_num_2))
desc) rank
from dw.tag_relation_function_05 t1
left join (select tag_id,
user_num as user_num_1
from dw.tag_relation_function_03 --疾病 对应的用 数
) t2
on t1.tag_id_1 = t2.tag_id
left join (select tag_id,
user_num as user_num_2
from dw.tag_relation_function_04 --科室 对应的用 数
) t3
on t1.tag_id_2 = t3.tag_id

出与 疾病 相关 最 的科室 ,即将该疾病
归 到相关 最 的科室下面。 row_number()方 出权重
最 的科室 顶, 行如下。
-- row_number()方 出权重最 的科室 并 顶
create table dw.tag_relation_function_07
as
select tag_id_1, --疾病 id
tag_name_1, --疾病 名称
tag_id_2, --科室 id
tag_name_2, --科室 名称
power
from (select tag_id_1,
tag_name_1,
tag_type_id_1,
tag_id_2,
tag_name_2,
tag_type_id_2,
power,
row_number() over(partition by tag_id_1 order by power desc) row_id
from dw.tag_relation_function_06
) t1
where t1.row_id=1

最后可以看到, 小 的 试数据 将疾病 归 到对应科


室下面的效 还是比 准确的(见 4-32)。
4-32 疾病与科室 的相 度计
4.8 组 计
组 计 是画像开 的一 重要 。本章前面几 小
讲的 是如 开 用 上的一 ,当 务方根据 务规则应
用 时,是需要组 来创建对应的用 的,此时需要
应用到组 计 。
4.8.1 应用 景
这里看一 组 计 的应用 景, 4-33 用 A、B、C、
D、E已 被 上 己特征的 , 务 给“高价 用
组” 放一 券 消费。根据运营 验,定义 “高价
用 组”的特征为:①女 用 ;②25~35岁 ;③ 计消费5
次以上;④ 计消费500元以上;⑤ 度 以上的用 。可以
看到同时 这 条件的用 为用 B、用 C、用 E。组 计
的 务就是根据 务 的规则,计 出 对应条件的用

4-33 组 计 景

组 计 的实现 , 来说分为3 程:

·读取不同组 的计 规则;
·将 规则 接成接 入参数的 询命令, 接 方 进
行 询;

·接 询计 时, Elasticsearch 询 这 条件的用
id, 用 id 为rowkey去HBase 询这 用 上的 。
4.8.2 数据计
务 画像 端可以组 定 (见 4-34),对
应 关 数据库 将 记 该条 规则包 的用 。

4-34 组 定

记 定 规则的表 主要包 以下主要内容( 4-35):

· id:创建该条 规则对应的 一id 识。

· 名称:该条 规则 务定义上的名称。

· 规则: 组 规则 包 的 及 。

· 数 :该 对应的数 。

·创建时 :该 规则的首次创建时 。
· 改时 :该 规则的最近一次 改时 。

·是 应用:该 是 应用到 上。

4-35  组 规则示

调用接 询时,将 规则 接成字 ,


Elasticsearch 询 该规则的用 id。 如 对上面id
为“100003”的 ,将其规则 接成“ATTRITUBE_U_06_001,
6||ACTION_U_05_003,3||CONSUME_U_05_003,15”, 为参数 入接

本 介 一种组 计 用 的解决方 , 来说包


两 程:首先从关 库表 (如MySQL)读取 务 定 的
规则,将 规则 接成接 的 入参数, 后 接 请
Elasticsearch的方 询对应的用 id。
4.9 数据服务层开
数据最终的目的是 出数据 库,应用到 务 营 景
。一 开 完画像后,还需要 数据 务 的
, 化的方 将 数据应用到 务 去。这里需要
的服务层包 离 服务层 服务层,其 离 服务层将ETL后的用
数据推送到对应 务 , 服务层以RESTful API方 提 接
服务,可支持 化推荐、营 推送、 特征库 景。

几 典 的应用 景包 :

1)短 营 :可以 用 画像的 定义 服务,进行重 用


的广 /消 消 推送/短 / 件营 。

2) 件营 :可以 不同用 ,进行 化有效的 营


,同时 服务上也可以 已 的用 数据,提 差 化
的客服/物 / 动 服务。

3)风控 :可以根据用 别, 为风控 规则 擎


的 入。

4)数据分 :可以分 不同 的行为特征,提 分 决 。

5)BI数据:可以监控核 用 的变化,为上层决 提 数据
础支持。

下面以 介 种常见的 运营 ,及如 将 数


据与这 种 务 。后文的7.4 讲 画像 化的 ,
本 内容主要讲解 后的工程化实现方 , 读本 内容时可
7章来看。

用 画像 数据服务层除 力 省、 程 化
方面带来诸 利 , 营 (如同时 短 、 件、消 推
送 ) 动时,可以 设 排 已 其 营 的
用 ,排除对用 的 次 ,同时 省 的营 费用。
下面将介 两种常见的 务 的方 。
4.9.1 推送至营
如 公司有 一的营 ,则 需要应用到服务端的数据 一
入服务层对应的数据库 。一 来说,服务层 用HBase、
Elasticsearch 进行数据存储。

一: 用站内广 对用 进行 化弹窗、广 位的轮


播展示是一 常见的应用 景。 如 弹窗 用 推送 券、
减 包, 广 位轮播 用 展示近期 览 的相关
,如 4-36、 4-37 示,有效 进用 订单 化。

二:机端App有消 推送(push)的功 ,消 推送是


运营 用 的重要方 一(如 4-38)。应用的出 可以
好 帮助 提高DAU GMV的 化,如 应用不 当也 让用 对
到 。 此如 好消 推送营 的 略, 对目 用
准推送消 ,对 提升用 验尤为重要。这里, 画像 可实
现 对不同用 推送不同的消 。

三:短 是常见的客 营 一, 4-39为一 典 的


短 营 景。 动 日常运营 , 务 将 好的文
推送给对应 ,用 收到短 击 接可 到详 页 App。
细化运营下可有效 进订单 化。
4-36 App弹窗推送内容 ( “ 刻App”)
4-37 App轮播广 位推送内容 ( “ 宝”)

4-38 消 推送(push)内容
4-39 短 营 用 景

工程开 上,可将 ETL后的用 数据离 同步到HBase


数据库, 请 接 的方 提 服务。 前文3.3.3 有详细
介 。
4.9.2 接 调用服务
服务层数据一 接 调用的方 为上层应用提 支持,一
是 用 三方平台提 的服务时用 。 如 用 三方平台提 的
送短 、 件 服务时, 接 方 调用 数据。

接 调用时需要定义好接 的请 、请 参数、 参数
关 。

(1)接 说明

本接 主要用 支持 询用 。

(2)请 参数

用 询的 ,如 说 入用 id 数据的时 询该
用 上的全 ,则参数为用 id 时 。

请 参数示

{
"data_date":"20190101",
"id":"e598027d-5412-4e7b-84a2"
}

(3)接

如接 为“http://xxxx.api.com/userprofile”,上面的
请 接为“http://xxxx.api.com/userprofile?
data_date=20190101&id=e598027d-5412-4e7b-84a2”。

(4)调用方
一 以GET方 送请 。

(5)

常见的 状 (code):

下面我 看一 接 请 用 上的 , 的数据:

{"code":"200",
"data":
{
"userprofile":{
"id": "e598027d-5412-4e7b-84a2",
"tags": [
{
"tagid": "ATTRITUBE_U_06_001",
"tagweight": 6
},
{
"tagid": "ATTRITUBE_U_02_001",
"tagweight": 1
},
{
"tagid": "ACTION_U_05_003",
"tagweight": 3
},
{
"tagid": "ATTRITUBE_U_01_001"
},
{
"tagid": "ACTION_U_05_003",
"tagweight": 1
},
{
"tagid": "CONSUME_U_05_003",
"tagweight": 15
},
{
"tagid": "CONSUME_U_05_003",
"tagweight": 5
}
]
}
}
}

上面 接 入用 id的方 请 用 上的 , 组
的应用 ,同样可以 入需要组 的 及 的关 ,
接 方 询同时 这 对应的用 。

实际开 需要 本公司 务特 开 环 来进行。


4.10 GraphX 计 用

4.10.1  计 理论及应用 景
Spark GraphX是分布 计 , Spark平台提 对 计
的 单且 富的接 ,以 对分布 理的需 。

对GraphX视 的 有计 ,最终 化为其关 的Table视 的


RDD操 来完成。 工程实 ,存 需要计 二度关 用 的 景,
即用 与用 其共同的好友 到 的二度关 熟 ,这种
对 的 掘计 可 助Spark GraphX完成。。

GraphX提 顶 (Vertex)、 (Edge)、三元组(Triple)三


种视 ( 4-40),GraphX 计 也 这三种视 上完成。顶 包
顶 id 顶 属 ; 包 顶 (srcid),目 顶 (dstid)
属 (property);三元组是对顶 的 展,将顶 的属
存为一 RDD[EdgeTriplet[VD,ED]],可 下面SQL表 :

SELECT src.id, dst.id, src.attr, e.attr, dst.attr


FROM edges AS e
LEFT JOIN vertices AS src, vertices AS dst
ON e.srcId = src.Id AND e.dstId = dst.Id

4-40 GraphX 属 ( Spark GraphX官 )

下面 Spark GraphX官 上的 来初步 解 的创建 程。


设需要 建一 由不同用 组成的属 ,顶 属 包 用 id
用 的 (Property), 属 包 顶 (SrcId)、目 顶
(DstId) 的关 (Property)( 4-41)。
4-41 GraphX示 属 ( Spark GraphX官 )

根据上 顶 的关 ,可创建顶 对应的RDD:

val users: RDD[(VertexId, (String, String))] =


sc.parallelize(Array((3L, ("rxin", "student")), (7L, ("jgonzal", "postdoc")),
(5L, ("franklin", "prof")), (2L, ("istoica", "prof"))))

以及 对应的RDD:

val relationships: RDD[Edge[String]] =


sc.parallelize(Array(Edge(3L, 7L, "collab"), Edge(5L, 3L, "advisor"),
Edge(2L, 5L, "colleague"), Edge(5L, 7L, "pi")))

顶 创建 :

val defaultUser = ("John Doe", "Missing")


val graph = Graph(users, relationships, defaultUser)

进一步可 用graph.vertices graph.edges方 对 进行顶 、


的计 。
// 计 有 少 用 的属 为postdocs
println(graph.vertices.filter { case (id, (name, pos)) => pos == "postdoc"
}.count)
// 计 少条 的 src > dst
println(graph.edges.filter(e => e.srcId > e.dstId).count)

行两条println命令可看到 印的计 为1,即 对 有


顶 的 有一 用 的顶 属 为"postdoc", 有一条
(Edge(5L,7L,"pi"))的 顶 目 顶 。

GraphX 可 种方 创建一 。

·Graph(VertexRDD,EdgeRDD): 入顶 的RDD创建
,上面介 的 即用这种方 创建 。

·Graph.fromEdges:由 的RDD创建 , 动将 有顶 的属
设 为默认 。

·Graph.fromEdgeTuples:由 元组 生成 , 赋 为1, 动
创建 涉及的 有顶 并赋默认 。

·GraphLoader.edgeListFile: 解 ( 顶 、目 顶 )
的数据 到 接关 。下面一 介 的 将 用此种方 创
建 。

下面 一 实际 景 介 如 开 N度关 用 的列表。
4.10.2 数据开
实际 景存 用 登 同一 机上的 App,也存 同
一 用 机上登 该App的 况,这里初步认为 同一 机
上登 的用 是熟 关 , 这种熟 关 需要进一步 掘用
的二度熟 。即 用 朋友的朋友也有可 是该用 的 好友。
4-42 可初步推断:111、222、333 C 机上登 ,
相互熟 ,333 999 F 机上登 , 是熟 , 次
推。这样,我 可以根据用 这种相互 的熟 进行计 的二
度关 熟 。

4-42 用 登 机关 分布

计 景 ,需要将 4-42 左 用 登 机的这种


关 象成 的用 关 关 ,这种关 关 可视为一条 ,
左 一列数据代表 顶 (srcid), 一列数据代表目 顶
(dstid)。
对 务 进行 象后,需要 理 助 计 掘用 二
度好友的实现方 ,主要包 对主 (可视为 用 )的两次
历计 ( 4-43):

· 一次 历,获取本 的 有 居 ,即获取1 的 居
2、3、4;

· 二次 历,获取 有 居 的 居 ,将 的二度
居 进行 计。即获取2、3、4的 居 ,将其 给1。

4-43  计 二度好友

GraphX 核 操 是调用API:aggregateMessages,它负责
送消 ,以及 并收到的 消 。

下面 Scala 本来看 计 的实现 ,首先 主函数 调用


的 造方 ,其 入的数据文件“relations.txt”为 4-42
数据, 后 getSecondUserIds方 计 用 的二度关 用 列
表。 本 行如下:

import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.graphx._

object GraphxUser {
def main(args: Array[String]) {
val conf = new SparkConf()
conf.setAppName("Graphtx-Calculate-Userprofile")
conf.setMaster("local[*]")
val sc = new SparkContext(conf)

// 造
val graph=GraphLoader.edgeListFile(sc,"C:/Users/user/Desktop/relations.txt")
val graphxNeighborUser=new GraphxNeighborUser

// 二度关 用 列表
val neighborIds=graphxNeighborUser.getSecondUserIds(333,graph)
println("neighborIds: "+ secondIds.mkString(","))
}
}

GraphxNeighborUser对象 定义 getSecondNeighborIds方 用
计 用 的二度好友, 该方 嵌套调用getFristNeighborIds
方 获取用 的一度好友。 行如下:

import scala.collection.immutable.HashSet
import scala.collection.mutable.ArrayBuffer
import org.apache.spark.graphx.{Graph, VertexRDD}

object GraphxNeighborUser {
// 获取二度好友
def getSecondUserIds(id:Long, graph:Graph[Int,Int]) = {
getSecondNeighborIds(getFristNeighborIds(id,graph), graph)
}

// 根据用 id获取其一 居
def getFristNeighborIds(id:Long, graph:Graph[Int,Int])={
var fristIds=new HashSet[Long]() // 存储一 居的集
//aggregateMessages 送给 条 的 顶 的消
val firstNeighbor = graph.aggregateMessages[Int](triplet=>{
if(triplet.srcId==id ){
triplet.sendToDst(1) //给目 顶 送 记位
}
} ,(a,b)=>b ) // 顶 接收到的消

firstNeighbor.collect().foreach(
a=> fristIds+=a._1
)
fristIds
}

// 根据用 id获取其二 居
def getSecondNeighborIds(firstIds:HashSet[Long] , graph:Graph[Int,Int])={
val secondryIds = new ArrayBuffer[Long]() // 存储二 居的集
firstIds.foreach(id=>{
val secondNeighbors=getFristNeighborIds(id,graph) // 获取 一 居的二 居
secondNeighbors.foreach(
secondId=>secondryIds+=secondId)
})
secondryIds
}
}
行 务后根据下面 的 可知333的一 居包 111、222
999, 后将这三 一 居进一步 代获取这三 居的一
居, 后将二次 代后的 居数据 给333。二次 代的 居 包
111、222、333 一 居,需要对其进行 ,下面是获
的二次 代 居:

111 -> 222,333,444,555,666,777,888


222 -> 111,333,777
999 -> 333,777,000

最终获 333的二度好友列表:

444,555,666,777,888,777,777,000

从二度好友列表可以看出:

333 444的共同熟 数:1;

333 555的共同熟 数:1;

333 666的共同熟 数:1;

333 777的共同熟 数:3;

333 888的共同熟 数:1;

333 000的共同熟 数:1。

照共同熟 数排序后,可认为777是333的 熟 。

计 用 的 好友, 掘用 关 景 有 应
用, 如 3.1.4 的ID-MAP章 ,同样可 用 计 的方 来 掘
不同用 设 的关 。
4.11 本章小
本章是全 的重 章 ,介 画像 相关数据的开 工
应用 景 方面的内容,以 的 对 象的 方进行 详细介

其 4.1 至4.4 讲的是 数据开 是用 画像的 础 工


, 搭建好 后 进行后 的 分 面 应用层
的 营 。4.5 介 用 特征库的开 ,相比用 “相对静
” 记 用 当前的状 ,用 特征库可以对明细数据进行
计,从 度分 用 特征。4.6 用 特征库,提 一种
权重计 的解决方 。4.7 用 行为特征库 度 掘
的相 度关 。4.8 介 组 计 的实现 径, 组
定的 可以为 务 提 细化运营用 的 。画像
除 分 特征,更重要的是可以将数据 到服务层,
种 触 用 。4.9 介 如 数据到服务层提 应用
服务。4.10 Spark GraphX 计 的 介 如 用
的关 掘 的N度 熟 。
5章 开 调
关 Spark开 调 及Hive SQL 本调 的 博客已 有
,本章将 重讲解 开 画像 程 可 到的一 共 题,及
对应的解决方 。
5.1 数据 斜调
数据 斜是开 画像 程 常 到的 题,当 务 行一直卡
map 100%、reduce 99%,最后的1% 几 小时 行完时,这时
一 是 到 数据 斜。

题出现的原 是当进行分布 计 时,由 需要计


的数据 ,导致其 的reduce阶 务 行完成时,该 的
务还 有 行完成,造成其 待该 行完成的 况。比
如两 表 join的时 分key对应10条数据, 是 别几 key
对应 100万条数据,对应10条数据的task 行完成 , 对应
100万数据的key则要 行几 小时。

5-1 示的是一 典 的 子。

5-1 数据 斜 景
bb这 key 3 上有11条数据,aa cc 3 上分别有2
条 1条数据,这 数据 被 取到一 task上 理。 理bb这
task的运行时 可 是 理aa cc的task的运行时 数 ,整 运行
速度由最 的task决定。

下面介 两种解决数据 斜 题的方 。

方 一: 掉 斜数据

当少 key重 次数特别 ,如 这种key不是 务需要的key,可


以直接 掉。这里有一 日 表ods.page_event_log,需要
订单表dw.order_info_fact join关 。 行Hive的 程 现
务卡 map 100%、reduce 99%,最后的1%一直运行不完。 虑应该是
join的 程 出现 数据 斜,下面进行排 。

对 ods.page_event_log表 看出现次数最 的key:

select cookieid,
count(*) as num
from ods.page_event_log
where data_date = "20190101"
group by cookieid
distribute by cookieid
sort by num desc limit 10

将key 出现次数从 到少排序(如 5-2 示)。


5-2 日 表key 出现次数 排序

同样 ,对订单表dw.order_info_fact 看出现次数最 的key:

select cookieid,
count(*) as num
from dw.order_info_fact
group by cookieid
distribute by cookieid
sort by num desc limit 10

将key 出现次数从 到少排序(如 5-3 示)。


5-3 订单表key 出现次数 排序

从上面的 子可以看出,日 表 订单表 cookieid进行


join,当cookieid为0的时 ,join操 将 生142286×142286条数
据,数 如此庞 的 无 理 来。同样当cookieid为NULL
空 时也 出现这种 况, 且cookieid为这3 时并 有实际
的 务 义。 此 对两 表 关 时,排除掉这3 以后,就可以
计 出 。

方 二: 入随机数

数据 照 group by时, 将相同的key 需的数据 取到一


进行 , 当 组数据 时, 出现其 组已 计 完成
当前 务未完成的 况。可以 虑加入随机数,将原来的一组key强
制 分为 组进行 。下面 一 进行介 。

现需要 计用 的订单 , 行如下代码:

select t1.user_id,
t2.order_num
from (select user_id
from dim.user_info_fact # 用 度表
where data_date = "20190101"
and user_status_id=1
) t1
join ( select user_id,
count(*) as order_num
from dw.dw_order_fact # 订单表
where site_id in (600, 900)
and order_status_id in(1,2,3)
group by user_id

) t2
on t1.user_id = t2.user_id

用 度表 有2000万条数据,订单表有10 条数据, 务 未
化前 行 1 小时也 有 出 ,判断可 是出现 数据 斜。

订单表 key 数 , group by的 程 取到一


task上 行时, 出现其 task 行完毕, 待该task 行的 况。

这里可以将原本相同的key 加随机前 的方 变成
key,这样将原本被一 task 理的key分散到 task上先 一次
, 后去掉前 再进行一次 到最终 。 程如 5-4 示。

5-4 两阶

改后代码 行如下:
select t1.user_id,
t2.order_num
from (select user_id
from dim_user_info_fact
where data_date = "20190101"
) t1
join ( select t.user_id,
sum(t.order_num) as order_num
from (select user_id,
round(rand()*1000) as rnd,
count(1) as order_num
from dw.order_info_fact
where pay_status in (1,3)
group by user_id,round(rand()*1000)
) t
group by t.user_id
) t2
on t1.user_id = t2.user_id
5.2  并小文件
Spark 行“insert overwrite table表名”的语句时,由
程并行 HDFS写入且RDD默认分区为200 , 此默认 况下 生
200 小文件。

Spark 可以 用reparation coalesce对RDD的分区重新进行划


分,reparation是coalesce接 shuffle为true的实现。

Spark内 对 一 分区分 一 task 行,如 task ,


么 task 理的数据 小,这就 造成 程频 task 切
换,导致集 工 效率低下。为解决这 题,常 用RDD重分区函数
来减少分区数 ,将小分区 并为 分区,从 提高集 工 效率。

// 并插入用 宽表数据的分区
val executesqls = spark.sql(
"""
| select user_id,
| org_id,
| org_name,
| sum(act_weight) as act_weight,
| sum(cnt) as cnt
| from dw.peasona_user_tag_relation
| where user_id is not null
| and user_id <> 'null'
| group by user_id,org_id,org_name
""".stripMargin).rdd.coalesce(1)

val datardd = executesqls.map(row => {


val user_id = row.getAs[String]("user_id")
val org_id = row.getAs[String]("org_id")
val org_name = row.getAs[String]("org_name")
val act_weight = row.getAs[String]("act_weight")
val cnt = row.getAs[String]("cnt")
Row(user_id,org_id,org_name,act_weight,cnt)
})
spark.createDataFrame(datardd, StructType(Seq(
StructField("user_id", StringType),
StructField("org_id", StringType),
StructField("org_name", StringType),
StructField("act_weight", StringType),
StructField("cnt", StringType)
))).createOrReplaceTempView("user_act_info")

spark.sql(
s"""
| INSERT OVERWRITE TABLE dw.peasona_user_tag_relation
partition(data_date="$data_date")
| SELECT user_id,org_id,org_name,act_weight,cnt
| FROM user_act_info
""".stripMargin)
5.3  存 数据
Spark的一 重要的 力就是将数据持 化 存,这样 操
期 可以访 这 持 化的数据。当持 化一 RDD时, 的
其 分区 可以 用RDD 内存 进行计 , 该数据上的其 action
操 将直接 用内存 的数据,这样 其操 计 速度加 。对RDD
的 杂操 如 有持 化, 么一切的操 从 开始,一步
步往后计 ,不 用原始数据。

画像 ETL的时 ,对 一 计 可以不落磁
盘, 需 数据 存 内存 。 用Hive进行ETL时需要将一
计 落 时表 , 用完 时表后再将其删除。

RDD可以 用persist cache方 进行持 化, 用StorageLevel


对象给persist方 设 存储 别时,常用的存储 别如下 示。

·MEMORY_ONLY: 存储 内存 ;

·MEMORY_ONLY_2: 存储 内存 , 分区 集 两
上建立副本;

·DISK_ONLY: 存储 磁盘 ;

·MEMORY_AND_DISK:先存储 内存 ,内存不 的话存储 磁盘


其 cache方 同 调用persist()的MEMORY_ONLY方 。

画像 开 ,一 从Hive 读取数据, 后将需要


理的DataFrame 册成 存表。

这里介 一 开 画像 时 存 数据的 。

行如下代码:
// 读取原数据 下单用
val peopleRDD =
spark.sparkContext.textFile("C:\\Users\\king\\Desktop\\practice\\cookiesession")
.map(_.split(",")) // RDD[Array[String]]
.map( row => Row(row(0),row(1),row(2),row(3),row(4))) // RDD[Row]
peopleRDD.persist(StorageLevel.MEMORY_ONLY)
peopleRDD.createOrReplaceTempView(“user_base_info”)

这里将读取的用 数据 存 内存 并 册为一 视 。后 直
接从视 读取对应用 数据。 该Spark 务 行完成后, 放内
存,不需要 除该 存数据。
5.4 开 表
用画像 代开 的 程 ,初期开 完 后, 对
加工 的血 整理,可以 到 用相同数据 的 ,对这 分
,可以 加工 表 减 日画像调度 时 。

层设计前需要明确几 重要的 :

1)这 层对应的 务 景、 务目 是 么?

2) 务方有 这 层数据以后可以进行 度的分 ,


ETL时有 这 层数据可以减少对 数据的重 开 计 ?

3)这 务 景分 包 分 度 ?

4)同时面 务 景的 层不一定是好的 层。

开 表前,首先需要 理目前用 计 时 赖的上


数据 库的表(如 5-5 示) 的血 赖(如 5-6 示)。

5-5 用 赖上 数据 库的表(示 表名)


5-6 用 血 理(示 表名)

如 开 程 ,可以 dwd层的日分区存放当 日期对应的订


单, dws层 为服务层,其日分区用 存放当 日期对应的全 数
据。这样, 日常调度计 的 程 ,可 免 dwd层重 计 历 数
据, 需计 当 的新 数据,既 省 ETL时 ,也不 服务层
的数据。

对用 的血 进行 理, 到共同 赖的上 数据。


5.5 本章小
前 的项目开 程 ,ETL调度时 是一 难解决
的“瓶颈”, 的调度 完计 、 验预警、计
、 验预警、同步到服务层 环 后往往需要几 小时,最后
提 到服务层数据时也比 晚 。 这 程 为 减少调度时 ,
我 也 尝试,包 对一 Hive表设计 分区,并行 务
插入数据;对一 行时 的 本进行调 ; 理数据血 开
层表,对一 常见的公共数据直接从 层表获取数据,减少数
据的重 开 计 。 次 代后也取 不 的效 ,将整
调度时 压 1/3,可以 及时将画像数据 出到服务层的
需要。

本章介 画像 数据开 可 到的需要调 的 景。


对数据 斜、 并小文件、 存 数据、开 表几 常见
题的 理,可以 化ETL 程,减少调度的整 时 。
6章  程调度
开 完 一 画像 对应的 本后,需要将该 本提上调度
, 定时 刷昨 生的新 。

开 代的 程 ,开 初期 用crontab命令调度开 务
定时 行, 随着调度 务规 的 加, 用Kettle、Airflow这样的
工具替代crontab 定时调度 提高集 工 效率。一方面可以帮助厘
务 的 赖关 ,另一方面当调度出现 常时可 速定位出现
题的位 。
6.1 crontab命令调度
画像开 的初期阶 ,为 数据尽 上 代,对 调度
规范化的要 许 放 次要位 。 这一阶 , Shell
本、Python 本 crontab调度命令即可完成 单的ETL 务。

下面 一 来看这种ETL的实现方 ,如 6-1 示。

6-1 crontab调度 程

crontab命令 7 定时调 workflow_work.sh 本。

00 07 * * * /usr/bin/sh /home/userprofile/userprofile_workflow.sh >>


/home/userprofile/ crontablog/log_`date +\%Y\%m\%d`.log 2>&1 &

workflow_work.sh 本 好环 变 后,调 Python 本


main_workflow 行。代码示 如下:

#!/bin/sh
export SPARK_HOME=/usr/local/spark-2.1.1-bin-hadoop2.6
export JAVA_HOME=/usr/local/jdk1.8.0_162/
export PATH=$JAVA_HOME/bin:$PATH
/usr/bin/python /home/userprofile/work/main_workflow.py

main_workflow 本 ,分别提 Spark 务去 行画像 的


计 本。代码示 如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import datetime
import os

if len(sys.argv) < 2:
today = datetime.datetime.today()
oneday = datetime.timedelta(days=1)
yesterday = today - oneday
datestr = yesterday.strftime("%Y%m%d")
else:
datestr= sys.argv[1]
os.system("export PYTHONIOENCODING=utf8")
os.system("export SPARK_HOME=/usr/local/spark-2.1.1-bin-hadoop2.6")
os.system("export JAVA_HOME=/usr/local/jdk1.8.0_162/")
os.system("export PATH=$JAVA_HOME/bin:$PATH")

# 分别提 Spark 务, 行画像 计 本


os.system("spark-submit --master yarn --deploy-mode client --driver-memory 1g
--executor-memory 8g --executor-cores 2 --num-executors 50
userprofile_cookieid_gender.py " + datestr)
os.system("spark-submit --master yarn --deploy-mode client --driver-memory 1g
--executor-memory 4g --executor-cores 2 --num-executors 50
userprofile_cookieid_country.py " + datestr)
......
6.2 Airflow工 平台
Airflow是Airbnb内 的一 工 理平台,如 6-2
示。 用Python 写实现的 务 理、调度、监控工 平台。
Airflow的调度 赖 crontab命令,与crontab相比,Airflow可以方
看 务的 行状况( 行是 成功、 行时 、 行 赖
),可 务历 行 况, 务 行 败时可以收到 件
知、 看 误日 。对 理调度 务有 的帮助。

6-2 Airflow官 首页( Airflow官 )

crontab命令 理调度的方 来看存 以下几 方面的 端:

1) 务调度 行的 况下,难以厘 务 的 赖关 ;

2)不 看当前 行到 一 务;

3)不 看调度 下 务 行的 止消 时 , 这对
化task 是非常重要的;
4)不 记 历 调度 务的 行 况, 这对 化 排
误是非常重要的;

5) 行 务 败时不 看 行日 ,不方 定位报 的 务


接收 误 警 件。

Airflow的官方文 是
http://airflow.apache.org/index.html, 用Airflow 理调度
务的读 可 研读官 文章, 入 解Airflow。

下面介 工程开 如 去应用Airflow。


6.2.1  础
介 Airflow这 调度工具前先介 几 相关的 础 。

·DAG(Directed Acyclic Graph,有 无环 ):用 描 数据


的计 程。

·Operators:描 DAG 一 具 的task要 行的 务,如


BashOperator为 行一条bash命令,EmailOperator用 送 件,
HTTPOperator用 送HTTP请 ,PythonOperator用 调用 的
Python函数。

·Task:是Operator的一 实 ,也就是DAG 的一 。

·Task Instance:记 task的一次运行。Task Instance有 己


的状 ,包 “running”“success”“failed”“skipped”“up
for retry” 。

·Triggher Rules: task的触 条件。

6-3 , 一 可视为一 task, task用 行一条


务,比如 行 表的ETL加工。这 task调度 务 行顺序的先
后 接 来 成一 有 无环 。
6-3  调度DAG task 的 赖示 ( Airflow官 )
6.2.2 Airflow服务 成
一 正常运行的Airflow 一 由以下几 服务 成。

1.WebServer

Airflow提 一 可视化的Web界面, 动WebServer后,可以


Web界面上 看定义好的DAG并监控及改变其运行状况。也可以 Web界
面 对一 变 进行 。

2.Worker(Celery )

一 ,我 用Celery Worker来 行具 。Worker可以


台机 上,并可以分别设 接收的 列。当接收的 列 有
务时,Worker就 接收这 务并开始 行。Airflow 动
Worker的机 上同时 一 Server Logs服务,这样就可
以 Web界面上方 看分布 不同机 上的日 。

3.Scheduler

整 Airflow的调度由Scheduler负责 , 隔一 时
Scheduler就 有定义完成的DAG 定义 其 的 ,如 有
运行条件的 ,Scheduler就 相应的 务以 Worker
接收。

4.Flower(Celery )

Flower提 一 可视化界面用 监控 有Celery Worker的运行


状况。
6.2.3 Airflow安装
Airflow的安装 单,如 6-4 示, 命令下 入“pip
install airflow”即可完成Airflow的下 安装。

6-4 Airflow安装

安装完成后, 入airflow webserver命令 动Airflow的Web端服


务。
6.2.4 主要 功
Airflow的 理界面,可以 解其主要覆盖的功 。下面
介 Airflow主要覆盖的功 ,这 Airflow官 上有详细
介 :http://airflow.incubator.apache.org。

1.DAG 务列表

首页 的DAG 可以 看当前DAG的 务列表,包 当前有


DAG调度 务、 务运行成功、 务运行 败、 务正
运行 。如 6-5 示,从 可看到当前有3 DAG调度 务, 务
有 (Owner)为airflow, Task by State 可 看当前 务的调
度状 。

6-5 DAG 务列表( Airflow官 )

2.DAG调度状

Tree View (如 6-6 示)可以 看当前DAG task 务


的调度状 ,是 行成功、正 行、 行 败还是 待 行 ,
速定位到 行 败的 务,重新调 行。
6-6 DAG调度状 ( Airflow官 )

3.DAG有 无环

Graph View (如 6-7 示)可以看到当前DAG task


务 的 赖关 ,以及 务的 行状 。
6-7 DAG调度有 无环 ( Airflow官 )

4.甘特

Gantt (如 6-8 示) 可以 看DAG调度的甘特 ,


甘特 可以 看 task调度 务的 止时 、持 时 。方
到调度时 的task 务,以 后 进行 化。

6-8 DAG调度甘特 ( Airflow官 )
5.DAG 行 本

Code(如 6-9 示) 可以 看当前DAG 务的 行


本,包 务的 始调度时 、调度 败后重试机制、 task 务
的 赖关 。当 task 行出现 题时可 看该调度 本
定位原 。

6-9 DAG调度 行 本( Airflow官 )

6. 行日

当 task 行 败时, 击该task 务, 弹出的


“View Log”可 看该 务的 行日 ,如 6-10 示。
6-10  看task 行日
6.2.5 工 调度
Airflow的工 设计是有 无环 (DAG),如 6-11 示,
写工 时,需要 虑如 将 务划分为 可独立 行的 务,
后将这 务 并为一 整 ,从 实现 务调度的 。

6-11 DAG有 无环 示 ( Airflow官 )

Airflow DAG文件的功 定时 务开 的Shell 本,负责


理定时 务 一 子 务(task)的调度 赖。

画像 的调度 是先 行 计 务, 完后 验 数
据,如 数据 验无误则 送 件, 后 行 计 务,
则 送 败 件, 务暂 。 计 完成并 验后将数据同
步到 务 。 程 一环 有 监控 验 暂 务,
待开 理并 证数据 验后开 后面的调度环 。 程
详细的调度环 见6.2.8 内容。
6.2.6  本实
Airflow , 单 说,task 本是需要被一 调 行的
本,DAG 本是 理task 本 行顺序、 行触 条件的。 Airflow
调度开 主要需要 护的是DAG 本。下面 一 具 的 子来
解。

from airflow.operators.bash_operator import BashOperator


import airflow
from airflow.models import DAG
from airflow import operators
from airflow.contrib.hooks import SSHHook
from airflow.models import BaseOperator
from airflow.contrib.operators import SSHExecuteOperator
from airflow.operators.latest_only_operator import LatestOnlyOperator
import os
import sys
from datetime import timedelta,date,datetime
import pendulum
from airflow.utils.trigger_rule import TriggerRule

default_args = {
'owner': 'userprofile',
'depends_on_past': False,
'start_date': datetime(2018, 12, 01),
'email': ['administer@testemail.com'],
'email_on_failure': True ,
'email_on_retry': True,
'retries': 1,
'retry_delay': timedelta(minutes=1),
}
os.environ['SPARK_HOME'] = '/usr/local/spark-2.1.1-bin-hadoop2.6'
sys.path.Append(os.path.join(os.environ['SPARK_HOME'], 'bin'))

dag = DAG(
'userprofile_dag',
default_args=default_args,
description='A userprofile test',
schedule_interval='00 07 * * *')

该 本 ,首先定义 需要 入的 赖包,定义 默认的参数


及DAG参数 调度时 。其 default_args的默认 主要定义
如下参数。

·depends_on_past:是 赖上 务,即上一 调度 务 行
败时,是 行该 务。可 项包 True False,False表示当前
行 本不 赖上 行 务是 成功;
·start_date:表示首次 务的 行日期;

·email:设定当 务 行 败时,用 接收 败报警 件的


·email_on_failure:当 务 行 败时,是 送 件。可


项包 True False,True表示 败时将 送 件;

·retries:表示 行 败时是 重新调 务 行,1表示 重


新调 ;

·retry_delay:表示重新调 行 务的时 隔。

DAG的定义 ,除 入上 的默认
(default_args=default_args) ,还定义 该DAG 本的dag_id为
userprofile_dag,定时调度时 为 早上7 。

两行参数为 本运行的环 变 。

userlabel_task1= BashOperator(
task_id='userlabel_task1',
bash_command='spark-submit --master yarn --deploy-mode client --driver-memory
4g --executor-memory 8g --executor-cores 2 --num-executors 100
userlabel_execute1.py {{ ds_nodash }} ',
dag=dag,
trigger_rule=TriggerRule.ALL_DONE)

userlabel_task2 = BashOperator(
task_id='userlabel_task2',
bash_command='spark-submit --master yarn --deploy-mode client --driver-
memory 4g --executor-memory 8g --executor-cores 2 --num-executors 100
userlabel_execute2.py {{ ds_nodash }} ',
dag=dag,
trigger_rule=TriggerRule.ALL_DONE)

… # 相应用 画像 本的task,这里省略

airflow_run >> userlabel_task1 >> userlabel_task2 >> userlabel_task3


airflow_run >> userlabel_task4 >> userlabel_task5 >> userlabel_task6

上面这 本 入 需要 行的task_id,并对DAG进行 实
化。其 对userlabel_task1这 task_id来说,里面的bash_command
参数对应具 行这 task 务的 本,可理解为Linux下提 的
shell命令。userlabel_execute1.py文件为 行加工用 订单 对应
的 本。Trigger_rule参数为该task 务 行的触 条件,官方文
里面该触 条件有5种状 ,一 常用的
为“ALL_DONE” “ALL_SUCCESS”两种。其 ALL_DONE为当上一
task 行完成时,该task即可 行, ALL_SUCCESS为 有当上一
task 行成功时,该task 调 行, 行 败时,本task不 行
务。

“airflow_run>>userlabel_task1”命令为task 本的调度顺
序, 该命令 先 行“airflow_run” 务后
行“userlabel_task1” 务。

完成后,可以 Airflow的Web端 理界面的“Graph


View” 项下看到上文 的调度 赖 程 ,如 6-12 示。

6-12 Airflow下用 画像调度
6.2.7 常用命令行
Airflow 可视化界面的方 实现 调度 理的界面操 ,
试 本 界面操 败的时 ,可 命令行的方 调 务。下
面介 几 常用的命令。

·airflow list_tasks userprofile:该命令用 看当前DAG


务下的 有task列表,其 userprofile是DAG名称。

·airflow test userprofile age_task 20180701:该命令用


试DAG下面 task是 正常 行,其 userprofile是DAG名称,
age_task是其 一 task的名称。

·airflow backfill-s 2018-07-01-e 2018-07-02


userprofile:该命令用 调 整 DAG 本 行 务,其
userprofile是DAG名称,2018-07-01是 本 行的开始日期。
6.2.8 工程化调度方
工程实 ,对 用 画像 的ETL调度工 ,除 的调
度,还包 同步数据到服务层、数据的监控预警( 预警、同步到
服务层的预警 )。下面详细介 工程化调度 覆盖的 , 该
调度方 可以 前面介 的 开 、同步数据到服务层、服务层调
用数据 开 内容的知识 全 来, 读 对用 画像整 方
有一 宏观上的认知。

从 6-13可以看出,用 画像工程的调度主要可划分为2 ,
包 数据 库进行的 计 ,以及数据写入服务层,下面详细进
行介 。
6-13 主要调度

1. 计

计 主要用 ETL将 用 上,包 计


、规则 、机 学习 。对应的ETL 本 行 程
如 败,Airflow支持 败后重试。

本示 如下:

# 上 务的task
airflow_start_run = BashOperator(
task_id='airflow_start_run',
retry_delay=timedelta(minutes=5),
retries=10*12,
bash_command='python /airflow/myscripts/userprofile/airflow_start_run.py',
dag=dag)

# 计 的task
userlabel_task1 = BashOperator(
task_id='userlabel_task1',
bash_command=' spark-submit --master yarn --deploy-mode client --driver-memory
1g --executor-memory 2g --executor-cores 2 --num-executors 20 userlabel_task1.py
{{ ds_nodash }} ',
dag=dag,
trigger_rule=TriggerRule. ALL_SUCCESS)

从上面的 本 可以看到 上 务的task 败后 隔5分


重试一次(retry_delay),最 重试10×12次(retries)。下面
计 的task 行触 条件(trigger_rule)是上 务 行成功
(ALL_SUCCESS), 以 上 务 行 败重试时, 计 的 务
不 调 行。bash_command是提 行 务的命令,该命令 提
行对应的 务 本。

计 完成后, 验当 的 出是 正常,当 验 后
进行 出到服务层的 务, 则 务 败重试 务挂 。

2.数据写入服务层

ETL 务 行到服务层时,将对应的 数据写入服务层对应的


数据库 。如对接本公司的营 平台,则将数据写入到HBase、
Elasticsearch 数据库, 对接 三方营 平台, 接 的方 将
数据 出到 三方营 平台去。
3.服务层调用

服务层 接 方 调用 务需 的用 数据。下面 两
应用 景。

景一: 对存储 HBase 的用 数据 Elasticsearch 创


建二 的方 ,支持到组 对应的用 ,进 对其进行
特定的营 动 。

景二: 入用 id来 询该用 上带有的 ,进


对其进行 化的营 、服务 行为。
6.3 数据监控预警
相比Hive,由 MySQL 关 数据库对小 的数据读写速度
, 以开 时 虑将数据的监控相关表 护 MySQL 。

数据监控预警整 来看 盖下面几 主要 。

监控预警:用 监控 当日的ETL是 生 题,当数


据 出正常范 时, 出报警 件。

服务层数据监控预警:数据从数据 库 出提 到服务层时,该
程 是 正常进行,一 对比数据 库(Hive) 务 的
数 务 (如MySQL、Hbase、csv文件 ) 对应的 务 的
数 进行监控。

下面详细介 这两 监控预警的表 设计 应用 景。
6.3.1  监控预警
监控预警主要用 证 日用 加工的正常进行,当
的数 覆盖用 况出现 动时 触 件报警,开 收到
报警 件后定位 题 的原 并进行 理。

报警 件的 本 描这 监控表当日数据,当 当日的
出 与历 相比出现 程度 动时,可触 警提示。 如男
历 出覆盖用 数 是100万,今 出覆盖的用 是120
万,可视为出现 动。

可设计如下监控表,监控 的 出 况。

CREATE TABLE `userlabel_monitordata` (


`id` int(11) NOT NULL AUTO_INCREMENT,
`labelid` varchar(45) NOT NULL,
`data_date` date NOT NULL,
`label_num` int(11) NOT NULL,
`label_wave` float DEFAULT NULL
PRIMARY KEY (`id`)
) ENGINE=InnoDB

该监控表主要记 以下字 :

·labelid: id。

·data_date:数据日期。

·lable_num:该 覆盖的用 。

·label_wave:该 今日 出 与历 相比的 动 况。

6-14是 监控表示 数据。


6-14  监控表示 数据
6.3.2 服务层预警
该监控主要用 证服务层数据的稳定 准确 , 数据从数
据 库 服务层时需要对其进行监控, 则应用到 务
用 的 知 验。如:当推送到服务层的数据存 题时,App
推送给用 的弹窗 送给用 的短 件 受到 。 以
将数据推送到服务层前需要对其监控,当 现 题时,暂 推送到服
务层,排 题后再重新推送。

设计服务层预警 时,可开 一 监控表存储当日同步到服


务层的数据 (service_count)与存储 Hive 的数据
(Hive_count),报警 件的 本 描这 务 监控表当日数
据,当数据存 的 动时,表明数据的同步可 出现 题,此
时触 件 警。

如 广 务 的 景 ,该 RESTful API方 读取
HBase 存储的数据, 此 监控预警 验时,需要比对数据同步前
Hive 该 数据 及数据同步后HBase 存储的数据 。首先需要
询Hive HBase 对应 的数据 ,示 代码如下(Python代码):

# 询 Hive 数据
r = os.popen("hive --hiveconf mapreduce.map.memory.mb=8192 --hiveconf
mapreduce.reduce.memory.mb=16384 -S -e\"select count(1) from
dw.userprofile_userlabel_map_all where data_date='"+datestr+"'\"")
Hive_count = r.read()
r.close()
print "Hive_result: " + str(Hive_count)

# HBase 询 导入HBase 数据
r = os.popen("source /etc/profile; HBase
org.apache.hadoop.HBase.mapreduce.RowCounter 'userprofile_"+datestr+"' 2>&1 |grep
ROWS")
HBase_count = r.read().strip()[5:]
r.close()
print "HBase result: " + str(HBase_count)

将上 询到的数 写入“service_monitor”这 服务层的


监控表 ,示 本如下:
# 接 DB,将 询 插入表
db = MySQLdb.connect(host="xx.xx.xx.xx",port=3306,user="username",
passwd="password", db="xxx", charset="utf8")
cursor = db.cursor()
cursor.execute("INSERT INTO service_monitor(date_date, service_type, Hive_count,
HBase_count) VALUES('"+datestr_+"', 'advertisement',
"+str(Hive_count)+","+str(HBase_count)+")")
db.commit()

6-15是 务 监控表示 数据。

6-15  务 监控表示 数据

数据插入完成后 这 服务层监控表的Hive数据 同步
后服务层的数据 来判断同步数据是 正常,是 需要 送 警
件。
6.4 ETL 常排
画像 ETL调度的 程 ,难免 到调度 败的 况。
败时,短时 (小时 别)来看对 服务、BI 视分 来
说暂 服务的 还不 , 是对 上实时推荐的 务来说就
带来用 验 差、推荐准确 不 关 到营收的重 。
此 调度 败时, 速定位 败的原 关 。

关 调度 败的原 , 下来, 照排 误方 的 先 来
说,主要包 以下几 方面。

1.资 内存不 导致 败

这是最常见的 败原 。当集 资 竞 严重时,画像 的ETL


调度 有可 受到 ,关 该种原 的排 , 需 看调度 败
务对应的 行日 文件即可。 日 文件 搜 “error”关 词可
速定位到报 原 的位 。

常 内存不 的 败,日 报
出“java.lang.OutOfMemoryError” 误 。

2.上 数据ETL延 导致 加工 败

出现该 误的原 可 数据监控预警 件 现。 数据


监控预警 报出当日 的数据 下降幅度 理范 。 对
数据 下降 常的 , 看该 加工 本 赖的上 表包
,进一步 看上 表的ETL完成时 是 本ETL时 前。

如:计 用 历 购 额的 ,是从上 的订单 表


加工 来的。平时上 订单 表的ETL完成时 早上8:00,计
用 历 购 额的 的ETL时 8:30, 日订单 表
8:30还未完成ETL , 照设定此时该 已 开始 ETL 务,
加工当 败。

如 定位是 为 上 数据ETL延 的 败, 需要判断画


像 的调度时 是 上 数据当日ETL完成时 后进行。 如,
对 判断上 订单 表dw.order_fact数据的当日ETL完成时 ,可
命令“hadoop fs-ls
hdfs://data/user/hive/warehouse/dw/order_fact/data=20180701”
看,其 “hdfs://data/user/hive/warehouse/dw/order_fact”是
订单 表对应的HDFS文件位 ,可 HiveQL语句:“show create
table dw.order_fact” 看。

3.上 数据ETL 常 败导致 加工 败

这种 败原 比 2条 败原 更难 现。当上 数据已 加工完


毕,写表落 后,即 HDFS上 上 文件的写入时 也不 现
题。此时可 对比该上 表近期 日的数据 来 现是 存
题。

如:对 日期分区的订单 表dw.order_fact,可 命


令“select data_date,count(*)from dw.order_fact where
data_date>=’20180701’and data_date<=’20180707’group by
data_date”来看近几日的 是 存 的 动。当 现昨日数
据 下降 时,即 有可 是 上 数据加工 常导致的
题。

4. 本 导致数据加工 败

这种 况也是可 误的原 一。 上 前期ETL 正


常, 随着时 的推移,积攒的 题最终 爆 出来。这里 一 开
程 到的 题来进行详解。

我 知 一 用 (userid)可 设 上登 ,同一 设
(cookieid)上可 登 用 ,即userid cookieid为 对
关 。 次开 需要从cookieid关 到userid,获取userid的状
时, 略 这两 度 的 对 关 ,未加条件限制。初
始化 数据时, 本 行后 出“看 ”的数据。 ETL
调度两 后,这种直接 对 关 的 误 , 数据 ,
造成 行 败。

此, 排 题时同样要 开 的 是 存 BUG。
5. 上 务变动导致原有 加工 效

这种 题虽 不常见, 生时也 数据的 动。

如: 正则表 解 页 接来获取用 访 页面对应的


, 这种 景 ,当 上 务变动时 导致原有的 接改
变, 正则表 是 定的,从 导致不 解 变动后的 接。

对 这种 况应尽 免,需要运营方 上 新的 接前 知
开 。
6.5 本章小
如 说 数据开 日常工 么最重要, 一定就是 护调度
的稳定 。数据稳定 有 障,提 到服务层的数据的质
有 障。本章介 如 用开 ETL工具Airflow进行画像相关 务
的调度工 及出现 题时的排 方 , 数据预警机制 障 的
数据 出、提 的服务的可靠 。

更多书籍访问:www.j9p.com
7章 用 画像 化
开 画像后的 数据,如 是“ ”数据 库 ,并不
挥更 的 务价 。 有将画像数据 化后 更 务方
用。 本章 ,Web端展示的数据 读取 MySQL这 的关 数据
库,MySQL 存储的数据 Hive加工后, Sqoop同步的 集。

本章主要介 用 画像 化后主要可 盖到的功 ,以


及这 功 的应用 景。
7.1 即时 询
即时 询功 主要面 数据分 师。将用 画像相关的 表、
用 特征库相关的表开放出来 数据分 师 询。

顾下3.1 的Hive存储的相关 表,包 userid cookieid两


度。

·dw.userprofile_attritube_all:存储用 属 度的

·dw.userprofile_action_all:存储用 行为属 度的 。

·dw.userprofile_consume_all:存储用 消费 度的

·dw.userprofile_riskmanage_all:存储风控 度的 。

·dw.userprofile_social_all:存储社 度的 。

·dw.userprofile_cookielabel_map_all:对 cookieid 上
的 后 出。

·dw.userprofile_usergroup_labels_all:用 分组表。
询应用到 务 下面,对应 id里面的用 数据, 营 效
试 有广 应用。 如 务 对 定的 进行短 营 ,数
据分 师 分 营 效 时,可以 询这 表 该 id下面的用
id数据,进一步分 这 用 后 的 订单方面的表现。

·dw.cookie_feature_event_append:用 特征库表,存储用
一 一次行为带来的 数据,可用 掘用 行为特征及
好。

数据分 师 日常分 与用 相关 度的数据时,可 询相应表


的数据,这里 两 来介 。
对 存储cookieid 度数据的 表
dw.userprofile_cookielabel_all,如 提取带有男
(id=ATTRITUBE_C_01_001)的用 以 后 应用,可 用如下
询语句:

select cookieid
from dw.userprofile_attribube_all
where data_date = ‘20190101’
and labelid = ‘ATTRITUBE_C_01_001’ # 分区的 主题是 别
limit 10

该 询 ,限制 询的日期分区为当前日期前一 , 询
id为男 用 。

询 如下:

对 存储userid 度的 的表
dw.userprofile_userlabel_map_all,如 已知一 用 的id,可
询出该 用 上带有的全 。

select userid,userlabels
from dw.userprofile_userlabel_map_all
where data_date = ‘20181201’
and userid in (‘44463729’,’4069220’,’20101029’,’54597979’,’19816511’)

询 如下:
关 用 特征库相关数据的 询 应用方 4.5 有详细介
。面 数据分 师 询时, 需要开放出表 及详细字 说明即
可。
7.2  视 与 询
视 与 询功 主要是面 务 用,如 7-1
示。

7-1 平台 视

视 ,层 化 展示 目前已 上 用的全 用
。用 可以层 化 击 , 看 的详细介

7-1 ,当 击“用 属 ”这 一 目时,可进入到“


别”“购物 别”“用 价 ” 二 目, 击“
别”二 目,可看到展开的“男 ”“女 ”三 ,进一步
击三 “男 ” 是“女 ”,可以 看该 的详细介 ,如
7-2 示。
7-2  元数据视

该 详 页 ,可以 看 属 这一 目下面
的覆盖用 况。

对 的覆盖用 进行监控,可以 为预警 用。


如: 的覆盖用 与前一 相比出现 比 的
动,需要排 该 当日ETL 是 出现 常 是 务上的操
导致 的 动。

询 ,如 7-3 示, 入用 对应的userid
cookieid,可以 看该用 的属 、行为 、风控属
度的 , 方位 解一 用 的特征。关 如 存储这种数据
, 3.1.3 有介 ,即 将 用 对应的 成map字
,如{‘key1’:‘value1’,‘key2’:‘value2’},进行
存储。
7-3 用 询
7.3 元数据 理
理功 主要是面 数据开 。数据开 开
完 后,需要将 入元数据进行 理,如 7-4 示。

的 理也即对 元数据 理,将 Web端 表单


写的数据存储到MySQL 关 数据库 。用 该 击“
加 ” 对已 加的 进行 操 ,可设 该 的元数
据相关 (如 7-5 示)。

可 该页面 相关的元数据,包 id、名称、开


、 、 描 、数据 ,方 务 应用时理解
该 的 务 义以及其负责 。对应的元数据 护 关
数据库 ,需要创建一 关 字 ,如 7-6 示。 Navicat
化操 界面可 看 入的元数据 ,如 7-7 示。

7-4  理– 加
7-5  理– 元数据

7-6  元数据字
7-7  Navicat 看 入的 元数据
7.4 用 分 功
用 分 功 主要是面 务 用。 理、运营、客服
务 应用 时,可 不 看 一 对应的
况,更 可 需要组 来 其 务上对 的定
义。 如:组 “近30日购 次数” 3次 “高 ”“女 ”用
这3 定义目 , 看该 覆盖的用 ,以及该 分
的 度特征。下面介 上的实现方 。

“用 分 ” 下, 击“新建 ” 前已
加的分组(见 7-8),进入详 页可 定义 盖 的 (如
7-9 示)。

7-8 用 定义分
7-9 用 定义分

定义 用 分 时,对 有 计 ,可以 定义
该 的取 范 ,如 7-9 “近30日购 次数” , 务 可
该 的数 。对 分 ,如 7-9 的“ 度” ,
务 该 即可 出包 该 的用 。“ 名
称” “ 描 ”表单用 务 描 该 务上的定义,
方 后 看、应用该 。下面详细介 一下“ 减 ”功 的
应用 。

Web 端, 务方 组 来 视分 、 定
,并 推送到的 务 ; ETL 务时,即 7-9 “数据计
层 ”,首先需要从MySQL 关 数据库 读取 务方 定的
规则,即 的权重 , 后将 规则组 成SQL语句,
Spark 务将对应的 计 出来,写入Hive ; 服务层应用时,即
7-9 “ 出到服务端”,根据不同的 务 ,分别 行对应的数
据同步 本,将上 程 计 出来存储到Hive 的 数据同步
到对应的 务 。

数据计 层面,实现用 功 的详细开 程可见4.8 。


7.5  分 功
分 功 主要是面 务 、数据分 师、 理
用。


提 根据现有用 定用 的功 ,同时 务方
可以从 度(如 、 别、年龄、消费 平 )进一步分 该
用 的特征,从 为 细化运营提 支持。 上一小 讲的用
功 相 , 分 功 首先也需要组 定用 ,不
同 视分 功 支持从 度去分 定用 的
特征, 用 分 功 重的是将 出来的用 推送到 务
,提 服务支持。

下面介 分 功 。首先 用 分 功 一样,


需要组 出目 用 (如 7-10 示)。

7-10 创建需要分 的
创建好目 用 后, “对比 度” 菜单 需要分
该 用 的 度(如 7-11 示), 如这里 的是下单次数
度。“对比 度”列表 的可 也是用 属 、用 行为
目 已 建的 。

7-11 对目 需要分 的 度

好 视分 的 度,下面就可以看到刚 出来的用
度 下单次数上的表现 (如 7-12 示)。
7-12 从 度分 目 特征

除 视分 单 度上的特征, 视分 功
还可以支持同时分 不同 度上的表现。 务 根据
不同 务规则同时创建两 , 后 对比 度,可以从
度上对比分 这两 的特征(如 7-13 示)。
7-13 对比分 两 特征
7.6 本章小
本章介 用 画像 化主要 盖的功 以及这 的
应用 景。用 画像 化是 数据应用到 务服务 的一 重要出
, 务 熟知 务, 对数据不 解。 这种 可视化的方
,方 务 分 用 特征,将分 后的用 推送到对应
务 触 用 ,更方 、 捷 将数据赋 到 务 景 去。本
章 对 功 的详细剖 ,为数据 、运营、客服
务 提 一种 规划 应用 服务的解决方 。
8章 用 画像应用
用 画像 化后就成为 务 分 用 、触 用 的有效工
具,本章从 营分 、 准营 、 化推荐 方面介 用 画像的
应用 景。
8.1  营分
画像 可帮助 务 从 方面进行 营分 。
8.1.1  分
助用 画像,可以对 的 进行分 ,比如说可以 速定
位到爆 ,进一步分 购 爆 的用 度上的特
征。

如 8-1 示,运营 可以直观 看出男装三 的


况,如本 牛 裤 季新 最高。当 ,运营 进一步
分 购 这两种三 的用 其 度上的特征(如年龄、
、 )以 准营 时,可以 用 视分 功 (详见7.5 )
来分 该用 度上的特征。
8-1  男装三 日 (示 数据)
8.1.2 用 分
助画像 可以 解平台用 的 别、年龄、 度特
征的用 分布特征,如 8-2、 8-3、 8-4 示。

8-2 平台用 别分布
8-3 平台用 年龄分布
8-4 平台用 分布
8.1.3  分
根据 黑客理论(AARRR) ,如 8-5 示,将 的营收
径 分为 — 册—留存—下单— 播,其 主要是 运
营 负责;用 运营 贯穿接下来的 程;内容运营主要负责生
质的内容来提高用 的黏 ,从 提高留存;主 运营主要负责主营
务的 径, 化 化 ,提高 化率。

8-5 AARRR 及运营重

下面对AARRR 的定义及运营方 进行详细讲解:

1) :这是 来 的 动 , 有有 的用 进入平
台, 对这 用 进行 化。 我 知 ,互 新客的获客成
本是比 高的,如 不 的 质 , 有可 既
有获取到质 好的用 。对 这一 ,用 触 的 本分 就是对
用 来 进行分 ,即本 要介 的内容。 不 靠 的
况下, 、 放 对我 的App、Web 更 适。

2) 册: 后,如 用 是 进来就 ,这
对 并 有 么 用。 有 高质 的内容、 适的 功
用 的需 ,用 有进一步 解 的 望, 有 化的下
一步操 —— 册。 此 将用 入平台还是远远不 的,
需要进一步关 用 是 进一步 册 化,从 册 程上看是 存
需要 化的细 。
3)留存:前面我 提 ,新用 的获客成本是比 高的, 此不
可 一 去获取新的 ,同时也需要 用 ,让进来的
用 对 成 赖, 用 需 ,让用 持 不断 来
用我 的 。 此提升留存一方面需要 用 需 ,另一方面需
要 化用 验。 化 程 可 用 分 、 细化运营、将
准内容推送给有特定需 的用 来提高用 对 的 度。
数据可以 用 行为来分 行为可以 用 持 访
、如 这 行为 生。并 用 生命 期的研究,对 默用
进行识别,让运营 运营 对这 用 进行 ;对 用
进行 记,让运营 推送、 放 方 进行用 。

4)营收:用 是收入的前提。 有 完全 用 的需 ,用
认同 的价 , 用 费 化。 要让 持 稳定
运营下去,就需要 一 列运营 让新用 持 费
化,让 用 持 费。 用 运营的 础是对用 解、
熟 ,数据 的是帮助运营 解用 的 有属 ,让用 不断 营
收进行 化。

5) 播: 有用 对 高度认可及对 功 高度 赖,
将 分 推荐给其 。 分 推荐的 程 ,
的来 , 成 的 环,最终 不断的将用 往营收用
进行 化, 到价 的目的。

对 目 用 的 来 的分 尤为重要。

画像应用 ,可以分 目 的 来 , 放的
略更有 对 。 如, 务 用画像 组 定对 女
装 兴 的 , 度进行 视,分 该 用 主要来
, 后有 对 该 放该女装 的广 。

8-6 示为目 用 的占比示 。


8-6 目 用 占比

一 , 画像 端可以 搭建BI报表的方 进一步细化分


的 度表现。整 来 用 平台上的访 、 册、
订单 、GMV、留存率以及 放费用 度数据,评 不同 的
质 好 ,以 务 对 的 放 略有的放矢。

下面以表8-1 示的 分 度为 进行分 。

1)用 用 衡 获取用 的 力 用 平,一


来说 几 主要的 即为该 带来 用 ,其 为该
带来的用 相对 小, 尾分布, 日报数据监控方面需要重
关 前几 主要的 。该 主要关 UV、日 UV、日用
册 、日 册 。其 日 的 计 径用 评价该 的整
平,一 计 该 的近30日 。
2)对 用 质 的评价一 留存率来进行,主要 包
次日留存率、7日留存率、月留存率 。这几 的计 径如下:

·次日留存率= 一 新 的用 二 还登 的用 数/ 一
新 用 数;

·七日留存率= 一 新 的用 往后的7 还有登 的用


数/ 一 新 用 数;

·月留存率= 一 新 的用 往后的30 还有登 的用


数/ 一 新 用 数。

从我 关 的 用 留存率来看,一定是 平台上有 消
费行为的用 留存用 , 这 留下来的用 的行为就变
重要。我 需要 解留下来的这 用 么, 方面可以
升留存率。 这方面可以 用运营 ,譬如 动运营 准营
推送 就是有 对 提高留存率的方 。

3) 收入用 评价从该 的盈利 力,主要从 入订单 、


营收、下单的用 、ARPU、用 购率 角度衡 。其 购率是
一定 期内购 2次 2次以上的用 比 。 购根据时 区 的不
同可分为 、月、季、年 购率。 用 的 购率越高,该
带来的用 的黏 越强。

表8-1  质 分 度(示 数据)


8.1.4  斗分
斗分 用 分 程 关 的 化效 ,常 助 斗
展现 化效 。 斗 是一种 斗的可视化 表, 用该
方 可以直观 的整 程、 务的 化 径、 不
同生命 期阶 下的用 表现。 一 列 化率的分 ,可以
速定位 题,方 运营 及时调整运营 略。

斗 的主要运用 景有以下几 :

· 程的关 径 化 ,比如电 常用的购 程;

· 务价 径的 化 程 ,比如常用的AARRR 的价
化 ;

·虚 程 ,比如 生命 期区分的 不同生命


期阶 的用 。

化 斗帮助 务 分 来访用 详 页访 、加购


击、下单 击、支 关 环 的 化 况,从 帮助 务
不断 化 径,如 8-7 示。
8-7 用 化 斗(示 )
8.1.5 客服话术
用 客服 也有广 的应用。生 常 到这样的
景:当我 平台的客服 诉、 询 馈 见时,客服
可以准确 说出我 该平台的历 购 况,上一次 询的
题 理 ,这也是画像 应用的 景 一(如 8-8
示)。

8-8 用 展示

客服 可以根据来电用 的画像 对 提出解决办 ,以及


对 高价 用 提 VIP客服 专项服务。
8.1.6  特征分
前4 介 的 是从单一 度分 用 特征, 用 特征分
可以 组 来 定义 (详见7.5 ), 后对 定义 从
度进行 视分 建立对照组 对比分 。

根据分 验, 分 时一定要去 对比,单 看单


的分布 有 ,不对比看不出差 。 助画像
,可以分 定的用 度上的特征 况,如 8-9 示。

8-9  特征分
8.2  准营

8.2.1 短 / 件营
日常生 我 常 从许 接收到营 来的 。一条关
包到账的短 消 推送可 用 开已 访 的
App,一条关 单里面 降价的 件消 推送可 刺 用
开推送 接直接下单购 。

这 营 是如 助画像 实现的 ?

当画像 成 后, 务 可以根据 务规则组


定相应 ,将该 推送到对应的 务 进行运营。关
用画像 端进行营 的详细解决方 可以参 7.4 9章的
实 。

如 公司 初创阶 , 有 力 入 、接 层面的开
时,也可以 数据分 师写Hive SQL语句,组 用 出
对应的用 数据。 后将该 用 相关数据给到对应 务 ,
将数据导入到 三方平台后以短 、 件 方 进行营 。
8.2.2 效 分
准营 是数据价 的一 重要出 , 如 评 效 好 ,不
同 务 的 有不同的关 重 。 来看,可分为 提升导
GMV提升导 两种 况。

有的 务 的KPI 是 , 此关 的重 是 提
升,如负责Push 务 的 。这种 况下,对效 的分 对比
用 定 进行 准推送方 带来的 击率,与 有 用用 画像进
行无差别普 推送带来的 击率相比是 有 提升、提升 少 百
分 。

有的 务 的KPI 是GMV, 此关 的重 是ROI的


化,如短 营 、 呼营 的 务 。这种 况下,对效 的分
关 营 动 营 少用 、实际触 少用 、有 少
用 实际 费以及带来的GMV,对比实际营 成本(短 、 呼电话的
成本)分 营 的ROI。

下面分别 两 进行说明。

1:对目 准消 推送带来 提升

电 负责 运营的 给用 推送消 , 进用 平
台的 度。 用画像 前 给用 的消 为无差别推送,
有 对用 行为特 推送消 , 消 推送的 击 化率一直
7%上下 动。

画像 上 后, 务 用 定用 ,根据用 属
行为特征将用 划分到不同的 去, 对这 分别 文
后进行推送。 如, 近×日 览 女装 且近×日有 来
访的用 ,给这 用 推送女装营 的消 。 助这种 细化推
送 的方 显著提高 整 用 验, 消 推送的 击 化率
到10%左 ,如 8-10 示。

2:对目 进行短 营 带来营收


动期 , 电 公司 运营 申请 一 财务 费
用 短 营 用 ,目 是 用 来访App以及实现订单的 化。

8-10 画像 消 推送上的应用效 (示 数据)

运营 根据 动的目 营 , 用画像 组 用
定 后推送到短 送平台。 短 送后的几日内, BI报
表 监 营 用 的访 、下单 况,如 8-11 示。 动 束后
计 现本次短 准营 给GMV带来 显著的提升。

8-11 画像 短 营 上的应用效 (示 数据)


8.3  化推荐与服务
用 画像的开 程 不 开 用 度的数据,同时
也 开 用 行为特征库、 特征库、 家特征库 相关数据。为
开 用 相关 、内容的 化推荐提 底层数据支
持。

另 , 画像 可以为用 的 化服务提 支持。


如, 对高质 用 提 VIP专 客服,可以让该 分 用 受到
高质 服务,有效提升用 验。
8.4 本章小
本章介 用 画像的应用方 。首先,对 务 从 营分
的 度分 解用 特征,可进一步 消 推送、短 、
件 触 、运营用 ,有效帮助 GMV 化,提升用
验。同时画像 数据、用 行为特征库的 建为 化推荐相关
进行数据 掘提 底层支持。
9章 实 详解
用 画像的落 应用 景有 ,本章 一 实 来 景
化 现用 画像的应用 应用方 。

画像 去 方面的数据分 、触 用 的运营方 ,可
以 速 将数据应用到服务层(T+1甚至实时即可上 应用), 到用
用 馈后 效 分 , 代营 略 设计。相比
的项目制, 项目 理提需 、上 版本, 后进行效 分 、
代再 化的时 期将 短。
9.1 风控 诈预警

9.1.1 应用 景
风控 诈预警 戏、电 、 融、家政、社 领 有
着广 的应用 景, 如家政领 识别 风险、 贷风险的用
,提高从 质 准入 ; 融领 识别存 风险、
贷的 题用 ,对其 绝放贷;电 领 识别出薅 、下
单 收 行为存 常的用 ,对其进行隔离 理。这 应用 景
可以 用 画像来实现。下面 融领 的 风控 诈 来
介 。

消费 融领 对 用 贷前准入有着严 的审核,对 用
、设 建立画像, 助画像数据 风控 略规则、
,进 生成完 的审 略,对 高风险用 进行有效识别,帮助
减少 工参与环 ,实现 动化审 、授 ,有效规 营 、
易的风险( 9-1)。
9-1 画像 贷 务 景的(示 数据)
9.1.2 用 画像切入
当一 用 申请 贷时,接 入用 id 设 id
, 服务层 (一 用HBase) 询对应的用 设 id
( 9-2),生成用 风控报 ( 9-3) 设 风控报 助
务 进行审核 根据风控规则进行 动化放贷 理。

根据调用的画像数据, 前端展现该用 度的风控 。

建风控 诈画像 的 程 , 用 授权数据


建 用 id、 机号码、设 主 、 度的画
像,从 帮助 有效建立 用 、 机号、设 的黑白名单,从
为 贷、租赁、家政 景的应用提 评 参 。

9-2 用 风控数据(示 数据)


9-3 用 风控报 (示 )
9.2 A/B 效 试
本着数据驱动的理 , 正 切换到 用 种规则运营用 前,
需要 A/B 试来看AB 组可以带来更高的 化 ,带来的 化
是 少。 助画像 可以 方 实现对两组 运营效 的
对照 试。
9.2.1  景
零食 消 为 动期 获 好的 ,计划
消 推送的方 种草新上市 、 的 功 列文章,为
动造势, 化。为 准定位目 , 运营
现 计划 两 A/B 效 试:

1)不同内容 题对 的 ;

2) 准推送相比普 推送带来的 提升。


9.2.2 用 画像切入
整 项目 需要 理 如 切分AB组 ,如 设计好AB组
规则 效 监 。下面分步骤介 画像 如 切入AB 试

1.对AB组 切分

为 A/B组 试,首先需要 好 的切分, 平台上


cookieid的生成机制, 虑从cookieid尾号入 切分。可以将
用 划分为A/B ,也可以 用 创建+随机分 的 对 进
行切分。

2. 试文 题对 的方

平台 运营 为 动期 更 用 来访App,计
划 动预 期 取少 用 一版文 题的AB效 试。

该 试方 ,控制组A 取 近x 来访 、cookie尾号为a,
且近x 内 览/收藏/加购 该零食的用 ,给该 用 推送零 文
A,对照组B 取 近x 来访 、cookie尾号为b,且近x 内 览/
收藏/加购 该零食的用 ,给该 用 推送零食文 B。控制组
对照组的用 相同, 文 不同,后 监控两组 的 击率
小,进 分 不同文 对用 击的 。

3. 准推送相比普 推送带来的 提升的 试方

用画像 细化推送 前, 平台对用 用无差别推


送消 的 进行推送。为 试 细化运营 相比无差别运营带
来的 提升, 运营 决定 近期重 运营的零食营
一 AB效 试。

该 试方 ,控制组A 取 近x 来访 、cookie尾号为1,
有 目 好的用 ,对照组B 取 近x 来访 、cookie尾号为2,
且近x 内 览/收藏/加购 该零食的用 。对AB组用 消 推
送相同的文 ,后 监控两组 的 击率 小,进 分 准营
推送带来的 小。
9.2.3 效 分
AB组 消 推送上 后,后 需要搭建监控报表来监 控制
组 试组的 化 况(如 9-4 示)。

9-4 A/B组效 监 报表

本 介 如 用画像 Push 进行A/B 效 试,


同样 , 短 、 件 其 营 同样可 助此 方 进行A/B
试。
9.3 用 生命 期划分与营
生命 期 的是一 生命 从出生到 的 展 程,用 的
生命 期 的是用 从接触 ( 站)到离开 ( 站)的 展
程,用 的生命 期价 LTV(Life Time Value)/CLV(Customer
Life Value) 的是这 展 程 用 为 ( 站) 带来的价

对用 生命 期的划分、分 用 不同生命 期阶 的行为


特征,以及切入运营,分 运营效 ,从 有效提升用 的 化、
购、留存, 公司 有广 的应用 景。本 主要介 如 划分生
命 期、分 用 不同阶 的行为特征、运营 略,以及将用 画
像如 切入到整 程 ,提升分 用 、触 用 的效率。
9.3.1 生命 期划分
用 生命 期主要分为: 入期、成 期、成熟期、衰退期
期5 阶 。用 进入 后,不一定 完一 完整的 期,
阶 有可 离开, 阶 为 ( 站)带来不同的价

· 入期:此时用 刚来,用 试探 来试用 , 尔用


一下,此时用 的价 相对来说比 低。

·成 期:用 不定期 来 用 ,并开始进一步 验


功 ,此时用 的价 有 提升。

·成熟期:用 常 用 ,并 以分 的 来宣
,此时用 的价 比 高。

·衰退期:用 原 (如 代后用 不 欢 )不再


常 用 ,此时用 的价 衰减 。

· 期:用 对 非常不 到 替代的同 的


,不再 用该 。

用 运营的 程 ,我 不 一上来就 期论, 是要定一


目 , 目 我 解出 关 ,要提升这 关
需要去 用 相应的核 需 。比如用 生命 期分 的核 目
是:提升用 生命 期 的 化率,提升用 的留存(用 的
参与程度)。 的持 化及用 留存的提高 程 ,用
的生命 期也 历 一 完整的历程,其价 也 到 提升。

这两 目 我 将其 解为如下 ,如表9-1 示。

表9-1  化核 解
用 的生命 期,我 可以将用 的 解如下,如 9-5
示。

9-5 用 生命 期 用 示

与用 生命 期的 阶 对应的关 ,如表9-2 示。

表9-2 用 生命 期关 解

Melnick的理论及互 的实际 况,将用 的生命 期


价 解为:
LTV=( 客 月的下单频次×客单价× 利率)×(1/月
率)

  =( 客 月的下单频次×ARPU× 利率)×[1/(1–


月留存率)]

  =用 生命 期内下单次数×客单价× 利率

其 ,①ARPU( 用 的平 收入)= 时 内的 收入/同


时期内 用 数;② 率: 率 的是一 时 内,有 少
比 的用 不再 用 的 。 以 率= 时 内 的用
/同时期内 的用 , 比 难定义, 留存比 好定义,故月
率近 价 1–月留存率; 率的 数用来表示预 的用 生
命 期,如 一 的 率为10%,则 对应的生命 期为10
月。

用 生命 期 务 主要有以下几 应用 景。

应用一:根据 解 为提升LTV制定不同的运营 略

从 解公 来看,运营需要 的是尽可 证 的质 ,确
进来的用 的有效 ,提升用 的质 及数 ,尽 降低获取用
的成本,并应用 样化的运营 提升用 化; 用 生命 期
的 阶 ,对不同 的用 进行 原 分 ,提升用
度。

应用二:评 用 运营 动是 盈利

单 用 利=用 生命 期价 –获取用 成本–运营成本=CLV


–CAC–COC

初期一直以补贴用 的 来留住用 , 此以往,


资 一旦断裂,将无以为 。 有当用 的 利 0时,
、持 稳 展下去。

设一 用 月的收入是20元, 月的 率为
50%, 用 播5次,被 播 的 用 月的收入为5
元, 月的 率为70%,则
CLTV=20×1/0.5+5×5×1/0.7=41.43元。

如 获取用 的成本加上运营的成本 用 的生命 期价 ,


么显 这 用 是不盈利的,如 获取用 的成本加上运营的成本
小 用 的生命 期价 , 这 动是 的。

应用三: 资 报率(Return On Investment,ROI)

根据LTV的公 及用 利的计 公 , 推 到 资 报率的计


公 :

ROI= 化率×ARPU/(CAC+COC)

从ROI的计 公 来看,要 提高ROI,需要从以下3 方面着 :

(1)提高 化率

提高 化率,一 开 ,二 。 谓开 , 的是要不断
种方 来获取新用 , 的是减少 的用 及挽
即将 已 的用 。这里主要介 。 主要从以下两
出 来最 化 减少用 。

a)从 出 , 具 的研究 , 有 离 的用 预警
是无 义的。首先我 要 现有的 出用 是 一步
的,再 具 的 进行改进。比如,是 一 环 生 退
的 况, 就推动 解决 退的 题;再如,是下单 化 程
琐、支 单一, 就推动 程 化、支 样化。
如,前面我 分 用 的生命 期 有关 用到的 化率
的关 ,从这 公 来看, 关 的 化率, 出
化率比 小的 ,定位原 进行 化。 一 具 应用的 子,
的 册率差不 , 不同 的下单 化率差 比
,此时用设定风控规则来评 的质 , 为这 是 册
来 费的, 现是有 刷单, 对刷单的 止 后,
整 的下单 化率就上来 。

b)从运营出 , 成种子用 , 证 下限, 具 的


运营 略,如 奖、 到送积分,将 质内容推送给 准用 ,进行
用 建设 。

(2)提高ARPU

互 的 利期已 去, 么如 住现有的用 来提高ARPU


?可以从 住用 的需 来展开:①用 放 券、 种 价
币、 包 方 ,来 用 占 宜的 理, 进用 下单;②
对用 设立 ,并对不同的用 设立不同的福利规则,
用 对 位高 一 的诉 ;③建立 准营 平台, 准定位
用 ,并对这 分 进行 化 准推荐, 用 的特定
景需 ;④提示用 不 被 露, 用 对安全 的诉 ;⑤
生日提 减券 其 福利, 用 对 的认同需 。用以上方
来 进用 下单,可直接 接 提高ARPU。

(3)降低成本

降低成本分为两 。

一 是降低用 的获取成本。实现的方 有 ,比如:①


数据分 化 质 ;② 预警,对即将 的用 进行
适的运营,提高用 留存, 加用 对 的参与度与黏 ;③与其
平台 ,资 共 ;④其 。

二是降低用 的运营成本。实现的方 也有 ,比如:①搭建


准营 平台,对 一 用 的 属 进行 、对即将 的用
进行推送 、对高 客 推送单价高的 ;②将常用的分
化,建立常用分 的BI报表,并支持 速 代,支持细分
项下 。

根据上面对用 生命 期核 的 解,对 用 生命
期 一环 的划分,可以从以下几 度着 。

1)App 用阶 :用 用App包 安装、 册、首次购 、


购、 默、卸 几 重要阶 。

2)RFM:从R(用 最近一次 今 数)、F(用 近x 消费


次数)、M(用 近x 消费 额)这3 度 虑用 消费 力。
3)访 时 :从最近一次访 今 数分 用 是 已 。

根据上面的 度,对 平台用 的生命 期从购 额、购 次


数、购 、购 时 度去分 用 当前 生命 期的
阶 ,进一步对该平台用 相关数据进行调研,最终 出如下划分
(如 9-6 示)。

9-6 用 生命价 期划分(示 数据)


9.3.2 不同阶 的用 触 略
从用 用 的阶 来看,包 从安装、 册、购 、 购、
成为 诚用 离开 阶 。这里 取 平台一 时 内的用
数据,分 用 不同生命 期阶 的行为特征(如 9-7 示)。

9-7 用 阶 的 化 况(示 数据)

9-7 9-8可以看出从安装到 册平 用时14 ,其 61%


的用 安装当日就完成 册,70%的用 安装3日内完成 册,从
安装到 册的 化率为30%。进一步分 可知 册用 30日内 率
为30%,比未 册用 的 度高10%。 此 新用 安装的前3日内可
新 包、 券 动, 消 推送、短 触 用
,进 导用 完成 册。

9-7 9-9可以看出从 册到购 平 用时10 ,其 43%


的用 册当日就完成首单,可见用 的 册目的 程度上就是
为 下单。76%的用 册9日内完成首单,从 册到购 的 化率
为20%。由此 新用 册9日内,可 新 包、 券、 减、
用 兴 内容的推送 方 , 消 推送、短 触 用
,进 导用 下单。

9-8 安装x 后 册用 占比(示 数据)

9-9  册x 后购 用 占比(示 数据)

9-7 9-10可以看出用 首单 后15 , 到 购的


高峰期, 购的刺 也应 此阶 前后进行。 购用 50%以上
35日以内进行 购,80%以上 90日内进行 购,可 月对首单
用 进行 。

分用 留 入期, 有20%用 进入成 期。从 入期到


成 期平 需要8 ,成 期进入成熟期 化率为10%。进入成熟期
后,有一半用 30 内未再次购 , 仍 持 ,需要积 导
购。初步来看,用 生命 期 阶 有 的可提升空 。

9-10 首购x 后 购用 占比(示 数据)

对用 生命 期 不同阶 进行差 化运营,可最 化用


价 ,如 9-11 示。

9-11 用 生命 期延 略

前面对用 生命 期 阶 的分 (见表9-3),需要对不
同阶 的用 取不同的运营 略进行触 。

表9-3 用 生命 期 阶 的分
· 入期: 对已安装 未 册的用 导其 册, 对已 册
未下 单的用 导其下单。对 该阶 的用 ,可 消 推
送、站内广 推送 触 , 短用 购 时 隔,实际 可
包、 券的方 励用 短从安装到 册、 册到首次下单
的时 隔;

·成 期: 分 可以看出一 新用 首次购 1 月内 有
购行为的其留存率 有19%,1 月内有 购行为的留存率 到60%
以上。 此阶 需要 养用 的 用习 , 短用 购 时 隔,
刺 其 购。可 消 推送、站内广 推送 触 ;

·成熟期:提升用 ,加强触 用 的 ,如消 推送。


随着用 购 频次的 加,用 黏 强,购 的时 隔
越来越短。 加用 购 频次可 设计 富的购物 景进行 景营
。另 ,可 减、 送 动提高用 客单价。 养用 的
用习 ,刺 其 购。可 消 推送、站内广 推送 触 ;

·衰退期:建立用 预警机制,对用 进行 挽留,提升


用 度,可 短 / 件/主动 呼 触 ;

· 期:由 验可知获取一 新用 的成本相比挽留一 用


的成本普 高5 以上, 此 对已 用 进行 ,可 短
/ 件/主动 呼 触 。
9.3.3 画像 生命 期 的应用
用 画像 端可帮助 务 速分 生命 期不同阶 用
的特征、 适的 触 用 。

1.分 用 特征

前面的介 ,读 已 知 如 对用 进行生命 期的划


分, 端可 出生命 期不同阶 的用 ,
视分 功 (详见7.5 ),分 不同阶 用 的特征,如 9-12
示。

9-12  视分 用

2. 触 用
根据前面 讲, 生命 期不同阶 可 不同 (消 推
送、站内 、短 、 件 )来触 用 。画像 的用 分 功
支持 组 好用 , 后以 种方 触 到用 (详见
7.4 ),如 9-13 示。

9-13  触 用

3.分 营 效

画像 端 定用 后,将对应的 id写入到Hive相应表
。数据分 师可以从Hive表提取相应数据分 营 效 。

此 , 触 用 (包 消 推送、弹窗、推荐、短 、
件、电话 呼 )的 程 ,不同 的触 成本是不一样的,
触 用 时一方面需要 虑营 成本;另一方面需 排除 同时
触 用 ,给用 造成骚 的 况。 这 是可以 用 画像
排重功 进行控制的。
9.3.4 应用
一:消 推送新安装用 提高用 册率

务 景: 平台新安装用 正常 册率一 持 30%左 ,


用 的 册对后 的下单、 购 行为有重要的 用。提高新用
册率是运营 努力的方 。

解决方 :根据数据分 现,80%的 册用 是 安装3日内完


成 册行为的,新安装3日内成为一 重要时 。运营 用画
像 定安装3日内的用 ,将新 包、 券 动, 消
推送 推送给该 用 。 A/B 试 现,消 推送后的 册率
比未推送前提升 15%。

二:短 营 新 册用 提高下单率

务 景: 平台新 册用 正常下单率 20%左 ,为提高新


册用 的下单 化,运营 近期要对 婴 一次营 动。

解决方 : 数据分 现,76%的下单用 是 册后前9日


内完成首次 易的,新 册9日内成为一 重要时 。运营
用画像 定新 册9日内,并且 览/收藏/加购 婴 的用
,将新 包到期提 及 婴 成文 , 短
推送给该 用 。 A/B 试 现,短 营 的该 用 的下
单率比未 营 的新 册用 下单率提升 6%。

三:用 全生命 期营

务 景: 平台为对用 全生命 期营 ,对不同阶 用


站内广 弹窗 落 页的分组展示,评 用 从 览、 到最终
化 程的差 。 这 程 , A/B 效 试 代出更好的
用 运营 略。
9-14 不同阶 用 运营 略(示 略)

解决方 : 务 根据用 生命 期 阶 不同, 制定运


营 略时创建 3组 ,同时为 组 分别设 控制组 对照
组, 不同分组的弹窗来 试 (见 9-14)。

为分 触 不同阶 用 利益 , 务 对用 状 3 分
组, 分组分别设 控制组 对照组, 不同分组的弹窗展现
来 试 (如 9-14 示)。

进一步根据运营 略 画像 定好 ,并 推送到对
应的 务 (如 9-15 示)。
9-15  助画像 定

务 画像 组 用 定 并推送到广
,进一步 ERP的广 根据创建的 ID 号 对应的弹
窗、落 页、文 材(如 9-16 示)。

9-16 不同组用 弹窗入 (示 片)

AB组 上 运营后,BI分 师 报表 日监 不同
的 化 况。 分 ,有弹窗用 详 页 化率、加购 化
率、下单 化率、购 化率 方面表现 好 无弹窗用 组(如
9-17 示)。
9-17 报表 用 化(示 表)

试,用 的 务 决定对不同阶 用 用
首页广 弹窗这一 略来提高用 化率。
9.4 高价 用 实时营

9.4.1 项目应用 景
平台运营 为 进高价 新用 的留存,制定 运营规则
——“首日 册的新用 ,如 其 册当日消费 100元则对其进行短
营 ,短 附有平台 送 包的 接”。

如 用 甲,上午 平台 册后消费 60元,下午 平台消


费 50元,此时该用 平台 册当日 计消费 110元,则立马对其
送短 进行营 ,营 短 附有平台 送的 包,以更好 留存
该高价 新用 。
9.4.2 用 画像切入
该 务 景下需要用实时数据进行支持,Spark Streaming将从
Kafka 取的数据解 后写入 存表,这里由 需要 计新用 当日的
计 额 以 用到 存表。 后对 存表 的明细数据进行
计后写入到HBase ( 9-18)。

9-18 实时 调用方 设计
9.4.3 HBase应用 景小
本 我 用HBase存储用 实时数据, 画像实 应用
HBase 景下 可 为服务层提 接 服务, 来说HBase可
存储离 数据 实时数据 上接 调用( 9-19)。

·离 写入: 数 ETL 将 写入Hive表 的数据生成


HFile 后buckload到HBase对应的表。 景示 : 7.4 ,当
务 需要调用HBase 数据时,可以 将 ETL后的 数据
先离 写入Hive表 后将Hive表buckload的方 将 数据写入HBase

·实时写入:SparkStreaming/Flink实时消费Kafka 存储的 上
数据, 单 理后写入HBase , 接 实时调用HBase 数据
运营用 。本 讲的高价 用 实时营 就是一种实时写入的应用
景。
9-19 数据写入HBase 景

本 介 实时写入HBase的 景,下面再看一种离 写入
HBase的 景。

运营 画像 出 其运营条件(如 规则A则触
推送 券)的用 ,将该 分 推送到 上营 (
如推送到HBase表usergroup_HBase )。

用 甲(用 id:66600723) 该 务规则A,被 入该


。当该用 触 规则时, 上接 送该用 id,请 询HBase表
usergroup_HBase,判断该用 上 是 组 的条件,当
其 推送 券的条件,对其进行 券的 送。如 用 不
该规则A,则不对其 送 券。

关 离 写入HBase的工程化实现方 可参见3.3.3 内容。


9.5 短 营 用

9.5.1  景
平台上 消 牌 家 日常 运营客 程 现,目前
消 同质化严重, 牌 竞 ,虽 用 购率 高 是
诚度 低,用 普 对 动的敏 度 。 此,可 对 消
牌的易 ,定期 短 准触 目 用 , 导其进行
购。
9.5.2 画像切入及其应用效
家 助画像 进行短 营 定目 用 的时 ,主
要从以下几 方面 虑建立 务规则:

1)短 敏 度:有的用 对营 短 的敏 度 差,比如从历


数据来看,推送给其10次短 , 开 一次 从未 开 。 虑到
短 营 需要成本,需要对这 用 进行排除,减少对用 的

2)无效 机号:对 平台上随 写非 己的 机号、 机号


已 废/更换, 对 接收到的短 “TD”的用 来说,短
无 接收,属 “短 黑名单”用 ,同样需要对这 用 进行排
除。 9-20 的示 数据显示 排除黑名单用 对营 效 的提升程
度。

3)对营 兴 的用 :近期曾 次 览、收藏 有 加


购、下单行为的用 是对 存 的用 , 画像
出这 分用 , 减 券 包 利益 进行营 。

助画像 ,有效提高 短 送的 率 击率,如 9-


20 示。

日常生 我 也 常收到 的营 短 。 如,我5月


曾购 牌的牙 ,3 月 后,该 牌给我 送 一条营 短
( 9-21),此时我的牙 正好 用完 。其 推送短 时应该充分
虑 用 购 及 消 期,从这方面来看非常 用 购
需 。
9-20 短 营 效 分 (示 数据)

上面的 短 进用 的 购,同样可 短 营 用
推送 购 。 如, 次我购 到石家庄的机票,一 儿就
收到一条租 的营 短 ( 9-22),短 文 明 突出
这几 内容:①目的 有租 服务功 ;②租 的日最低费用;③租
券已到本 账 。对 有 飞机目的 市 驾出行需 的用
来说,这条短 是一条有用的 。

9-21  消 的营 短
9-22  出行 的营 短

用用 画像 ,从 适的时 适的 适的
对目 客 进行营 ( 9-23)。

9-23  准营 客 的
9.6 Session行为分 应用

9.6.1 关 用 行为分
用 行为分 是 获 站访 本数据的 况下,对有关
数据进行 计、分 ,从 现用 访 站的规 ,并将这 规
与 络营 略 相 ,从 现目前 络营 动 可 存 的
题,并为进一步 正 重新制定 络营 略提 据。

日记几 记 用 的 有行为,其 有 是 用的,


比如用 的访 频率、平 留时 ,有 是特定 景适用
的,比如盈利平台的下单行为、社区的内容 布行为 。用 行为的
相关 可分为黏 、参与度 、 化 ,下面详细进行
介 。

1.黏

一 需要关 的 是用 黏 ,如访 频率, 取 用


的 数,并 数对用 分 ,用 加百分比 来
对 的数据 展现,方 对比( :数据 为虚 数据),如
9-24 示。从 我 可以看出 1 的用 是最 的,可 这
分用 的规 ,定位这 分用 数少的原 , 后制定 适的
运营 略,尽 让 的 数提升。 对 数
6 的用 ,可以将这 出来,看平台的 实用 致 况及
诚度比 。
9-24 用 分布示

9-25是带平 曲 的散 ,显示的是近60 访 的用 的
最近一次访 离当前时 的 隔 数的用 分布, 表示的是最
近一次访 的 隔 数, 表示的是对应 隔 数的用 比 ,从
可以直观 看出 时 隔对应的用 况, 用 的
生命 期来看,我 可以将访 数 10 的用 定义为 默用
。可 对这 分用 细分看用 为 隔这么 有访 ,比如看
最后一次访 看 么内容, 对这 用 的特征进行分 ,
将 准 质的内容推送给这 用 看挽 的用 比率, 取 分
用 进行调研,寻 的 分可以 化。
9-25 用 访 期示

接下来是看用 的留存,用 留存的本质是 ( 站) 用


需 。要分 留存,我 首先要 留存的定义,留存是 用
下一 时 有 少用 仍旧 的比 。 时 分 有次日留
存、7日留存、15日留存、 留存、月留存、季度留存 , 分
有App留存、H5留存、Web留存 , 用 分有新用 留存、 用
留存 。一 来说, 用 的留存 高 新用 的留存,这 可以
用来进行数据 验。新用 的留存主要取决 用 的来
导。对新 用 细分的留存分 就是数据驱动运营的典 应用,比
如 用 留存的分 可以对运营质 监控, 对新用 留存
的分 可以 出 质的 。

9-26以细分 用 留存来 一 子,从 可以看出,对


言,App的留存要 H5及Web,这 智 机的普及是分不
开的。还可以细分看3端留存的新 用 的占比及 端 移用 的留
存,及 端细分 的留存对比,评 质 。
9-26  用 留存示

2.参与度

二 需要关 的 是用 的参与度。 度 为评判用 参


与度的一 关 ,并 有 准定义, 常 的是完成 一关 动
的用 , 参与 况 一条件的用 。比如电子 务 站的
下单、社 的互动、视频 的视频播放, 登 、消费、
用 可定义为 。 用 关 定义, 有准确定义 用
,我 解 用 的 况。比如 初期,为 数据
看 来好看,数据可 定义 比 宽 ,比如 就 , 有
对 用 的定义比 严谨,比如 有消费 的用
,这样数据出来虽 比 小,看 来 的 用 比 少,
是这样定义的 用 是 的盈利用 ,用该 来 映 题
比 敏。

我 以定义登 ( 站)即称 为 来 , 登
( 站)来 , 时 分 可以 分为日 (日 用 ,DAU
—Daily Active User)、 ( 用 ,WAU—Weekly Active
User)、月 (月 用 ,MAU-Monthly Active User),一
用DAU/MAU来 为 站的 开率 ,该 越 说明
站的 开率越高。
用 的分 主要有对比分 及细分。对比分 主要可以看时
变化趋势及竞 数据对比。这 分 比 直观 映 的用
趋势,也 比对 己 同 的 致 况,以 更
好 制定 下一步的目 及 。如 DAU有一 时 明显,此
时并不是数 越 越好,需要细分看这 用 的留存及其 化 况。
为 有可 是 动 一 用 , 这 用 具 质 如 ,需
要进一步分 。

表示用 参与度的另 两 是用 的 留时 及用 的访
页面数。为 么要用这两 来表示用 的参与度 ? 为用 的
留时 可以 接 映 页对用 的 程度,可以 接 映 是
用 的需 及 页面的设计是 理。对 盈利 来
说,其目 就是 化,让用 下单,如 用 下单前的 页面
, 这 用 就 有完成 化。从 9-27来看,用 有 页面
A、B、C, 到 目 页,完成 化。则用 页面A的 留时 为
用 离开页面A的时 –用 进入页面A的时 ,用 到 目 页前共
访 3 页面,这3 页面分别是页面A、页面B、页面C。

9-27 用 访 页面示

比如我 随机生成一组数据,如 9-28 示,看下用 的平 访


时 及平 访 页面, 现 三 的时 这两 剧下降。
事出 有 。此时需要详细定位原 ,是 数据 有上报,还是日
解 出 题?如 数据 有 题, 么是 改版后 有 导机
制,用 不到入 ,还是 改版后新加 程,比如实名
强制 措施,用 对新 不 ?这 需要数据 根据一
列 设定及 来具 定位。

3. 化

三 需要关 的 是用 的 化。分 用 的 径 化主要


有3 用:一是 数据 用 的访 细 ,访 细 映的是用
的行为特征, 访 细 来推 用 的 理 动;二是
用 的访 行为来 用 访 程 可 碰到的 难,看整
径 运营 前设 的是 一致,如 不一致,是 环 不一致,定
位具 的原 ,调整页面布局;三是 用 的访 径的 程
,寻 有价 的可 代 径,对 进行 化。

9-28 用 参与度示

要分 用 的 化 况,不 需要熟知 务 程,也需要熟知数


据 程,即将 务 程 化成数据 程。由 互 行 独有的日
数据 记 用 的 有访 行为,故我 需要熟 务的设计
程,对 务的细 程及数据上的记 、获取、 字
,将 务 程 化为数据 程,再将数据 务 , 住 务
的关 径,层层剥离 解再组 ,即可 成 务 化的完整分
。对 App 可用Charles Fiddler 包工具 试 关 。

分 用 的 化 况可以从两 的方 着 ,一是从 的整
运营 况来看,用 从 到下单的整 程;二是从细分 的
关 径来看,用 接触 到完成 化 历的步骤,这 已
8.1.4 详细 。下面就 一 应用 景进行 说明。

9.3 我 列 运营 景 的 有 化 ,如 9-29
示。
对这 关 的数据监控,我 可以从整 及细分 、
细分时 、细分 动来看不同的 化 况,如表9-2 示。 出有
题的 化 。比如细分 的 景下, 设 是 用
费,从 两 进来的用 后 的 化行为如表9-4 示, 是来评
判这两 的质 劣, 同 用 的 况下,我 应 么判
断 ?

9-29 用 化 一览
表9-4  质 监控

设 用 为10000 ,将 化 的 化为成本绝对
,如表9-5 示。

表9-5  成本监控
显 ,从成本的角度来说, 1要 2。当 ,后 我
也需要分 不同 进来的用 的ARPU,看整 的营收 况, 评
的整 质 。
9.6.2  景
这里首先 一 典 的 景来介 用 访 Session分 应用的
景。

用 进入电 站 App的一 典 程包 ,进入首页后搜


关 词、 击 击推荐 进入详 页, 详 页 览
击加购后退出该页面搜 其 览,最后进入订单页进行支
, 览 退出App。这一 列行为就是用 的行为 ,如 9-
30 示,对 用 这样的 访 话,我 称 为Session。

9-30 用 访 行为

Session 记 用 么时 , 么样的行为, 览
么页面/ 。一 Session的切割为 定时 ,如定义App端
Session的切割时 为5分 时,即用 次访 行为如 离上一次
访 行为 5分 内,则记为同一次访 ,如 离上次访 5
分 则记为两次不同的访 。 session_id可 识用 的访 ,同
一次 访 的session_id相同, 则不同。

Session对用 进行分 具有非常重要的 用,可以从用 的


访 次数、访 径、访 度分 用 特征。进一
步 分 用 首次访 的Session对 掘 用 购 行为具有重要
的 义。
本章介 的Session访 行为分 是 对4.5 介 的用
特征库进行二次开 的 础上,进一步 掘用 首次访 的行为特
征。下面 详细的介 。
9.6.3 特征 建
新用 首购当次Session 购当次Session的行为分 特征
建的 程 ,可 4.5 建的特征库进行二次开 。 日期分区
记 新访 用 的特征,可从行为事件、 、 特征、
览时 度 建特征 。

与4.5 介 的用 特征库不同的是,4.5 建的特征库是记


用 一次行为的明细, 本 是对用 首访行为进行 ,将其
成一条记 。表 设计参 度表9-6 示。

表9-6 Session分 特征库

下面 介 如 取用 首次访 的Session。
这里有一 记 用 击行为日 的底层
表‘ods.click_event_log’表,从该表 对当日访 的新用 当日
访 时 正排序,取 一次访 时 对应的sessionid,即是用 首
次访 的行为记 。示 代码如下:

select cookieid,
sessionid
from ( select cookieid,
eventtime,
sessionid,
row_number() over(partition by cookieid order by eventtime
asc) as rank
from ods.click_event_log # ODS层 击事件表
where data_date = "data_date" # 当 日期分区
and is_newuser = 1 # 判断是新用
and cookieid is not null
and cookieid <> ''
) t
where t.rank = 1
group by cookieid,sessionid

上面的建 ,最后 到用 首次访 行为特征的Session表,


如 9-31 示。

9-31 Session分 特征数据 示

后 进一步对用 访 特征的Session表进行 视分 ,可以从


度 掘用 首访特征。
9.6.4 分 方 与 论
对 建的首访用 行为特征进行 视分 ,可以从用 访
径、访 、 览 价 区 、对 敏 程度 度
掘首访用 特征。

下面 对用 访 径进行分 的实 来介 。

// 创建SparkSession
val spark = SparkSession
.builder()
.AppName("FirstSessionAnalysis")
.config("spark.testing.memory","2147480000")
.master("local[*]")
.getOrCreate()

// 读取原数据 下单用
val peopleRDD =
spark.sparkContext.textFile("C:\\Users\\king\\Desktop\\cookiesession.log")
.map(_.split(",")) // RDD[Array[String]]
.map( row => Row(row(0),row(1),row(2),row(3),row(4))) // RDD[Row]

// 表
val schemas = "cookie,event,ispaid,data_date,time".split(",")
.map(fp => StructField(fp, StringType))
val schema = StructType(schemas)

// 创建视
spark.createDataFrame(peopleRDD, schema).createOrReplaceTempView("people_feature")
spark.sql("select * from people_feature").show(20,50)

看表 如 9-32 示,可以看出分 用 Session行为 径包


以下字 :
9-32 用 首访Session原始数据

·cookie:用 id。

·event:用 访 事件,如 击加购、访 页面 。

·ispaid:用 本次行为事件是 支 ,支 为1,未支 为


NULL。

·data_date:访 日期。

·time:本次行为事件的时 。


首访的Session数据,可以 掘用 集 时 访
、集 访
事件是 、主要 行为事件后 出 访 、
行为事件 进 最后下单、访 时 与访 的 加是 进下单
度的内容。

下面 对 用 首访Session进行 掘分 的 来介 ,
Scala代码示 如下。

val test1 = peopleRDD.map { row => {


val id = row.getString(0)
val event = row.getString(1)
val result = row.getString(2)
val time = row.getString(3)
val isOrder = row.getString(4)
(id, event,result ,time, isOrder)
}} // RDD[(String, String, String, String, String)]

val orderedSessionEventRdd = test1.map { f => (f._1, (f._2, f._3, f._4,f._5)) }


.groupByKey()
.mapValues {
itor => {
val eventLst = itor.toList.sortBy(f => f._4)
// 进入日期
val data_date = eventLst.head._3
// 进入时
val startTime = eventLst.head._4
// 离开时
val endTime = eventLst.last._4
// 进入事件
val startevent = eventLst.head._1
// 离开事件
val endevent = eventLst.last._1
// 访 时
val start = data_date.toString + " " +startTime.toString
val end = data_date.toString + " " + endTime.toString
val visitdiff = DateUtils.timeDiff("2019-01-12 03:22:39", "2019-01-12
03:22:49")
// 首 Session内是 下单
val ordered = if (eventLst.head._2 == "NULL") "0" else "1"
// 访 页面数
val visitnum = eventLst.length.toString
// 出时
val lastEvent = eventLst.last._1
(eventLst.mkString(""),
startTime,endTime,startevent,endevent,ordered,visitnum) // 次数 时
}
}

val rowRdd = orderedSessionEventRdd.map(tp => {


val id = tp._1 // cookie_id
val eventLst = tp._2._1.mkString("") // event_cts
val startTime = tp._2._2 // startTime 进入时
val endTime = tp._2._3 // endTime 离开时
val startevent = tp._2._4 // startevent 一 访 事件
val endevent = tp._2._5 // endevent 离开时事件
val ordered = tp._2._6 // ordered 是 下单
val visitnum = tp._2._7 // visitnum 本次访 少 行为
Row(id, eventLst, startTime, endTime,startevent, endevent, ordered, visitnum)
})

val sct = StructType(


Seq(
StructField("cookie_id", StringType),
StructField("eventLst", StringType),
StructField("startTime", StringType),
StructField("endTime", StringType),
StructField("startevent", StringType),
StructField("endevent", StringType),
StructField("ordered", StringType),
StructField("visitnum", StringType)
))

spark.createDataFrame(rowRdd, sct)
.createOrReplaceTempView("v_tmp_session")
// 看 理后的数据
spark.sql("select * from v_tmp_session").show(20, 40)

对RDD进行 理后,表 主要包 以下字 :

·cookie_id:用 id。

·eventLst:用 访 事件列表,将用 本次Session 一 访


事件、是 下单、访 日期、访 时 为列表 一 元 进行存
储,数据 如“(App_open,NULL,2018-12-30,03:30:40)
(loginreg_view,NULL,2018-12-30,03:30:42)
(loginreg_next_click,...”。

·startTime:用 本次Session开始访 时 。

·endTime:用 离开本次Session的时 。

·startevent:用 本次Session 的 一 行为事件。

·endevent:用 本次Session 的最后一 行为事件,即退出


本次Session的事件。

·ordered:用 本次Session访 是 下单。

·visitnum:本次Session访 的行为事件数 。

用 首访Session行为事件分 示 如 9-33 示。

9-33 用 首访Session行为事件分
除 以上 度的分 ,还可以进一步从用 的访 时 、访
隔 其 度 入 掘用 访 特征。

Session分 还可以 到用 行为 径, 径分 记 用
次访 的顺序, 可以 观察 一关 前后的
进入 况。 化关 分,可以提升这
的 化效率。

val orderedSessionEventRdd = test1.map { f => (f._1, (f._2, f._3, f._4,f._5)) }


.groupByKey()
.mapValues {
itor => {
// 事件的时 次排序
val eventLst = itor.toList.sortBy(f => f._4).map(p => p._1)

val firstpath = eventLst(0)


val secondpath = if (eventLst.size >= 2) { eventLst(1) } else{ null }
val thirdpath = if (eventLst.size >= 3) { eventLst(2) } else{ null }
val forthpath = if (eventLst.size >= 4) { eventLst(3) } else{ null }
val fifthpath = if (eventLst.size >= 5) { eventLst(4) } else{ null }

val paths = firstpath + ',' + secondpath + ',' + thirdpath + ',' +


forthpath + ',' + fifthpath
paths.toString // 前5次行为访 径
}
}

val rowRdd = orderedSessionEventRdd.map(tp => {


val cookieid = tp._1 // cookie_id
val eventLst = tp._2 // event_cts
Row(cookieid, eventLst)
})

val sct = StructType(


Seq(
StructField("cookie_id", StringType),
StructField("eventLst", StringType)
))

spark.createDataFrame(rowRdd, sct)
.createOrReplaceTempView("v_tmp_session")

spark.sql("select eventLst, count(cookie_id) as num from v_tmp_session group by


eventLst order by count(cookie_id) desc limit 20")
.show(20, 130)

用 的访 径(如 9-34 示),可以 解用 前5次访


集 行为。
根据用 的访 径进行分 ,对 设计的改进有 帮
助,分 用 从登 、搜 、 览详 页到购 的行为 径,根据用
环 的 化率 现用 行为 好 订单 化的主要 。

从 9-35的 可以看出用 进入App后 一次访 的


去 。

9-34 用 前5次访 径

9-35 用 访 Session

从 9-36可以看出未购 用 分时 览Home主页面,其
次 是 详 页, 首购 购用 分时 详 页,其
次是 目页面。由此建议 对未购 用 访 的页面 用 好,
提 更 用 兴 的 。未购 用 有6%访 购物 页面,与
购 用 占比相同,建议 购物 页面 加“ 减 券/再购xx元包
” 提 ,以减少有购物 的用 的 。
9-36 用 session访 页面分布(示 数据)
9.7  效 监 报表搭建

9.7.1  景
务方 应用画像 进行 营 时, 运营
希望 动收到监 报表来 诉 己目前应用 务
的后 访 、下单 化 况,以 对运营 略有 化调
整, 运营更加有的放矢。 是画像 的开 面 务方
搭建 一套 效 监 的 动化报表。
9.7.2  理
搭建 监 报表时,主要分为两 阶 ,首先从相关的Hive
表 提取数据,关 分 成一 宽表, 后整理好一 Excel报表
,最后 动报表 件 定时 Hive 务,将数据插入到Excel
报表 后 动 送。

下面 一 次 解 环 的实现方 。

1.数据提取

负责对接用 主动 呼营 的运营 , 画像 上
到 务 后,后 需要进一步监控该 分 的访 、下单
化 况。

根据 务方 定的规则, ‘10003’‘10004’创建后上 到
件营 (见 9-37)。

9-37  务方 定目 用 呼

insert overwrite table dw.user_group_info partition(data_date ="data_date")


select groupuserid as user_id,
case when groupid='10003' then '核 费用 '
when groupid='10004' then '近7日新 册女 '
end group_name
from dw.userprofile_usergroup_labels_all
where data_date= "data_date"
and tagsystem = 'email_system' // 件 id 号
and groupid in('10003', '10004') // id 号
2.报表 动化

整 来说, 好一 化的Excel数据 理 需要分三步 :


一步需要根据分 的内容及 ,设计好报 的 现内容与 现
,即根据分 度搭建数据报 的 。可以先 动设计好报 的
版 ; 二步厘 的 关 ,明确报 的 现内容,设计
报 的内容实现 ,建立数据 表 数据 化表; 三步 照设计
调整报 元 及 ,设计 动化 程。 从数据 表导入数据即
可 报 正文页 到最终 现的 。实现 程如 9-38 示。

9-38 Excel报 动化 程

数据 库:对 务数据及日 数据 数据 集成存


储的 化集成环 ,需要数据分 师 用HQL语言从数据库 提取数
据;

原始数据表:是用 存放 次 报 需关 数据的 表,
一 用HQL语言 初步的数据 及数据预 理(如 、排序、离
散、 换 )从数据库 提取出来;

化数据表:用来动 用数据 的数据,并进行相应的


数据 化、 计 、 表绘制及 报文字组 工 ;

Excel日报正文:根据分 ,组织 用“数据 化区 ” 相


应组 好的数据、 报文字及绘制好的 表,以一定 现出来。

接下来 一 Excel运营数据日报来 说明 化数据 理


报 是如 创建的。

从数据 表到数据 化表

本小 将对上一 介 的数据 表 数据 化表的创建 程展


开详细介 。Excel原始数据sheet用 存放从数据 库 提取的原始
数据 二次计 到的数据。一 分为原始提取数据、计 数据
助数据3 区 。如 9-39 示。

9-39 Excel原始数据表

提取数据区 用 存放从数据 库 原始提取出来的数据; 助


数据区 用 存放一 时的参数, 为 助列 计 另一列数
据;计 后数据区 用 存放 计 到的 数据。

Excel 化数据表的创建是整 Excel 动化 理 最为


关 的一环。 对数据 表建立动 的数据 用, 用数据 表的
相关 。 数据 化表 主要用到 日期控件、MATCH函数、TEXT函
数、OFFSET函数 INDEX函数。下面我 分4步详细讲解数据 化表的
建立 程。

一步,设 日期控制单元
助日期控制单元我 可以 看目 日期的数据, 用
控制可以 动调整相应数据列变化。

首先我 开Excel表 , “开 工具”的“插入” 项卡下面


的“表单控件” 二 项组 ,如 9-40 示, 表 的
空白区 曵鼠 即可生成控件。

击该日期控件 “设 控件 ”命令,如 9-41 示,


弹出的“设 控件 ”对话 击“数据 区 ” 项的 ,
进入到数据 表 对应的日期,如 9-42 示, 确认操
。 后设 “单元 接”,即当我 控件日期后存放相应数
的位 。这里我 放 数据 化表日期控件的旁 ,如 9-43
示。

9-40  日期控制单元控件
9-41 “设 控件 ”对话

9-42  数据 表 的日期
9-43 日期控件的 用

至此,当我 数据 化表的日期控件 对应的日期时,旁


单元 即可显示该日期对应其 数据 表 的位 。接下来我 将
Excel函数建立 数据与日期控件 的关 , 改变 日期
时,对应的数据列 成相应变化。

二步,从原始数据表动 用数据

这里我 Excel函数从原始数据表 取报 需的 分数
据, 取的时 ,由上步骤的日期控制单元 控制。时 度可
根据 务需要进行调整。这里我 详细讲解数据动 用 涉及的函
数。

OFFSET函数以 定的 用为参照 , 给定 移 到新的


用。 的 用可以为一 单元 单元 区 ,该函数的 如
下:

OFFSET( reference, rows,cols,height,width)

OFFSET函数是 移单元 用的函数,这 移不是原始单元 内


容的 移, 是 用单元 的 生 变化。该函数 的 参数
义如下:

·reference:是 移的 , 为 移 的 用区 , 须为对
单元 相 单元 区 的 用;
·rows:是 移的行数(其 正数表示 下 移,负数表示 上
移,0表示不 移);

·cols:是 移的列(其 正数表示 移,负数表示 左


移);

·height:是 要 的 用区 的行数;

·width:是 要 的 用区 的列数。

当 参数是正数的时 ,单元 用区 是以 位移
单元 为左上角。如 不 改变 用区 的 小, 、 参数可
以省略。 单元 入公 后需要同时 下Shift+Ctrl+Enter ,组
完成 入, 入后 显示公 用 号 来,此时表示公
效 。如 9-44 示。

9-44 OFFSET函数的 用方

当记 日报 数据时,数据是从行上不断 下 加的, 以应
定单元 的上方。

INDEX 定位 的内容,该函数的 如下:

INDEX(array,row-num,column-num)
·array:表示要 数据的区 ,其 为单元 区 数
组;

·row-num:要 数据 的行号;

·column-num:要 数据 的列号。

INDEX函数 该数据 理 的 用方 如 9-45 示。

9-45 INDEX函数的 用方

MATCH函数可 单元 区 搜 定项, 后 该项 单元
区 的相对位 。该函数的 如下:

MATCH(lookup-value,lookup-array,match-type)

·lookup-value:表示要 的 。

·lookup-array:表示要搜 的单元 区 。

·match-type: 定如 lookup_array lookup_value。


其 1表示 小 lookup_value的最 ,lookup_array参数
的 须 升序排列;0表示 lookup_value的 一 ;-1
表示 lookup_value的最小 。

MATCH函数 该数据 理 的 用方 如 9-46 示。

三步,报 的 报文字

报 的 报文字一 包 两 分,一 分是 题;另一 分


是数据表的 论。 报文字 分可分为 定不变的文本 随日期变化
的数字 分。我 将其放 相 的单元 , 定不变的文本 持不
变,随日期变化的数据我 用TEXT函数对其进行 化,最后
用“&” 接 将文字描 数字进行组 ,效 如 9-47 示。

9-46 MATCH函数的 用方

9-47 组 报文字及对应数据
用TEXT函数可将数据 化成 定的 。该函数 如
下:

TEXT ( ,“数字 ”)

· :是单元 内存放的原始数据;

·数字 :将原始数据 化成我 期望的 定数据样 。

步,制 关 表

先 数据 化表 出单元 数据相关 表,由 单元 数据受


函数控制动 用,当改变日期控件时,单元 数据将 随时 改
变,同时 表也 同步更改。最后 报 正文 用数据 化表 的
表,同样可实现当改变日期控件时 时, 表 相应调整。如 9-
48 示。
9-48 数据 化区关 表制

如 说“原始数据”表存放的是原始 ,“数据 换表”存放


的是 理、加工的数据 草稿, 么“报 正文”表就是这
数据 理 的“ 面” 。它 读 展现 整 数据日报的核
、关 内容(如 9-49 示)。

报 正文除 需要 持 的准确 、 ,还需要 持页面


的干净整 。对 动化报 ,我 不同的日期时要 证报
的正文展示区 动随 改变。为 让 读界面更加 ,我
可以对 要展示的 (如工 表、单元 题、 )进行
隐藏。

更多书籍访问:www.j9p.com
9-49 报 正文展示内容
9.7.3  动报表 件
为 减少重 工 ,数据提取 可以 用Python 动化 本
定时 务。将写好的HQL语句放入Python 本 ,并 服务 上设
crontab定时调度 务, 证 定时 动从数据 库 提取数据后,
将 集写到Excel 并 送 件到数据需 方的 。Python 本代
码示 如下(auto_email.py):

#coding: utf-8
search_data = """ 创建 时表 询昨日运营数据"""
report_data = ''' select * from 上一步创建的 时表 '''

import psycopg2
import smtplib
import os
import openpyxl
import datetime
from impala.dbapi import connect
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
import pyhs2 # Hive环

wb = openpyxl.load_workbook('/home/path/username/daily_report_v1.xlsx') # 开服
务 存储 径下的Excel文件
# 接Hive环
impala_conn = pyhs2.connect(host='10.xx.xx.xx', port=xxx, authMechanism="PLAIN",
user='username', password='password', database='dwd')

seo_h5_1 = impala_conn.cursor()
h5_result = impala_conn.cursor()

seo_h5_1.execute('''SET mapreduce.job.queuename=root.yydata''')
seo_h5_1.execute(search_data) # 行HQL语句

# 取出数据
h5_result.execute(report_data) # 取出数据
h5_result = h5_result.fetchall()

#放到sheet里面去
sheet = wb.get_sheet_by_name('daily_report') #daily_report表

# 除历 数据
for i in range(2,sheet.max_row + 1 ):
for j in range(1,sheet.max_column + 1 ):
sheet.cell(row=i,column=j).value = ''

# 充 数据
for i in range(2,len(h5_result) + 2 ):
for j in range(1,len(h5_result[i-2]) + 1 ):
sheet.cell(row=i,column=j).value = h5_result[i-2][j-1]
#关 Hive 接
impala_conn.close()
wb.save('/home/path/usernamet/daily_report_v1.xlsx') # 存Excel文件
receiver = 'receiver_email@xxx.com' # 收件

date_str = datetime.datetime.strftime(datetime.date.today()-
datetime.timedelta(days=1),'%m%d')

mail_txt = """
Dear All,
附件是 监 日报,请 收。
"""
msgRoot = MIMEMultipart('mixed')
msgRoot['Subject'] = unicode(u'日报-%s' % date_str) # 加日期
msgRoot['From'] = 'sender_email@xxx.com'
msgRoot['To'] = receiver
msgRoot["Accept-Language"]="zh-CN"
msgRoot["Accept-Charset"]="ISO-8859-1,utf-8"

msg = MIMEText(mail_txt,'plain','utf-8')
msgRoot.attach(msg)
att = MIMEText(open('/home/path/usernamet/daily_report_v1.xlsx', 'rb').read(),
'base64', 'utf-8')
att["Content-Type"] = 'Application/octet-stream'
att["Content-Disposition"] = 'attachment; filename="日报2017%s.xlsx"' % date_str
msgRoot.attach(att)
smtp = smtplib.SMTP()
smtp.connect('mail.address.com')
smtp.login('sender_email@xxx.com', 'sender_password')
for k in receiver.split(','):
smtp.sendmail('receiver_email@xxx.com', k, msgRoot.as_string())
smtp.quit()
9.8  用 特征库 目

9.8.1  景
前面章 的 是 电 务数据 建的用 特征库,这
里介 另一种 医疗 务 景下 建的用 特征库及其应用方 。

互 医疗 上入驻 行 内几十万名专家 医生,用


该 Web端、App端 H5页面上 与要 询疾病相关的专家,并预
后,可以以 片+文字、语音 话、视频 方 专家 询相关
疾病。专家 出解 后,用 确认 并 写评价。根据用 该
上的 务订单与行为数据,可充分 掘用 疾病特征,以 准营
适的医疗服务与 。

目前该平台的数据 库 积 订单数据及用 行为数据,


为更好 支持运营 将相关 动 准推送给有需 的用 ,数据开
将根据用 的订单、行为相关数据进行建 , 建用 行为特
征库。
9.8.2 应用方 及效
创建用 行为 表dw.peasona_user_tag_relation, 用
特征库的表 , 该医疗 务 景下对字 的定义 如表9-7 示的
调整。

表9-7  医疗 景用 行为 表

景1: 对近期 诊的用 有 冒、 、 痛 疾病的


用 营 相关的医疗服务与 。

根据 务需 ,从用 行为 表 取相关的 准用 。

select userid
from dw.peasona_user_tag_relation
where data_date >= '20190101'
and data_date <= '20190106'
and (eventtype = '1' #用 诊医生诊断疾病
or eventtype = '2' #用 诊评价 写疾病
or eventtype = '3') #用 诊医生擅 疾病
and (tagname like '% 冒%' or tagname like '% %' or tagname like '%
痛%')
景2: 动期 ,平台要 对 医院的一 重 科室医生
营 相关医疗服务,需要 准 取一 近期 该医院 诊 的用 。

select userid
from dw.peasona_user_tag_relation
where data_date >= '20190101'
and data_date <= '20190106'
and tagtype = '4' # 为医院
and tagname = 'xxxx 医院'
and eventtype = '5' #用 诊医生对应医院
9.9 本章小
本章 10用 画像 务 景 实际应用的 讲解 用 画
像 消 推送营 、A/B 效 试、用 生命 期营 、用 VIP
专属客服 景 的应用。9.7 讲解 如 搭建报表 画像 推
送 务 的 数据 务上的应用效 。

从上 前后的数据分 效 来看, 对 的 细化运营,对


、GMV、用 验 有显著的 进 用。
附   用 画像项目规划文
下面是一 画像规划说明 ,希望为需要写文 的读 提
一种 方 。

文 记 :

摘要记 :

变更记 :
1  言

1.1 项目名称

×××用 画像及其应用

1.2 项目 景及 要

互 步步入 数据时代后,不可 免 给 用 行为
带来一 列改变与重 ;其 最 的变化莫 ,用 的一切行为
面前 是“可视化”的。随着 数据 术的 入研究与应用,
的专 日益 样利用 数据来为 细化运营及 准营 服
务,进 入 掘 的 价 。 是,用 画像的 也就应运
生。

用 画像可以 的服务对象更加 ,更加专 。本项目分


别从用 属 、订单消费、行为属 、用 好、疾病 诊
、客 度6 角度 建用 画像 ; MySQL(关 数据
库) 数据平台进行 集分 ,分别从用 别、 内容、行为
特征及 务 景 方面进行数据 ,实现 与应用 景
数据共 , 用千 千面 方 进行UI数据可视化展现,实现 细化
运营及 确营 服务。

1.3 项目目

全 务运营下,用 画像及应用 MySQL(关 数据库)


数据平台 集分 , 用 特征 封装成数据接 服务,实时推送
到一 ,将 数据变成生 力,项目实现目 如下。
一、用 画像 封装

(1) MySQL(关 数据库) 数据平台(Hive、HBase、


Elasticsearch )

包 础 与分 知识 ,实现用 特征全貌刻画。

(2) 种封装角度

分用 别、 内容、 务 景进行封装 。

二、接 数据实时推送

实现用 画像数据实时更新至运营及营 一视 (Web )


进行展现,并实时 馈运营及营 题, 证数据应用的时效

三、展现UI封装

用 画像,将推荐 应用端进行可视化展现,集
动运营,实现千 千面的运营效 。

1.4 项目适用范

1)运营决 :对运营的关 题进行决 。

2)运营分 :从事市 竞 分 、用 需 分 、 务分
工 ,主要负责用 需 的 现 目 确定,并 运营 划 评
的实施。

3)运营 划 :从事运营 实施方 设计,根据用 需 生成


创 ,将创 化为 略,并制订实施方 。

4)数据分 :负责数据 掘 数据分 支撑的全 IT支撑


5) 开 :应用 上推荐 实时调用画像 数据。


2  功 及

2.1  功

用 画像及应用项目包 底层数据 集 存储、画像


建、数据 应用3 层 , 功 如下:

2.2 

画像 分 主要分原始数据 计分 、 计 建 分
、 预 分 3 分,具 如下:
3 需 设计

3.1 用 画像

【需 说明】用 画像 是 用 本属 分 ,对用 的
互 行为特征进行描 ,包 用 登 、搜 、关 、消费 方
面数据,对用 的疾病 诊、行为 好变化、消费订单 全 程的记
,以 方 展示 用 的 化特征,画像是 分 的
,是 数据 掘的 始。

【 务要 】用 画像 照数据内容 分为:用 属
、行为属 、资 消费、疾病 诊、用 好、客 度6

【核 描 】核 包 分 、分 、时 序列
分 、RFM 、推荐 、关 分 。

(1) 分

分 将看 无序的对象进行分组、归 ,以 到更好 理解
研究对象的目的。 要 组内对象相 高,组 对象相
低。 用 研究 , 题可以 助 分 来解决,比如用
度行为 、用 消费 况 。

(2)分
分 是 照 种 准给用 贴 ,再根据 来区分归 ,分
是事先定义好 别, 别数不变。根据用 的文化观 、订单消
费、行为习 的不同细分新的 别, 根据用 的不同制定 牌
推广 略 营 略,将资 对目 用 集 用。

(3)时 序列分

时 序列分 是一种动 的数据 计方 。该方 随机 程


理论 数理 计学方 ,研究随机数据序列 从的 计规 ,以用
解决实际 题。比如用 的 期 行为分 、 子 归分 建

(4)RFM

RFM 为动 显示 一 用 的全 轮廓,R表示用 购
的时 有 远,F表示用 时 内购 的次数,M表示用 时 内
购 的 额,加权 到RFM 分。

(5)推荐

利用用 的一 行为, 一 (协同 、LFM、 分


、关 分 )推 出用 可 欢的 。推荐讲究准确 ,提
高用 –医生(医院)–内容(订单、知识 ) 组 的匹 度,提
升服务质 。

(6)关 分

关 分 就是 关 数据 其 , 存 项目集
对象集 的频 、关 、相关 , 掘
的行为 消费关 特征。

3.1.1  属

【需 说明】 属 是用 的 本 ,这 往往是
用 册及 用 时记 的 ,如年龄、 别、 册时 、婚姻
状况、 高 重 。 属 刻画, 到对用 初步认知的目
的。
【 务要 】 属 分可从数据 库 直接获取,
分数据(生理)可 、疾病 方 非 数据 提 。

3.1.2 行为属

【需 说明】行为属 是 用 用 程 生的
,包 登 行为,挂号、 诊、协议 方、 险 订单以及平台
击、 览、关 、搜 、评价 互 行为数据, 础 计分
解用 的行为 期、习 好、关 内容 。
【 务要 】行为属 主要 订单以及前端的 数
据的 础 计分 获取,详细内容及 径如下:

3.1.3 疾病 诊

【需 说明】疾病 诊 是 用 挂号、 诊、 方数据提


取用 (用 )的疾病及 诊相关 ,并相应提取用 搜
、 览、关 、 击 互 行为相关的疾病 诊 , 数据
分 与 掘预 用 疾病 诊的 务需 .

【 务要 】疾病 诊 主要 分 挂号 诊订单以及
疾病关 数据,提取用 疾病及 诊需 的 务 ,详细内容
及 径如下:
3.1.4 订单消费

【需 说明】订单消费 是用 平台 用 程 进行
购 消费 的 , 分 务订单及消费数据 掘用 的消
费特征,以 为用 提 对 服务。

【 务要 】订单消费 主要从 务分 及消费 额 数据角


度进行 计 ,详细内容及 径如下:

3.1.5 用 好

【需 说明】用 好 是用 平台 用的一种 好
特征 习 ,重 分 用 常用 、 诊 、就医 好、用
加关 内容。

【 务要 】用 好 从用 的终端 、 诊方 、历
就诊医生 、就诊医院 、用 击关 分 用 的
特征,具 如下:
3.1.6 客 度

【需 说明】客 度 是用 用 程 的
现,主要从用 用 后的 馈 况以及用 的 风险进行
评 。

【 务要 】客 度 从用 历 是 有 诉 、主动
评价包 差评数据以及 子建 评 风险,具 如下:

3.2 接 封装
【需 说明】用 画像接 旨 解决用 画像数据与 务
应用的 题, 用 画像 应用时 化展现,
并且 证数据运营及营 推荐数据实时更新,数据 日更新, 免数
据不准确 重 叉应用。

【功 说明】Hive数据 库封装用 画像 宽表, 日同步至


MySQL数据库, 务及运营可 直接访 MySQL数据库 数据文件
下 的方 ,访 画像 数据宽表;也可 接 以RESTful
API的方 实时调用HBase、Elasticsearch 的用 、用
数据,实时 馈运营及营 接触数据 题,整 画像 并更新;
分 及应用平台可视化展现推荐 库,以实现权限 控需 。

3.3 UI设计

【需 说明】数字化运营及 准营 的可视化展现,是 用
画像数据实现千 千面的展现效 , 运营及营 有更好的用
认识,带来更 的用 服务质 。

【功 说明】展现UI 包 : 属 、行为属 、疾病


诊、订单消费、用 好以及客 度 ,同时 用
实现更 的用 分 计分 ,具 展现样 如下:

(1)画像数据展现
(2) 务 计

(3)用 分 力
(4)用 特征雷
(5) 况 表盘

(6)用 关 及搜 疾病 词云
3.4  景应用及项目排期

画像 上 后将应用 数据分 、BI分 、Push推送营 、站


内广 推送、差 化客服、主动 呼 、短 / 件营
应用 景。项目排期与 阶 关 出如下 示。
4.运行环

4.1  络与硬件设

络与硬件设 包 数据库服务 :Kafka、MySQL、HDFS、


Hive、HBase、Elasticsearch、Spark,应用服务 , 络环
。以 3 上的集 为 ,说明 机 的 用。机 及环
如下示 示。
4.2 软件平台

软件平台包 Web服务 环 、数据库操 、数据 掘软件工


具 。

You might also like