Spark电商用户行为分析(2)——用户访问 session 分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012292754/article/details/87800324

1 用户访问 session 分析模块介绍

  1. 可以根据使用者指定的某些条件,筛选出指定的一些用户(有特定年龄、职业、城市);
  2. 对这些用户在指定日期范围内发起的session,进行聚合统计,比如,统计出访问时长在0~3s的session占总session数量的比例;
  3. 按时间比例,比如一天有24个小时,其中12:00~13:00的session数量占当天总session数量的50%,当天总session数量是10000个,那么当天总共要抽取1000个session,ok,12:00~13:00的用户,就得抽取100050%=500。而且这500个需要随机抽取。当天总session数量是10000个,那么当天总共要抽取1000个session,ok,12:00~13:00的用户,就得抽取100050%=500。而且这500个需要随机抽取。
  4. 获取点击量、下单量和支付量都排名10的商品种类
  5. 获取top10的商品种类的点击数量排名前10的session
  6. 开发完毕了以上功能之后,需要进行大量、复杂、高端、全套的性能调优;
  7. 十亿级数据量的troubleshooting(故障解决)的经验总结
  8. 数据倾斜的完美解决方案
  9. 使用mock(模拟)的数据,对模块进行调试、运行和演示效果

1.1 session 介绍

  • 用户在电商网站上,通常会有很多的点击行为,首页通常都是进入首页;然后可能点击首页上的一些商品;点击首页上的一些品类;也可能随时在搜索框里面搜索关键词;还可能将一些商品加入购物车;对购物车中的多个商品下订单;最后对订单中的多个商品进行支付。
  • 用户的每一次操作,其实可以理解为一个action,比如点击、搜索、下单、支付。
  • 用户session,指的就是,从用户第一次进入首页,session就开始了。然后在一定时间范围内,直到最后操作完(可能做了几十次、甚至上百次操作)。离开网站,关闭浏览器,或者长时间没有做操作;那么session就结束了。以上用户在网站内的访问过程,就称之为一次session。
  • 简单理解,session就是某一天某一个时间段内,某个用户对网站从打开/进入,到做了大量操作,到最后关闭浏览器的过程。session实际上就是一个电商网站中最基本的数据和大数据。那么大数据,面向C端,也就是customer,消费者,用户端的,分析,基本是最基本的就是面向用户访问行为/用户访问session。

2 基础数据结构表示

做任何大数据系统/平台类的项目,首先第一步,就是要做数据调研。也就是分析平台要基于的底层的基础数据。分析表结构,弄清楚表之间的关系。表中的数据的更新粒度,一个小时更新一次,还是一天更新一次。会不会有脏数据。每天什么时候数据能够进来。

2.1 user_visit_action(hive 表)

  • date:日期,代表这个用户点击行为是在哪一天发生的
  • user_id:代表这个点击行为是哪一个用户执行的
  • session_id :唯一标识了某个用户的一个访问session
  • page_id :点击了某些商品/品类,也可能是搜索了某个关键词,然后进入了某个页面,页面的id
  • action_time :这个点击行为发生的时间点
  • search_keyword :如果用户执行的是一个搜索行为,比如说在网站/app中,搜索了某个关键词,然后会跳转到商品列表页面;搜索的关键词
  • click_category_id :可能是在网站首页,点击了某个品类(美食、电子设备、电脑)
  • click_product_id :可能是在网站首页,或者是在商品列表页,点击了某个商品(比如呷哺呷哺火锅XX路店3人套餐、iphone 6s)
  • order_category_ids :代表了可能将某些商品加入了购物车,然后一次性对购物车中的商品下了一个订单,这就代表了某次下单的行为中,有哪些
    商品品类,可能有6个商品,但是就对应了2个品类,比如有3根火腿肠(食品品类),3个电池(日用品品类)
  • order_product_ids :某次下单,具体对哪些商品下的订单
  • pay_category_ids :代表的是,对某个订单,或者某几个订单,进行了一次支付的行为,对应了哪些品类
  • pay_product_ids:代表的,支付行为下,对应的哪些具体的商品

