创业公司做数据分析(三)用户行为数据采集系统_weixin_33770878的博客-程序员宅基地

技术标签: ViewUI  ui  前端  后端  

作为系列文章的第三篇,本文将重点探讨数据采集层中的用户行为数据采集系统。这里的用户行为,指的是用户与产品UI的交互行为,主要表现在Android App、iOS App与Web页面上。这些交互行为,有的会与后端服务通信,有的仅仅引起前端UI的变化,但是不管是哪种行为,其背后总是伴随着一组属性数据。对于与后端发生交互的行为,我们可以从后端服务日志、业务数据库中拿到相关数据;而对于那些仅仅发生在前端的行为,则需要依靠前端主动上报给后端才能知晓。用户行为数据采集系统,便是负责从前端采集所需的完整的用户行为信息,用于数据分析和其他业务。

举个例子,下图所示是一次营销活动(简化版)的注册流程。如果仅仅依靠后端业务数据库,我们只能知道活动带来了多少新注册用户。而通过采集用户在前端的操作行为,则可以分析出整个活动的转化情况:海报页面浏览量—>>点击”立即注册”跳转注册页面量—>>点击“获取验证码”数量—>>提交注册信息数量—>>真实注册用户量。而前端用户行为数据的价值不仅限于这样的转化率分析,还可以挖掘出更多的有用信息,甚至可以与产品业务结合,比如笔者最近在做的用户评分系统,便会从用户行为中抽取一部分数据作为评分依据。

在早期的产品开发中,后端研发人员每人负责一个摊子,虽然也会做些数据采集的事情,但是基本上只针对自己的功能,各做各的。通常做法是,根据产品经理提出的数据需求,设计一个结构化的数据表来存储数据,然后开个REST API给前端,用来上报数据;前端负责在相应的位置埋点,按照协商好的数据格式上报给后端。随着业务的发展,这样的做法暴露了很多问题,给前后端都带来了混乱,主要表现在:前端四处埋点,上报时调用的API不统一,上报的数据格式不统一;后端数据分散在多个数据表中,与业务逻辑耦合严重。

于是,我们考虑做一个统一的用户行为数据采集系统,基本的原则是:统一上报方式、统一数据格式、数据集中存储、尽可能全量采集。具体到实现上,归纳起来主要要解决三个问题:

采什么。搞清楚需要什么数据,抽象出一个统一的数据格式。

前端怎么采。解决前端如何有效埋点、全量采集的问题。

后端怎么存。解决数据集中存储、易于分析的问题。

采什么

用户在前端UI上的操作,大多数表现为两类:第一类,打开某个页面,浏览其中的信息,然后点击感兴趣的内容进一步浏览;第二类,打开某个页面,根据UI的提示输入相关信息,然后点击提交。其行为可以归纳为三种:浏览、输入和点击(在移动端,有时也表现为滑动)。其中,浏览和点击是引起页面变化和逻辑处理的重要事件,输入总是与点击事件关联在一起。

因此,浏览和点击便是我们要采集的对象。对于浏览,我们关注的是浏览了哪个页面,以及与之相关的元数据;对于点击,我们关注的是点击了哪个页面的哪个元素,与该元素相关联的其他元素的信息,以及相关的元数据。页面,在Android与IOS上使用View名称来表示,在Web页面上使用URL(hostname+pathname)来表示。

元素,使用前端开发中的UI元素id来表示。与元素相关联的其他元素信息,指的是与“点击”相关联的输入/选择信息,比如在上面的注册页面中,与“提交”按钮相关联的信息有手机号、验证码、姓名。元数据,是指页面能提供的其他有用信息,比如URL中的参数、App中跳转页面时传递的参数等等,这些数据往往都是很重要的维度信息。

除了这些页面中的数据信息,还有两个重要的维度信息:用户和时间。用户维度,用来关联同一用户在某个客户端上的行为,采用的方案是由后端生成一个随机的UUID,前端拿到后自己缓存,如果是登录用户,可以通过元数据中的用户id来关联;时间维度,主要用于数据统计,考虑到前端可能延迟上报,前端上报时会加上事件的发生时间(目前大多数正常使用的移动端,时间信息应该是自动同步的)。

综合起来,将前端上报的数据格式定义如下。uuid、event_time、page是必填字段,element是点击事件的必填字段,attrs包含了上述的元数据、与元素相关联的其他元素的信息,是动态变化的。

而针对不同客户端的不同事件,通过不同的REST API来上报,每个客户端只需调用与自己相关的两个API即可。

前端怎么采

