基于 Spark 的用户行为路径分析的产品化实践

AbeAntle 7年前
   <p><strong>1)什么是用户行为路径</strong></p>    <p>用户行为路径分析是互联网行业特有的一类数据分析方法,它主要根据每位用户在App或网站中的点击行为日志,分析用户在App或网站中各个模块的流转规律与特点,挖掘用户的访问或点击模式,进而实现一些特定的业务用途,如App核心模块的到达率提升、特定用户群体的主流路径提取与浏览特征刻画,App产品设计的优化与改版等。</p>    <p><strong>2)路径分析业务场景</strong></p>    <p>用户行为路径分析的一个重要终极目的便是优化与提升关键模块的转化率,使得用户可以便捷地依照产品设计期望的主流路径直达核心模块。具体在分析过程中还存在着以下的应用场景:</p>    <p><strong>i.用户典型路径识别与用户特征分析</strong></p>    <p>用户特征分析中常常使用的都是一些如性别、地域等人口统计数据或订单价、订单数等运营数据,用户访问路径数据为我们了解用户特征打开了另一扇大门。例如对于一款图片制作上传分享的应用,我们可以通过用户的App使用操作数据,来划分出乐于制作上传的创作型用户,乐于点赞评论的互动型用户,默默浏览看图的潜水型用户,以及从不上传只会下载图片的消费型用户。</p>    <p><strong>ii.产品设计的优化与改进</strong></p>    <p>路径分析对产品设计的优化与改进有着很大的帮助,可以用于监测与优化期望用户路径中各模块的转化率,也可以发现某些冷僻的功能点。一款视频创作分享型App应用中,从开始拍摄制作视频到视频的最终发布过程中,用户往往会进行一系列的剪辑操作;通过路径分析,我们可以清晰的看到哪些是用户熟知并喜爱的编辑工具,哪些操作过于冗长繁琐,这样可以帮助我们针对性地改进剪辑操作模块,优化用户体验。如果在路径分析过程中用户的创作数量与用户被点赞、评论以及分享的行为密切相关,就可以考虑增强这款App的社交性,增强用户黏性与创作欲望。</p>    <p><strong>iii.产品运营过程的监控</strong></p>    <p>产品关键模块的转化率本身即是一项很重要的产品运营指标,通过路径分析来监测与验证相应的运营活动结果,可以方便相关人员认识了解运营活动效果。</p>    <p>说到这里不得不提及一下漏斗模型与路径分析的关系</p>    <p>以上提到的路径分析与我们较为熟知的漏斗模型有相似之处,广义上说,漏斗模型可以看作是路径分析中的一种特殊情况,是针对少数人为特定模块与事件节点的路径分析。换句话说是一种高度的抽象逻辑。</p>    <p>漏斗模型通常是对用户在网站或App中一系列关键节点的转化率的描述,这些关键节点往往是我们人为指定的。例如我们可以看到某购物App应用的购买行为的漏斗转化情况。这款购物App平台上,买家从浏览到支付成功经历了4个关键节点,商品浏览、加入购物车、结算、付款成功,从步骤1到步骤4,经历了其关键节点的人群越来越少,节点的转化率呈现出一个漏斗状的情形,我们可以针对各个环节的转化效率、运营效果及过程进行监控和管理,对于转化率较低的环节进行针对性的深入分析与改进。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/ff52911808a1149f10306155bbd9fd1d.png"></p>    <p>路径分析与漏斗模型存在不同之处,它通常是对每一个用户的每一个行为路径进行跟踪与记录,在此基础上分析挖掘用户路径行为特点,涉及到每一步的来源与去向、每一步的转化率。可以说,漏斗模型是事先的、人为的、主动的设定了若干个关键事件节点路径,而路径分析是探索性的去挖掘整体的行为路径,找出用户的主流路径,甚至可能发现某些事先不为人知的有趣的模式路径。从技术手段上来看,漏斗模型简单直观计算并展示出相关的转化率,路径分析会涉及到一些更为广泛的层面。</p>    <p>这块有一个对大部分产品问题初步判定实践,首先我们会通过用户行为路径大概的了解一下用户是否依照产品设计期望的主流路径直达核心模块。 然后结合具体的业务场景建立漏斗细看转化。最后通过用户细查详细的查看具体用户的行为。实际在具体实践中反复结合这三步,我们可以得到许多有价值的信息。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/e8dc3d67fbeae478c7c6fd4b97e949ef.jpg"></p>    <p><strong>3)诸葛用户行为自动化报告实践</strong></p>    <p><strong>Sunburst Partition可视化分析探索</strong></p>    <p>通过解析布点获得的用户行为路径数据,我们可以用最简单与直接的方式将每个用户的事件路径点击流数据进行统计,并用数据可视化方法将其直观地呈现出来。 D3.js是当前最流行的数据可视化库之一,我们可以利用其中的Sunburst Partition来刻画用户群体的事件路径点击状况。从该图的圆心出发,层层向外推进,代表了用户从开始使用产品到离开的整个行为统计;Sunburst事件路径图可以快速定位用户的主流使用路径。通过提取特定人群或特定模块之间的路径数据,并使用Sunburst事件路径图进行分析,可以定位到更深层次的问题。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/8b9bd591af5366d781d4f894bfdd1486.jpg"></p>    <p><strong>4)用户行为路径算法</strong></p>    <p>较常用的用户行为路径算法有基于关联分析的序列路径挖掘方法和社会网络分析</p>    <p><strong>i.基于关联分析的序列路径挖掘方法</strong></p>    <p>提到关联规则分析,必然免不了数据挖掘中的经典案例“啤酒与尿布”。暂且不论“啤酒与尿布”是不是Teradata的一位经理胡编乱造吹嘘出来的“神话故事”,这个案例在一定程度上让人们理解与懂得了购物篮分析(关联分析)的流程以及背后所带来的业务价值。</p>    <p>将超市的每个客户一次购买的所有商品看成一个购物篮,运用关联规则算法分析这些存储在数据库中的购买行为数据,即购物篮分析,发现10%的顾客同事购买了尿布与啤酒,且在所有购买了尿布的顾客中,70%的人同时购买了啤酒。于是超市决定将啤酒与尿布摆放在一起,结果明显提升了销售额。</p>    <p>我们在此不妨将每个用户每次使用App时操作所有事件点看成“购物篮”中的“一系列商品”,与上面提到的购物篮不同的是,这里的所有事件点击行为都是存在严格的前后事件顺序的。我们可以通过改进关联规则中的Apriori或FP-Growth算法,使其可以挖掘存在严格先后顺序的频繁用户行为路径,不失为一种重要的用户路径分析思路。我们可以仔细考量发掘出来的规则序列路径所体现的产品业务逻辑,也可以比较分析不同用户群体之间的规则序列路径。</p>    <p><strong>ii.社会网络分析(或链接分析)</strong></p>    <p>早期的搜索引擎主要基于检索网页内容与用户查询的相似性或者通过查找搜索引擎中被索引过的页面为用户查找相关的网页,随着90年代中后期互联网网页数量 的爆炸式增长,早期的策略不再有效,无法对大量的相似网页给出合理的排序搜索结果。</p>    <p>现今的搜索引擎巨头如Google、百度都采用了基于链接分析的搜索引擎算法来作为这个问题的解决方法之一。网页与网页之间通过超链接结合在一起,如同微博上的社交网络通过关注行为连接起来,社交网络中有影响力很大的知名权威大V们,互联网上也存在着重要性或权威性很高的网页。将权威性较高的网页提供到搜索引擎结果的前面,使得搜索的效果更佳。</p>    <p>我们将社交网络中的人看作一个个节点,将互联网中的网页看作一个个节点,甚至可以将我们的App产品中的每一个模块事件看作一个个节点,节点与节点之间通过各自的方式连接组成了一个特定的网络图,以下将基于这些网络结构的分析方法统称为社会网络分析。</p>    <p>社会网络分析中存在一些较为常见的分析方法可以运用到我们的路径分析中来,如节点的中心性分析,节点的影响力建模,社区发现等。通过中心性分析,我们可以去探索哪些模块事件处于中心地位,或者作为枢纽连接了两大类模块事件,或者成为大多数模块事件的最终到达目的地。通过社区发现,我们可以去探索这个社会网络中是否存在一些“小圈子”,即用户总是喜欢去操作的一小部分行为路径,而该部分路径又与其他大部分模块相对独立。</p>    <p><strong>5)用户行为路径产品化实践</strong></p>    <p>下面是一个大致的用户行为路径产品需求导图</p>    <p><img src="https://simg.open-open.com/show/b0e80c68534611f95c452d22836a0399.jpg"></p>    <p>我们大体目标要完成基于人数和次数的用户行为路径,可以支持从任意事件起下查后续行为或者上查来源行为,并且要支持任意30天时间行为路径的查看。最重要的一点是强调用户体验需要较实时处理获得结果。根据上述这些需求,我们给出基于Spark的用户行为路径实践。</p>    <p><strong>6)基于Spark的用户行为路径</strong></p>    <p>Spark是一个基于内存计算的开源集群计算系统,目的是更快速的进行数据分析</p>    <p>下面是一个Spark的套件图</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/9284fa94ebbd8196adfbfa45056099f0.png"></p>    <p>伯克利将Spark的整个生态系统称为伯克利数据分析栈(BDAS)。其核心框架是Spark,同时BDAS涵盖支持结构化数据SQL查询与分析的查询引擎Spark SQL,提供机器学习功能的系统MLbase及底层的分布式机器学习库MLlib、并行图计算框架GraphX,流计算框架Spark Streaming。这些子项目在Spark上层提供了更高层、更丰富的计算范式。</p>    <p>下面简单介绍一下 <strong>Spark的 Yarn-Cluster任务提交流程</strong></p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/65bbf80e26ab07dd404a630b4ba60bc7.jpg"></p>    <p>1. Spark Yarn Client向YARN中提交应用程序,包括ApplicationMaster程序、启动ApplicationMaster的命令、需要在Executor中运行的程序等;</p>    <p>2. ResourceManager收到请求后,在集群中选择一个NodeManager,为该应用程序分配第一个Container,要求它在这个Container中启动应用程序的ApplicationMaster,其中ApplicationMaster进行SparkContext等的初始化;</p>    <p>3.ApplicationMaster向ResourceManager注册,这样用户可以直接通过ResourceManage查看应用程序的运行状态,然后它将采用轮询的方式通过RPC协议为各个任务申请资源,并监控它们的运行状态直到运行结束;</p>    <p>4.一旦ApplicationMaster申请到资源(也就是Container)后,便与对应的NodeManager,要求它在获得的Container中启动启动CoarseGrainedExecutorBackend,CoarseGrainedExecutorBackend启动后会向ApplicationMaster中的SparkContext注册并申请Task。这一点和Standalone模式一样,只不过SparkContext在Spark Application中初始化时,使用CoarseGrainedSchedulerBackend配合YarnClusterScheduler进行任务的调度,其中YarnClusterScheduler只是对TaskSchedulerImpl的一个简单包装,增加了对Executor的等待逻辑等;</p>    <p>5.ApplicationMaster中的SparkContext分配Task给CoarseGrainedExecutorBackend执行,CoarseGrainedExecutorBackend运行Task并向ApplicationMaster汇报运行的状态和进度,以让ApplicationMaster随时掌握各个任务的运行状态,从而可以在任务失败时重新启动任务;</p>    <p>6.应用程序运行完成后,ApplicationMaster向ResourceManager申请注销并关闭自己。</p>    <p>下面给出我们整体行为路径的数据流向以及请求过程</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/fa8a09ec892f701e57c8e4050dd1e246.png"></p>    <p><strong>数据收集:</strong></p>    <p>互联网行业对数据的获取有着得天独厚的优势,路径分析所依赖的数据主要就是服务器中的日志数据。用户在使用App过程中的每一步都可以被记录下来,这时候需要关注的便是优秀的布点策略,它应当与我们所关心的业务息息相关。事实上,在每个App里,不是所有事件都有着同样的价值,基于对核心事件的深度分析需求,推荐大家使用层级化的自定义事件布点方式,每一个事件由三个层次组成的:事件(Event)、属性(Key)和属性值(Value)。</p>    <p><strong>数据清洗:</strong></p>    <p>在ETL阶段我们会把收集到的Android/IOS/JS SDK数据进行统一的处理,从上述的JSON格式里面取出预定义好的字段(我们需要的一些信息)写入本地文件中。</p>    <p><strong>数据获取:</strong></p>    <p>将写好的本地文件通过定时加载程序加载到Inforbright里面,得到一系列的基础表。然后从这些基础表里通过跑批程序跑出方便查询和使用的一些汇总表。</p>    <p>为了减少Spark实时内存计算压力我们将用户行为路径核心算法过程分为离线部分和线上请求部分。如下:</p>    <p><strong>中间结果计算:</strong></p>    <p>回溯之前第五节说到产品需求,要完成这些需要(人数,次数,后续行为,来源行为,30天时间内任意查询),我们需要从数据库里获取事件ID,会话ID,事件触发时间,设备ID,用户ID这些信息。如图所示:</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/e61d97325b6f8e8dc2f9d245358388cd.png"></p>    <p><strong>下面重点来了,首先我们会将上述信息做一些处理。</strong></p>    <p>原则就是将一个会话ID下面的同一个用户ID的所有事件按照事件发生的顺序进行排序。这块为了进一步减少之后Spark内存使用我们会将所有超长ID进行一次map。 例如下图中最后一列的1表示的就是map过后的会话ID。第三列表示的是用户ID第五列和第六列表示的是这个会话ID内事件对发生的顺序。第一列和第二列表示的是具体的事件对。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/efe00a5165b1fa61b24c1f4a540cc4bc.png"></p>    <p><strong>具体解读一下图中的信息:</strong></p>    <p>用户ID为16351的用户在其map过后ID为1的会话中的事件</p>    <p>正序顺序 8532810 -> 7232351 -> 7232351 -> 8532810 -> 8532810 -> 7232351 -> 8532810 -> 8532810 -> 565 -> 8532810 -> 6907797 -> 565</p>    <p>逆序顺序 565 -> 6907797 -> 8532810 -> 565 -> 8532810 -> 8532810 -> 7232351 -> 8532810 -> 8532810 -> 7232351 -> 7232351 -> 8532810</p>    <p>你会发现按照上述的过程,我们将获取到的原始数据进行离线转化后,新的数据就会天然的支持我们的产品需求:人数,次数,后续行为,来源行为。对于30天内任意时间查询,我们也做了特殊的处理。我们会将每天的数据存放在一个文件里面,这样就会有30个用天数命名的文件,这样每天的离线计算只需要进行增量的部分。这种做法会大大节省我们离线部分计算的开销。</p>    <p><strong>数据计算:</strong></p>    <p>由于在离线部分准备的充分,故在Spark实时计算阶段我们只需要将数据Load到内存后通过一系列的Spark RDD算子查出我们需要的结果即可。当然按照离线计算后数据格式的特点结合我们的具体产品需求,在Spark处理过程中也是有不少小技巧可循,例如查询某个条件的用户行为路径可以只使用filter算子就可以得到结果,今天就不多赘述了。</p>    <p><strong>数据请求:</strong></p>    <p>前端的请求会通过Redis的订阅和发布机制告诉Spark提交相应的任务到集群。</p>    <p>下面是诸葛用户行为路径的demo数据</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/67f967bf180392717e3388a70fe66c13.jpg"></p>    <p> </p>    <p> </p>    <p>来自:http://mp.weixin.qq.com/s/nNlxXDFTKwWHfeGXK3K5nw</p>    <p> </p>