电商数据采集是数据体系建设的最上游,是非常重要的一个环节,除了专业的数据人员,人们普遍对数据采集的认知度不高。如果你提起埋点,应该很多人都熟悉它。它应该也是绝大部分人对数据采集的认知了。数据上报其实是一个系统性工程,它涉及了工具、团队、团队协同、标准、流程等多方面的内容,其中任何一个部分出现问题都有可能让上报过程变得复杂,下游数据出现问题的概率增高。本文系统的讲解了数据采集的核心原理是什么,以及工具、组织改如何建设,希望能让你对数据采集有一个清晰的认知和了解。
探究采集的整个过程
我最早接触的数据采集是从业务的数据库中COPY各种表到数据仓库中,就是从一个库中的一些表以各种形式拷贝到另一个库中再以各种形式存储下来的过程。这是一个后端交互的采集方式。后来逐步了解到,原来还可以去采集用户的行为,名词叫埋点。采集用户的行为主要目的是为了以数据的视角观察用户是怎么在你的产品里“活动”的,为了帮助设计者了解设计的缺陷,优化交互设计,提高产品的体验。数据采集中埋点的概念绝大多人都有听说,但基本上是停留在听说阶段,知道要埋点,反正埋点了就能有数据,然后就可以分析了。这么理解没问题,对于使用者本身,就足够了。直到真正开始做数据采集这个工作时,慢慢了解到数据采集是个比较复杂的事情,它涉及众多角色,涉及繁长的流程,和建设指标一样,是个既简单而又复杂的的工程。
从行为到指标,数据是怎么来的
用户行为动作的抽象过程
应用程序的出现是为了满足用户的各种需要,例如网上购物、看视频、玩游戏、社交等场景,所有的场景活动都会有用户在应用上的各种行为操作。下图是京东移动端的首页,京东的核心场景是购物,用户在应用上浏览商品,挑选,购买。用户在京东上的所有的操作行为都可以归类为“动作”。
用户和应用程序的交互,不像现实生活中的“动作”那么丰富,例如走路、开门、跑、跳,这些实际的物理动作在应用程序范围内是不会发生的。人在应用程序的动作会受限于使用载体本身(手机、电脑、电视..)的人机交互,如早期的手机用按键,控制电视需要用遥控器,ps\xbox等游戏机用手柄等。人机交互动作更多是像登录、浏览、点击等动作,用户在应用程序的操作,就是这些实际的物理操作,不会囊括太多现实中的其他物理动作。例如“扔手机”这个动作,没有和手机发生实际的交互,只是在现实中进行了物理的动作,该动作就不会让手机本身“知道’并记录下来。
从动作到日志
既然动作被限定在人机交互这个范围内,记录用户行为就有规律可循。识别用户的动作,并把它记录下来是数据采集的核心目标。现在以京东商城购物为例,看看从动作发生到数据记录的过程是什么。
下图是京东【京东商品API接口】商城手机端的首页,我们现在准备记录我的两个2个动作:
-
我浏览了该页面
-
我点击了家电家具的按钮
我的两个动作是浏览和点击,但动作的实际发生是要作用于具体的实体对象的,也就是“我对谁做了什么”:我点击了哪个实体,我浏览了哪个实体。
通常来说,用户在应用上的动作(谁对什么做了哪些动作),统一归纳理解为”事件“,可以理解为,发生了一件什么事。
事件的基本要素可以用这四点来描述:一个用户在某个时间点、某个地方,对谁做了什么什么动作。
总结归纳一个事件需要包括的四个要素:谁、什么时间、对谁、做了什么动作:
定义了”事件“,应用程序就需要在动作实际发生时,把这个事件以数据形式记录下来。在技术上,通常以记录日志的形式表现出来。也就是说,当我”点击“了京东家电家居的按钮时,应用会把我这个动作存储成一条数据:
$user_id:用户:勍爷(谁)
$event_time:时间:5:30:30(在什么时间)
$event_postion:”位置:jd_home_detail(对谁,页面)
$event_content内容:eid_jd_home_app(对谁,按钮元素)
$event_action:动作:click(做了点击动作)
日志一般用JOSN的格式来表示:
{ "user_id": "勍爷”,
"event_time": "5:30:30”,
"event_postion": "jd_home_detail”,
"event_content": “eid_jd_home_app”,
"event_action": "click”,
}
如果我继续在京东首页上分别点击“京东电器”、”京东到家“、”京东超市“三个按钮,则会产生三条日志记录:
京东电器:
{ "user_id": "勍爷”,
"event_time": "5:30:31”,
"event_postion": "jd_home_detail”,
"event_content": "eid_jd_app” ,
"event_action": "click", }
京东到家:
{ "user_id": "勍爷”,
"event_time": "5:30:32”,
"event_postion": "jd_home_detail”,
"event_content": “eid_jd_tohome”,
"event_action": "click", }
京东超市:
{ "user_id": "勍爷”,
"event_time": "5:30:33”,
"event_postion": "jd_home_detail”,
"event_content": “eid_jd_market”,
"event_action": "click", }
上面三条记录中变化的只有envet_content(对谁做),同一个动作(点击),记录了4条不同的记录。
更多的描述-参数的引入
事件的基本要素描述了事件的主体,他们构成了一个完整的事件。但是仅仅只记录事件的基本四要素信息,如上面日志记录里的内容,是不够我们用于业务分析的。例如用户勍爷,是注册用户,他用的什么设备登录,IP地址是什么,在什么地理位置,用的什么网络?点击的按钮,跳转地址是什么?再如,首页中的搜索框,”搜索“事件,用户输入了什么关键词,搜索类型,是否触发联想词,输入词为空的搜索,分析需求多种多样,需要记录的数据内容就会变的更多。
要想记录更多的数据,可以对事件的四要素进行扩展。如下图:
我们可以增加对该事件基本要素更多的属性描述,例如对用户进行描述扩展,对动作、实体对象进行更丰富的描述,这些描述统一为扩展参数。
扩展参数的记录,应该根据实际的需求来进行合理的设计。从指标和维度的实际使用情况来倒推所需要的参数是什么。例如,根据上面的例子,如果想了解在北京用IOS端点击”首页家电家居“按钮的用户数是多少,我们需要在事件中加入参数:
$event_ip:IP地址
$event_client:客户端
然后再加入一些用户的属性,性别、年龄、身高、体重4个参数,则日志会变成这样:
{ "user_id": "勍爷”,
”gender”:”男”,
”height”:”184”,
”weight”:”165”,
”age”:”18”,
event_ip“:”114.206.233.55”,
”event_client”:”IOS”,
"event_time": "5:30:31”,
"event_postion": "jd_home_detail”,
"event_content": “eid_jd_app”,
"event_action": "click”,
}
对于参数,可以基于事件的四要素做归纳:
【用户类】【页面元素类】【动作类】,每个类别都可以做扩展
公有参数、私有参数、日志长度
公有参数
随着加入参数的增多,日志也需要一定的统一性。例如想用户的基本属性,设备号、用户名、注册时间、会员属性、性别、年龄等,对于任何事件来说,都是需要包含对应的用户参数的。几乎绝大多数统计,都需要用户的基本属性。如今天有多少会员登录,有多少新用户,有多少年龄18岁的女性用户等等。它具有普遍性,几乎每条日志都会带有这些参数。这类参数视会被视为公共参数,他是在一定范围内,不论你定义什么事件、不论你分析什么,都会进行采集的。
私有参数
私有参数的范围更小,依赖业务自身的特定需求。例如直播这个业务辅助电商进行销售,那直播会有自己的私有业务属性,例如弹幕、打赏等动作,从事件本身就单独独立于电商整个体系,它有自己的私有业务规则,所以在直播这个领域内,它会有自己特定的参数。这时候,采集的日志表现,只会在直播这个业务范围内,才会存在这些参数。
日志长度
如果从日志的视角来看,把每一条日志都格式化后,每一个参数对一定一个字段,它们的长度是不一样的。我们假设有两个事件:
【直播进房事件】、【商品详情播放事件】来看一看他们的格式化后的长度:
两个事件所产生的日志长度是不同的,因为采集的参数(字段)不相同。这两条日志结构中,都有三个类型,其中关于用户属性的参数,是完全一致的,我们认定它们是公共参数。房间、SKU、主播ID、商品视频这些具有独特的业务含义,并不会再其他领域内出现,故描述它们的属性就属于私有参数。
用一张图来描述Event模型:
日志的格式设计:定常、扩展与嵌套
因为日志长度不同,在使用以及后续的处理上就会带来不便,想想看,你的EXCEL中有1万条不同长度的数据是个多么恐怖的事情。但是最重要的是,对于传输和解析(把日志结构化)就变的异常困难了。每条日志都不一样长,每个日志都具有独特的私有参数,批量解析需要规则,对某一字段是保留还是解析成结构化需要设定一个统一个规则。从成本的角度来讲,如果每一条日志都需要合理的解析成结构化的数据,那么消耗的计算资源也会大很多。从传输、解析、理解、扩展和后期维护的角度来看,日志的格式需要有特定的规则,而不是杂乱无章的。
所以,根据上述的内容,日志的格式设计需要满足以下几点:
1)日志的字段长度要一样,便于维护
2)为了满足需求的灵活性,日志需要有扩展性
3)扩展性字段需要统一定义,方便下游用户解析
4)运用嵌套满足扩展性
所以日志保持定长、并有共识的几个字段,通过嵌套来满足业务的灵活多变添加更多的参数。定长设计多少个字段、不是拍脑袋决定的,需要根据业务长期以来的分析需求通过抽象来判断的。例如设备号、IP地址、通信波段等最常用的,然后留有一定的扩展位,扩展位留几个,取决于设计者的技术方案与成本、运维、解析便利性以及容错性来综合判断。
如上图,假设统一定长的日志是10个字段,其中7个字段是最常用,这7个字段是全局公参,是所有需求都需要的字段。剩下留有3个扩展位,每个扩展字段下的内容还可以再扩展,留有足够的扩展空间,在这些扩展位中,可以写入业务的私有参数,也有可能是局部的业务、用户的公有参数,但它不是全局性的(公司级)如何扩展、把哪类扩展内容固定在具体的扩展字段上,需要与多方达成协定,便于后续的解析工作。后续解析成结构化,由使用方自行决定。
格式的设计没有对错之说,核心目标是要保障稳定利于传输、具有扩展性、可读性好、容错率高、传播协定便于解析的特性,至于是20个定长字段,还是10个,外层有一个扩展字段还是多个,需根据公司的实际发展需要来决定。
一个完整行为的记录
看一个实际的例子,如上图,我的行为路径分成了6步:
1)启动京东商城应用
2)进入首页,再点击家电家居按钮
3)进入家电家居页面,再点击家电馆按钮
4)进入家电馆页面,点击美的空调广告页
5)进入美的空调详情页
6)点击商品视频,播放视频
用户的动作可以分成这几步,我们对动作进行同类合并,这几步中,一共有4类动作:登录、浏览、点击、播放。
然后是实体位置,一共有多少的页面和按钮参与了这些动作,最后用表格来描述:
页面 | 按钮(元素) | 动作 |
京东APP | 无 | 登录 |
商城首页 | 无 | 浏览 |
商城首页 | 家电家居 | 浏览 |
商城首页 | 家电家居 | 点击 |
家电家居页 | 无 | 浏览 |
家电家居页 | 家电馆 | 浏览 |
家电家居页 | 家电馆 | 点击 |
家电馆页 | 无 | 浏览 |
家电馆页 | 广告banner | 浏览 |
家电馆页 | 广告banner | 点击 |
商品详情页 | 无 | 浏览 |
商品详情页 | 商品视频 | 浏览 |
商品详情页 | 商品视频 | 点击 |
商品详情页 | 商品视频 | 播放 |
京东app | 无 | 退出 |
浏览的动作理解起来比较特殊,页面暴露在手机上,就等同于这个页面让用户看到了,所以一般都把浏览动作定义为曝光动作。曝光是一个用户被动触发的动作,它是高频出现的,只要页面或者页面上的各种内容出现在(在手机上暴露)用户面前,都会触发曝光动作,如果用户只是上下浏览滑动,没有点击具体按钮,那么用户的动作就只有曝光。
通过表格的统计,一共包括了4个页面,4个按钮,4个动作,其中每一行都可以理解为一个独立的事件,每个事件在触发后,都会生成一条日志,这一套动作下来,一共产生了14条日志。此时如果我退出了应用,系统在记录一条我退出的动作,我这个自然人在应用上留痕的记录就是15条。假设该应用有1万个用户都做了上面的动作,则将会产生15万条日志记录。这些日志都会以定长的方式发送到接收服务器中,最后加工成表。
千万的用户会产生千万的行为轨迹,我们把应用的页面、元素与动作组合成一个个事件,每个用户的轨迹就上述的表格一样一条一条被记录下来。