整理好数据格式和上报方式后,前端的重点工作便是如何埋点。传统的埋点方式,就是在需要上报的位置组织数据、调用API,将数据传给后端,比如百度统计、google analysis都是这样做的。这是最常用的方式,缺点是需要在代码里嵌入调用,与业务逻辑耦合在一起。近几年,一些新的数据公司提出了“无埋点”的概念,通过在底层hook所有的点击事件,将用户的操作尽量多的采集下来,因此也可以称为“全埋点”。这种方式无需嵌入调用,代码耦合性弱,但是会采集较多的无用数据,可控性差。经过一番调研,结合我们自己的业务,形成了这样几点设计思路:

hook底层的点击事件来做数据上报,在上报的地方统一做数据整理工作。

通过UI元素的属性值来设置是否对该元素的点击事件上报。

通过UI元素的属性值来设置元素的关联关系,用于获取上述的“与元素相关联的其他元素的信息”。

我们首先在Web的H5页面中做了实践,核心的代码很简单。第一,在页面加载时绑定所有的click事件,上报页面浏览事件数据。第二,通过user_action_id属性来表示一个元素是否需要上报点击事件,通过user_action_relation属性来声明当前元素被关联到哪个元素上面,具体代码实现不解释,很简单。

上述代码可以嵌入到任何HTML页面,然后只要在对应的元素中进行申明就好了。举个例子,

后端怎么存

数据进入后台后,首先接入Kafka队列中,采用生产消费者模式来处理。这样做的好处有:第一,功能分离,上报的API接口不关心数据处理功能,只负责接入数据;第二,数据缓冲,数据上报的速率是不可控的,取决于用户使用频率,采用该模式可以一定程度地缓冲数据;第三,易于扩展,在数据量大时,通过增加数据处理Worker来扩展,提高处理速率。

除了前端上报的数据内容外,我们还需要在后端加入一些其他的必要信息。在数据接入Kafka队列之前,需要加入五个维度信息:客户端类型(Web/Android/IOS)、事件类型(浏览/点击)、时间、客户端IP和User Agent。在消费者Worker从Kafka取出数据后,需要加入一个名为event_id的字段数据,具体含义等下解释。因此,最后存入的数据格式便如下所示:

再来看event_id的含义。前端传过来的一组组数据中,通过page和element可以区分出究竟是发生了什么事件,但是这些都是前端UI的名称,大部分是开发者才能看懂的语言,因此我们需要为感兴趣的事件添加一个通俗易懂的名称,比如上面的数据对应的事件名称为“在海报页面中注册”。将page+element、事件名称进行关联映射,然后将相应的数据记录id作为event id添加到上述的数据中,方便后期做数据分析时根据跟event id来做事件聚合。做这件事有两种方式:一种是允许相关人员通过页面进行配置,手动关联;一种是前端上报时带上事件名称,目前这两种方式我们都在使用。

最后,来看看数据存储的问题。传统的关系型数据库在存储数据时,采用的是行列二维结构来表示数据,每一行数据都具有相同的列字段,而这样的存储方式显示不适合上面的数据格式,因为我们无法预知attrs中有哪些字段数据。象用户行为数据、日志数据都属于半结构化数据,所谓半结构化数据,就是结构变化的结构化数据(WIKI中的定义),适合使用NoSQL来做数据存储。我们选用的是ElasticSearch来做数据存储,主要基于这么两点考虑:

Elasticsearch是一个实时的分布式搜索引擎和分析引擎,具有很强的数据搜索和聚合分析能力。

在这之前我们已经搭建了一个ELK日志系统,可以复用Elasticsearch集群做存储,也可以复用Kibana来做一些基础的数据分析可视化。

Elasticsearch的使用方法可以参考Elasticsearch使用总结一文,这里不做过多讲解。使用Elasticsearch来做数据存储,最重要的是两件事:建立Elasticsearch的映射模板、批量插入。Elasticsearch会根据插入的数据自动建立缺失的index和doc type,并对字段建立mapping,而我们要做的创建一个dynamic template,告诉Elasticsearch如何自动建立,参考如下。批量插入,可以通过Elasticsearch的bulk API轻松解决。


本文作者:Mr-Bruce

来源:51CTO

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_33770878/article/details/90394039

智能推荐

基于vue做一个禅道主页拖拽效果_weixin_33725515的博客-程序员宅基地

不bb先看效果源码地址bb两句最近在做一个基于vue的后台管理项目。平时项目进度统计就在上禅道上进行。so~ 然后领导就感觉这个拖拽效果还行,能不能加到咱们项目里面。 既然领导发话,那就开干。。所有技术:vue + vuedraggable拖动的实现基于 vuedraggable的插件开发。主页为两栏流式布局,每一个组件可以在上下拖动,也可以左右拖动。基本步骤布局这块布局为...

手册如何看运放的db_深入鉴别运放手册之噪声篇的内容分析_不教书的塞涅卡的博客-程序员宅基地