2.2 user_info (hive 表)

  • user_id:其实就是每一个用户的唯一标识,通常是自增长的Long类型,BigInt类型
  • username:是每个用户的登录名
  • name:每个用户自己的昵称、或者是真实姓名
  • age:用户的年龄
  • professional:用户的职业
  • city:用户所在的城市

2.3 task(mysql 表)

  • task_id:表的主键
  • task_name:任务名称
  • create_time:创建时间
  • start_time:开始运行的时间
  • finish_time:结束运行的时间
  • task_type:任务类型,就是说,在一套大数据平台中,肯定会有各种不同类型的统计分析任务,比如说用户访问session分析任务,页面单跳转化率统计任务;所以这个字段就标识了每个任务的类型
  • task_status:任务状态,任务对应的就是一次Spark作业的运行,这里就标识了,Spark作业是新建,还没运行,还是正在运行,还是已经运行完毕
  • task_param:最最重要,用来使用JSON的格式,来封装用户提交的任务对应的特殊的筛选参数

task表,其实是用来保存平台的使用者,通过J2EE系统,提交的基于特定筛选参数的分析任务的信息,
就会通过J2EE系统保存到task表中来。之所以使用MySQL表,是因为J2EE系统是要实现快速的实时插入和查询的。

3 需求分析

  1. 按条件筛选session
  2. 统计出符合条件的session中,访问时长在1s~3s、4s~6s、7s~9s、10s~30s、30s~60s、1m~3m、3m~10m、10m~30m、30m以上各个范围内的session占比;访问步长在1~3、4~6、7~9、10~30、30~60、60以上各个范围内的session占比
  3. 在符合条件的session中,按照时间比例随机抽取1000个session
  4. 在符合条件的session中,获取点击、下单和支付数量排名前10的品类
  5. 对于排名前10的品类,分别获取其点击次数排名前10的session

3.1 按条件筛选session

  • 搜索过某些关键词的用户、访问时间在某个时间段内的用户、年龄在某个范围内的用户、职业在某个范围内的用户、所在某个城市的用户,发起的session。找到对应的这些用户的session,也就是我们所说的第一步,按条件筛选session。这个功能,就最大的作用就是灵活。也就是说,可以让使用者,对感兴趣的和关系的用户群体,进行后续各种复杂业务逻辑的统计和分析,那么拿到的结果数据,就是只是针对特殊用户群体的分析结果;而不是对所有用户进行分析的泛泛的分析结果。比如说,现在某个企业高层,就是想看到用户群体中,28~35岁的,老师职业的群体,对应的一些统计和分析的结果数据,从而辅助高管进行公司战略上的决策制定。

3.2 统计出符合条件的session中,访问时长不同区间范围的比例

  • session访问时长,也就是说一个session对应的开始的action,到结束的action,之间的时间范围;还有,就是访问步长,指的是,一个session执行期间内,依次点击过多少个页面,比如说,一次session,维持了1分钟,那么访问时长就是1m,然后在这1分钟内,点击了10个页面,那么session的访问步长,就是10.比如说,符合第一步筛选出来的session的数量大概是有1000万个。那么里面,我们要计算出,访问时长在1s~3s内的session的数量,并除以符合条件的总session数量(比如1000万),比如是100万/1000万,那么1s~3s内的session占比就是10%。依次类推,这里说的统计,就是这个意思。
  • 这个功能的作用,其实就是,可以让人从全局的角度看到,符合某些条件的用户群体,使用我们的产品的一些习惯。比如大多数人,到底是会在产品中停留多长时间,大多数人,会在一次使用产品的过程中,访问多少个页面。那么对于使用者来说,有一个全局和清晰的认识。

