一、需求说明
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 的页面单跳转化率。
2)统计页面单跳转化率意义产品经理和运营总监,可以根据这个指标,去尝试分析,整个网站,产品,各个页面的表现怎么样,是不是需要去优化产品的布局;吸引用户最终可以进入最后的支付页面。数据分析师,可以此数据做更深一步的计算和分析。企业管理层,可以看到整个公司的网站,各个页面的之间的跳转的表现如何,可以适当调整公司的经营战略或策略。
二、需求分析
三、代码
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
object Spark06_Req3_PageflowAnalysis {
def main(args: Array[String]): Unit = {
//TODO:Top热门品类
val sparkConf =new SparkConf().setMaster("local[*]").setAppName("HotCategoryTop10Analysis")
val sc = new SparkContext(sparkConf)
//1.读取原始日志数据
val actionRDD =sc.textFile("datas/user_visit_action.txt")
val actionDataRDD = actionRDD.map(
action =>{
val datas = action.split("_")
UserVisitAction(
datas(0),
datas(1).toLong,
datas(2),
datas(3).toLong,
datas(4),
datas(5),
datas(6).toLong,
datas(7).toLong,
datas(8),
datas(9),
datas(10),
datas(11),
datas(12).toLong
)
}
)
actionDataRDD.cache()
//TODO 计算分母
val pageidToCountMap:Map[Long,Long] = actionDataRDD.map(
actionR => {
(actionR.page_id, 1L)
}
).reduceByKey(_ + _).collect().toMap
//TODO 计算分子
val sessionRDD = actionDataRDD.groupBy(_.session_id)
//分组后,根据访问时间进行排序(升序)
val mvRDD:RDD[(String,List[((Long,Long),Int)])] = sessionRDD.mapValues(
iter => {
val sortList = iter.toList.sortBy(_.action_time)
//[1,2,3,4]=>[1,2],[2,3],[3,4]=>[1-2,2-3,3-4]
//Sliding:滑窗
//或者zip:拉链
val flowIds:List[Long] = sortList.map(_.page_id)
val pageflowIds:List[(Long,Long)] = flowIds.zip(flowIds.tail)
pageflowIds.map(
t => {
(t,1)
}
)
}
)
//((1,2),1)
val flatRDD = mvRDD.map(_._2).flatMap(List=>List)
//((1,2),1) =>((1,2),sum)
val dataRDD = flatRDD.reduceByKey(_+_)
//TODO 计算单跳转化率
//分子除以分母
dataRDD.foreach{
case ((pageid1,pageid2),sum) =>{
val lon = pageidToCountMap.getOrElse(pageid1,0L)
println(s"页面${pageid1}跳转到页面${pageid2}单跳转化率为:"+(sum.toDouble/lon))
}
}
sc.stop()
}
case class UserVisitAction(
date: String,//用户点击行为的日期
user_id: Long,//用户的ID
session_id: String,//Session的ID
page_id: Long,//某个页面的ID
action_time: String,//动作的时间点
search_keyword: String,//用户搜索的关键词
click_category_id: Long,//某一个商品品类的ID
click_product_id: Long,//某一个商品的ID
order_category_ids: String,//一次订单中所有品类的ID集合
order_product_ids: String,//一次订单中所有商品的ID集合
pay_category_ids: String,//一次支付中所有品类的ID集合
pay_product_ids: String,//一次支付中所有商品的ID集合
city_id: Long)//城市id
}
四、运行结果
五、优化版
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
object Spark06_Req3_PageflowAnalysis_youhua {
def main(args: Array[String]): Unit = {
//TODO:Top热门品类
val sparkConf =new SparkConf().setMaster("local[*]").setAppName("HotCategoryTop10Analysis")
val sc = new SparkContext(sparkConf)
//1.读取原始日志数据
val actionRDD =sc.textFile("datas/user_visit_action.txt")
val actionDataRDD = actionRDD.map(
action =>{
val datas = action.split("_")
UserVisitAction(
datas(0),
datas(1).toLong,
datas(2),
datas(3).toLong,
datas(4),
datas(5),
datas(6).toLong,
datas(7).toLong,
datas(8),
datas(9),
datas(10),
datas(11),
datas(12).toLong
)
}
)
actionDataRDD.cache()
// TODO 对指定的页面连续跳转进行统计
//1-2,2-3,3-4,4-5,5-6,6-7
val ids=List[Long](1,2,3,4,5,6,7)
val okflowIds:List[(Long,Long)] = ids.zip(ids.tail)
//TODO 计算分母(过滤掉不需要的数据)
val pageidToCountMap:Map[Long,Long] = actionDataRDD.filter(
action => {
ids.init.contains(action.page_id)
}
).map(
actionR => {
(actionR.page_id, 1L)
}
).reduceByKey(_ + _).collect().toMap
//TODO 计算分子
val sessionRDD = actionDataRDD.groupBy(_.session_id)
//分组后,根据访问时间进行排序(升序)
val mvRDD:RDD[(String,List[((Long,Long),Int)])] = sessionRDD.mapValues(
iter => {
val sortList = iter.toList.sortBy(_.action_time)
//[1,2,3,4]=>[1,2],[2,3],[3,4]=>[1-2,2-3,3-4]
//Sliding:滑窗
//或者zip:拉链
val flowIds:List[Long] = sortList.map(_.page_id)
val pageflowIds:List[(Long,Long)] = flowIds.zip(flowIds.tail)
//将不合法的页面跳转进行过滤
pageflowIds.filter(
t => {
okflowIds.contains(t)
}
).map(
t => {
(t,1)
}
)
}
)
//((1,2),1)
val flatRDD = mvRDD.map(_._2).flatMap(List=>List)
//((1,2),1) =>((1,2),sum)
val dataRDD = flatRDD.reduceByKey(_+_)
//TODO 计算单跳转化率
//分子除以分母
dataRDD.foreach{
case ((pageid1,pageid2),sum) =>{
val lon = pageidToCountMap.getOrElse(pageid1,0L)
println(s"页面${pageid1}跳转到页面${pageid2}单跳转化率为:"+(sum.toDouble/lon))
}
}
sc.stop()
}
case class UserVisitAction(
date: String,//用户点击行为的日期
user_id: Long,//用户的ID
session_id: String,//Session的ID
page_id: Long,//某个页面的ID
action_time: String,//动作的时间点
search_keyword: String,//用户搜索的关键词
click_category_id: Long,//某一个商品品类的ID
click_product_id: Long,//某一个商品的ID
order_category_ids: String,//一次订单中所有品类的ID集合
order_product_ids: String,//一次订单中所有商品的ID集合
pay_category_ids: String,//一次支付中所有品类的ID集合
pay_product_ids: String,//一次支付中所有商品的ID集合
city_id: Long)//城市id
}
运行结果: