第 6 章 需求3: 页面单跳转化率统计
6.1 需求简介
计算页面单跳转化率,什么是页面单跳转换率,比如一个用户在一次 Session 过程中访问的页面路径 3,5,7,9,10,21
,那么页面 3
跳到页面 5
叫一次单跳,7-9
也叫一次单跳,那么单跳转化率就是要统计页面点击的概率
比如:计算 3-5
的单跳转化率,先获取符合条件的 Session
对于页面 3 的访问次数(PV)为 A,然后获取符合条件的 Session 中访问了页面 3 又紧接着访问了页面 5 的次数为 B,那么 B/A 就是 3-5 的页面单跳转化率.
产品经理和运营总监,可以根据这个指标,去尝试分析,整个网站,产品,各个页面的表现怎么样,是不是需要去优化产品的布局;吸引用户最终可以进入最后的支付页面。
数据分析师,可以此数据做更深一步的计算和分析。
企业管理层,可以看到整个公司的网站,各个页面的之间的跳转的表现如何,可以适当调整公司的经营战略或策略。
在该模块中,需要根据查询对象中设置的 Session 过滤条件,先将对应得 Session 过滤出来,然后根据查询对象中设置的页面路径,计算页面单跳转化率,比如查询的页面路径为:3、5、7、8,那么就要计算 3-5、5-7、7-8 的页面单跳转化率。 需要注意的一点是,页面的访问时有先后的,要做好排序。
6.2 思路分析
读取到规定的页面
过滤出来规定页面的日志记录, 并统计出来每个页面的访问次数
countByKey
是行动算子reduceByKey
是转换算子明确哪些页面需要计算跳转次数
1-2
,2-3
,3-4
...按照 session 统计所有页面的跳转次数, 并且需要按照时间升序来排序
- 按照 session 分组, 然后并对每组内的
UserVisitAction
进行排序 - 转换访问流水
- 过滤出来和统计目标一致的跳转
- 按照 session 分组, 然后并对每组内的
统计跳转次数
计算跳转率
存储到 mysql 数据库
6.3 具体业务实现
1. 建表
-- ----------------------------
-- create table page_conversion_rate
-- ----------------------------
CREATE TABLE `page_conversion_rate` (
`taskId` TEXT,
`page_page` TEXT,
`conversion_rate` TEXT
) ENGINE=INNODB DEFAULT CHARSET=utf8
2. 入口
println("任务3: 开始... 规定页面跳转率")
PageConversionApp.calcPageConversion(spark, userVisitActionRDD, readConditions.targetPageFlow, taskId)
println("任务3: 结束")
3. 具体业务代码
package com.atguigu.sparkmall.offline.app
import java.text.DecimalFormat
import com.atguigu.sparkmall.common.bean.UserVisitAction
import com.atguigu.sparkmall.common.util.JDBCUtil
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.SparkSession
/**
* 需求3: 页面转化率
*/
object PageConversionApp {
/**
* 计算页面跳转转化率
*
* @param spark
* @param userVisitActionRDD
* @param conditions 要统计的页面
* @param taskId
*/
def calcPageConversion(spark: SparkSession, userVisitActionRDD: RDD[UserVisitAction], targetPageFlow: String, taskId: String) = {
// 1. 读取到规定的页面
val pageFlowArr = targetPageFlow.split(",")
val prePageFlowArr = pageFlowArr.slice(0, pageFlowArr.length - 1)
val postPageFlowArr = pageFlowArr.slice(1, pageFlowArr.length)
// 2. 过滤出来规定页面的日志记录, 并统计出来每个页面的访问次数 countByKey 是行动算子 reduceByKey 是转换算子
val targetPageCount = userVisitActionRDD
.filter(uva => pageFlowArr.contains(uva.page_id.toString))
.map(uva => (uva.page_id, 1L))
.countByKey
// 3. 明确哪些页面需要计算跳转次数 1-2 2-3 3-4 ...
val targetJumpPages = prePageFlowArr.zip(postPageFlowArr).map(t => t._1 + "-" + t._2)
// 4. 按照 session 统计所有页面的跳转次数, 并且需要按照时间升序来排序
// 4.1 按照 session 分组, 然后并对每组内的 UserVisitAction 进行排序
val pageJumpRDD = userVisitActionRDD.groupBy(_.session_id).flatMap {
case (sid, actions) => {
val visitActions = actions.toList.sortBy(_.action_time)
// 4.2 转换访问流水
val pre = visitActions.slice(0, visitActions.length - 1)
val post = visitActions.slice(1, visitActions.length)
// 4.3 过滤出来和统计目标一致的跳转
pre.zip(post).map(t => t._1.page_id + "-" + t._2.page_id).filter(targetJumpPages.contains(_))
}
}
// 5. 统计跳转次数 数据量已经很少了, 拉到驱动端计算
val pageJumpCount = pageJumpRDD.map((_, 1)).reduceByKey(_ + _).collect
// 6. 计算跳转率
val formatter = new DecimalFormat(".00%")
// 转换成百分比
val conversionRate: Array[(String, String)] = pageJumpCount.map {
case (p2p, jumpCount) =>
val visitCount: Long = targetPageCount.getOrElse(p2p.split("-").head.toLong, 0L)
val rate: String = formatter.format(jumpCount.toDouble / visitCount)
(p2p, rate)
}
// 7. 存储到数据库
val result: Array[Array[String]] = conversionRate.map {
case (p2p, conversionRate) => Array(taskId, p2p, conversionRate)
}
JDBCUtil.executeUpdate("truncate page_conversion_rate", null)
JDBCUtil.executeBatchUpdate("insert into page_conversion_rate values(?, ?, ?)", result)
}
}
/*
1. 读取到规定的页面
例如: targetPageFlow:"1,2,3,4,5,6,7"
2. 过滤出来规定页面的日志记录 并统计出来每个页面的访问次数
例如: 只需过滤出来1,2,3,4,5,6 第7页面不需要过滤
3. 计算页面跳转次数(肯定是按照每个 session 来统计)
1->2 2->3 ...
3.1 统计每个页面访问次数
4. 计算转化率
页面跳转次数 / 页面访问次数
1->2/1 表示页面1到页面2的转化率
5. 保存到数据库
*/