3.3 在符合条件的session中,按照时间比例随机抽取1000个session

  • 随机抽取本身是很简单的,但是按照时间比例,就很复杂了。比如说,这一天总共有1000万的session。那么我现在总共要从这1000万session中,随机抽取出来1000个session。但是这个随机不是那么简单的。需要做到如下几点要求:首先,如果这一天的12:00~13:00的session数量是100万,那么这个小时的session占比就是1/10,那么这个小时中的100万的session,我们就要抽取1/10 * 1000 = 100个。然后再从这个小时的100万session中,随机抽取出100个session。以此类推,其他小时的抽取也是这样做。
  • 这个功能的作用,是说,可以让使用者,能够对于符合条件的session,按照时间比例均匀的随机采样出1000个session,然后观察每个session具体的点击流/行为,比如先进入了首页、然后点击了食品品类、然后点击了雨润火腿肠商品、然后搜索了火腿肠罐头的关键词、接着对王中王火腿肠下了订单、最后对订单做了支付。之所以要做到按时间比例随机采用抽取,就是要做到,观察样本的公平性。

3.4 在符合条件的session中,获取点击、下单和支付数量排名前10的品类

  • 什么意思呢,对于这些session,每个session可能都会对一些品类的商品进行点击、下单和支付等等行为。那么现在就需要获取这些session点击、下单和支付数量排名前10的最热门的品类。也就是说,要计算出所有这些session对各个品类的点击、下单和支付的次数,然后按照这三个属性进行排序,获取前10个品类。
  • 这个功能,很重要,就可以让我们明白,就是符合条件的用户,他最感兴趣的商品是什么种类。这个可以让公司里的人,清晰地了解到不同层次、不同类型的用户的心理和喜好。

3.5 对于排名前10的品类,分别获取其点击次数排名前10的session

  • 这个就是说,对于top10的品类,每一个都要获取对它点击次数排名前10的session。这个功能,可以让我们看到,对某个用户群体最感兴趣的品类,各个品类最感兴趣最典型的用户的session的行为。

4 技术方案的设计

  • 这是正规企业级大数据项目开发流程的第三个步骤。就是说,在调研完了基础数据、分析完了需求之后,就需要针对我们手头上有的基础数据和PM提出来的需求,来进行技术方案的设计。所谓技术方案,指的就是,基于现有的数据,针对提出的需求,实现所有需求的整个技术架构、关键的技术点等。在这个过程中,需要考虑到实现所有需求,需要使用以及可能涉及到的技术点。另外,在这个过程中,有时也会涉及到技术的选项。比如,如果说,我们的Spark程序在中间,需要对某个RDD的数据写入外部的缓存,以便于后续的算子可以直接通过缓存读取数据。那么就需要对缓存进行技术选项,redis,memcached、spark tachyon。
  • 实现需求需要使用的以及涉及到的技术点,和技术实现思路,是我们这里的重点。也就是说,实现上述几个需求,你的技术实现的思路,以及在思路中,可能使用到的技术的要点。

4.1 按条件筛选session

  • 这里首先提出第一个问题,你要按条件筛选session,但是这个筛选的粒度是不同的,
    比如说搜索词、访问时间,那么这个都是session粒度的,甚至是action粒度的;那么还有,就是针对用户的基础信息进行筛选,年龄、性别、职业;所以说筛选粒度是不统一的。

  • 第二个问题,就是说,我们的每天的用户访问数据量是很大的,因为user_visit_action这个表,一行就代表了用户的一个行为,比如点击或者搜索;那么在国内一个大的电商企业里面,如果每天的活跃用户数量在千万级别的话。那么这个user_visit_action表,每天的数据量大概在至少5亿以上,在10亿左右。

  • 那么针对这个筛选粒度不统一的问题,以及数据量巨大(10亿/day),可能会有两个问题;首先第一个,就是,如果不统一筛选粒度的话,那么就必须得对所有的数据进行全量的扫描;第二个,就是全量扫描的话,量实在太大了,一天如果在10亿左右,那么10天呢(100亿),100呢,1000亿。量太大的话,会导致Spark作业的运行速度大幅度降低。
    极大的影响平台使用者的用户体验。

  • 所以为了解决这个问题,那么我们选择在这里,对原始的数据,进行聚合,什么粒度的聚合呢?session粒度的聚合。也就是说,用一些最基本的筛选条件,比如时间范围,从hive表中提取数据,然后呢,按照session_id这个字段进行聚合,那么聚合后的一条记录,就是一个用户的某个session在指定时间内的访问的记录,比如搜索过的所有的关键词、点击过的所有的品类id、session对应的userid关联的用户的基础信息。

  • 聚合过后,针对session粒度的数据,按照使用者指定的筛选条件,进行数据的筛选。
    筛选出来符合条件的用session粒度的数据。其实就是我们想要的那些session了。

4.2 聚合统计

  • 如果要做这个事情,那么首先要明确,我们的spark作业是分布式的。所以也就是说,每个spark task在执行我们的统计逻辑的时候,可能就需要对一个全局的变量,进行累加操作。比如代表访问时长在1s~3s的session数量,初始是0,然后呢分布式处理所有的session,判断每个session的访问时长,如果是1s~3s内的话,那么就给1s~3s内的session计数器,累加1。那么在spark中,要实现分布式安全的累加操作,基本上只有一个最好的选择,就是Accumulator变量。但是,问题又来了,如果是基础的Accumulator变量,那么可能需要将近20个Accumulator变量,1s~3s、4s~6s。但是这样的话,就会导致代码中充斥了大量的Accumulator变量,导致维护变得更加复杂,在修改代码的时候,很可能会导致错误。比如说判断出一个session访问时长在4s~6s,但是代码中不小心写了一个bug(由于Accumulator太多了),比如说,更新了1s~3s的范围的Accumulator变量。导致统计出错。
  • 所以,对于这个情况,那么我们就可以使用自定义Accumulator的技术,来实现复杂的分布式计算。也就是说,就用一个Accumulator,来计算所有的指标。

4.3 在符合条件的session中,按照时间比例随机抽取1000个session

  • 这个呢,需求上已经明确了。那么剩下的就是具体的实现了。具体的实现这里不多说,技术上来说,就是要综合运用Spark的countByKey、groupByKey、mapToPair等算子,来开发一个复杂的按时间比例随机均匀采样抽取的算法。(大数据算法)

4.4 在符合条件的session中,获取点击、下单和支付数量排名前10的品类

  • 这里的话呢,需要对每个品类的点击、下单和支付的数量都进行计算。然后呢,使用Spark的自定义Key二次排序算法的技术,来实现所有品类,按照三个字段,点击数量、下单数量、支付数量依次进行排序,首先比较点击数量,如果相同的话,那么比较下单数量,如果还是相同,那么比较支付数量。

4.5 对于排名前10的品类,分别获取其点击次数排名前10的session

  • 使用Spark的分组取TopN的算法来进行

4.6 总结——可以掌握的技术点

  1. 通过底层数据聚合,来减少spark作业处理数据量,从而提升spark作业的性能(从根本上提升spark性能的技巧)
  2. 自定义Accumulator实现复杂分布式计算的技术
  3. Spark按时间比例随机抽取算法
  4. Spark自定义key二次排序技术
  5. Spark分组取TopN算法
  6. 通过Spark的各种功能和技术点,进行各种聚合、采样、排序、取TopN业务的实现

5 数据表设计

  • 第一个呢,就是说,我们的上游数据,就是数据调研环节看到的项目基于的基础数据,是否要针对其开发一些Hive ETL,对数据进行进一步的处理和转换,从而让我们能够更加方便的和快速的去计算和执行spark作业;
  • 第二个,就是要设计spark作业要保存结果数据的业务表的结构,从而让J2EE平台可以使用业务表中的数据,来为使用者展示任务执行结果。

5. 1 session_aggr_stat表,存储第一个功能,session聚合统计的结果