一个有趣的问题?2 个 1kΩ 电阻串联,与 1 个 2kΩ 电阻噪声一致吗?2 个 500Ω 电阻并联,与 1 个 2kΩ 电阻噪声一致吗?噪声的基本特性1) 它的波形在任意时刻都是不确定的,因此它是广谱的,有低频也有高频;2) 它的幅度又是有限制的,这与数学上的高斯分布近似但不完全一致;具有短时波形性以及长期稳定性。3) 它具有无限积分趋零性。怎么衡量噪声的大小?1) 有效值:有效值Urms是...

echarts.min.js_AS、SD的博客-程序员宅基地_echarts.min.js

/** Licensed to the Apache Software Foundation (ASF) under one* or more contributor license agreements. See the NOTICE file* distributed with this work for additional information* regarding copyright ownership. The ASF licenses this file* to you un.

2021-07-18_goodsapple1的博客-程序员宅基地

上锁的主要是两个步骤设备加密,这块主要是与android管理设备密码服务相关显示锁屏界面,即展开通知面板,同时加载密码界面的布局,但是会隐藏起来,等到向上划去锁屏界面才显示更新activity stack的状态,锁屏下的activity会被置为onstop执行上锁的流程是调用KeyguardViewMediator的doKeyguardLocked函数来完成的private void doKeyguardLocked(Bundle options) {if (!mExternallyEnable

easyui combobox 下拉列表添加选择项_爱放屁的王屁屁的博客-程序员宅基地_easyui动态如何给下拉列表添加选项

我们在使用easyui combobox 创建下拉列表时,需要通过ajax获取从服务端返回的json字符串,并显示在客户端。但除了显示数据库中存在的数据,往往需要为返回的结果增加一个选项,比如“全部”。 对于这个问题尝试多种方式后,总结出以下两种可用方法: 方法一:从后台添加。从数据库或者后台代码添加都是可行的,在此不做详细阐述。 方法二:通过对data属性的json对象调整实现(请勿

2021-02-27-数据库的基本使用和事务-3_爱健身的转行菜鸡自学程序员的博客-程序员宅基地

一、多表查询——概述1. 笛卡尔积的概念: *有两个集合A,B,取两个集合的所有组成情况  * 完成多表查询,需要消除无用的数据2. 多表查询的分类:1. 隐式内连接查询 #将所有可能的组合都查询的多表查询语句 SELECT * FROM emp ,dep; 查询结果如下:#使用隐式内连接查询语句SELECT * FROM emp,dep WHERE emp.`dep_id`=dep.`id`; 查询结果如下:   2). 显式内连接    语法:se

随便推点

链路追踪(Tracing)的前世今生(上)_腾讯云开发者的博客-程序员宅基地_网络链路 trac

带着疑问看历史提起链路追踪,大部分人都会想起 Zipkin、Jaeger、Skywalking 这些已经比较成熟的链路追踪开源软件以及 Opentelemetry、OpenTracing、OpenCensus 这些开源标准。虽然实现各有差异,但是使用各种软件、标准和实现组合搭建出来的不同的链路追踪系统,却有着许多相类似的地方。例如这些链路追踪系统都需要在调用链路上传播元数据。他们对元数据内容的定义也大同小异,链路唯一的 trace id, 关联父链路的 parent id,标识自身的 span id .

那些web前端经典面试题大全及答案_weixin_33743703的博客-程序员宅基地

阅读目录JavaScript部分JQurey部分HTML/CSS部分正则表达式开发及性能优化部分本篇收录了一些面试中经常会遇到的经典面试题以及自己面试过程中遇到的一些问题,并且都给出了我在网上收集的答案。马上就要过春节了,开年就是崭新的一年,相信很多的前端开发者会有一些跳槽的悸动,通过对本篇知识的整理以及经验的总结,希望能帮到更多的前端面试者。(如有错误或更好的答案,欢迎指正,水平有限,望各位不吝...

判断两个vector是否相等_weixin_30809333的博客-程序员宅基地

转载:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=26354188&id=3198604 1 #include <iostream> 2 #include <vector> 3 4 using namespace std; 5 6 int ma...

cs231n笔记-dropout正则化_AG9GgG的博客-程序员宅基地

L1、L2正则化L2正则化在神经网络中可能意义并不是很明确,有时候我们会在神经网络中选择其他方案。一个在神经网络中非常常用的方法:dropoutdropout每次在网络中正向传递时,我们在每一层随机将一部分神经元置0,每次正向传递时,随机被置0的神经元都不是完全相同的,每次处理网络中的一层。下图左侧为全连接神经网络,右边为dropout的版本。dropout之后的网络规模变小,我们只...

如何在五年内从一名码农成长为阿里架构师(文末附程序员涨薪必备)_JAVA葵花宝典的博客-程序员宅基地

在Java程序界流行着一种默认的说法叫“黄金5年”,也就是一个程序员从入职的时候算起,前五年的选择直接影响着整个职业生涯中的职业发展方向和薪资走向,如何走好这5年,彻底从...

推荐文章

热门文章

相关标签