CREATE TABLE `session_aggr_stat` (
  `task_id` int(11) NOT NULL,
  `session_count` int(11) DEFAULT NULL,
  `1s_3s` double DEFAULT NULL,
  `4s_6s` double DEFAULT NULL,
  `7s_9s` double DEFAULT NULL,
  `10s_30s` double DEFAULT NULL,
  `30s_60s` double DEFAULT NULL,
  `1m_3m` double DEFAULT NULL,
  `3m_10m` double DEFAULT NULL,
  `10m_30m` double DEFAULT NULL,
  `30m` double DEFAULT NULL,
  `1_3` double DEFAULT NULL,
  `4_6` double DEFAULT NULL,
  `7_9` double DEFAULT NULL,
  `10_30` double DEFAULT NULL,
  `30_60` double DEFAULT NULL,
  `60` double DEFAULT NULL,
  PRIMARY KEY (`task_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

5.2 session_random_extract表,存储我们的按时间比例随机抽取功能抽取出来的1000个session

CREATE TABLE `session_random_extract` (
  `task_id` int(11) NOT NULL,
  `session_id` varchar(255) DEFAULT NULL,
  `start_time` varchar(50) DEFAULT NULL,
  `end_time` varchar(50) DEFAULT NULL,
  `search_keywords` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`task_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

5.3 top10_category表,存储按点击、下单和支付排序出来的top10品类数据

CREATE TABLE `top10_category` (
  `task_id` int(11) NOT NULL,
  `category_id` int(11) DEFAULT NULL,
  `click_count` int(11) DEFAULT NULL,
  `order_count` int(11) DEFAULT NULL,
  `pay_count` int(11) DEFAULT NULL,
  PRIMARY KEY (`task_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

5.4 top10_category_session表,存储top10每个品类的点击top10的session

CREATE TABLE `top10_category_session` (
  `task_id` int(11) NOT NULL,
  `category_id` int(11) DEFAULT NULL,
  `session_id` varchar(255) DEFAULT NULL,
  `click_count` int(11) DEFAULT NULL,
  PRIMARY KEY (`task_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

5.5 session_detail,用来存储随机抽取出来的session的明细数据、top10品类的session的明细数据

CREATE TABLE `session_detail` (
  `task_id` int(11) NOT NULL,
  `user_id` int(11) DEFAULT NULL,
  `session_id` varchar(255) DEFAULT NULL,
  `page_id` int(11) DEFAULT NULL,
  `action_time` varchar(255) DEFAULT NULL,
  `search_keyword` varchar(255) DEFAULT NULL,
  `click_category_id` int(11) DEFAULT NULL,
  `click_product_id` int(11) DEFAULT NULL,
  `order_category_ids` varchar(255) DEFAULT NULL,
  `order_product_ids` varchar(255) DEFAULT NULL,
  `pay_category_ids` varchar(255) DEFAULT NULL,
  `pay_product_ids` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`task_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

5.6 task表,用来存储J2EE平台插入其中的任务的信息

CREATE TABLE `task` (
  `task_id` int(11) NOT NULL AUTO_INCREMENT,
  `task_name` varchar(255) DEFAULT NULL,
  `create_time` varchar(255) DEFAULT NULL,
  `start_time` varchar(255) DEFAULT NULL,
  `finish_time` varchar(255) DEFAULT NULL,
  `task_type` varchar(255) DEFAULT NULL,
  `task_status` varchar(255) DEFAULT NULL,
  `task_param` text,
  PRIMARY KEY (`task_id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8

6 最后总结

  • 在数据设计以后,就正式进入一个漫长的环节,就是编码实现阶段,coding阶段。
    在编码实现阶段,每开发完一个功能,其实都会走后续的两个环节,就是本地测试和生产环境测试。需要在windows上面,自己安装MySQL数据库。然后本地测试的时候,将数据插入本地的MySQL中。接下来,就是在完成了数据调研、需求分析、技术方案设计、数据设计以后,正式进入编码实现和功能测试阶段。最后才是性能调优阶段。

猜你喜欢

转载自blog.csdn.net/u012292754/article/details/87800324
今日推荐