一 场景分析

用户行为分析应用的场景很多,像线上网站访问统计,线下客流分析(比如图像人脸识别、wifi探针等),比较核心的指标有几个:

PV | UV | SD | SC

指标说明:

PV(Page View):网站浏览量或者商场门店的访问量
UV(Unique Visitor):独立访客数,即去重后的人数
SD(Session Duration):单次会话停留时间
SC(Session Count):会话次数

用户行为分析的原始数据通常是一系列时间离散数据,比如网站访问记录:用户在一个时间点访问了一个网页,然后又在下个时间点访问了下个网页;

这些原始数据可以抽象为:

User | Timestamp | Target

即用户在什么时间点访问了什么目标;

统计PV、UV比较简单,但是在时间离散数据的基础上,要计算SD、SC这两个指标,常用的方式是设置过期时间阈值,如果用户两次访问的时间间隔超过阈值,则认为是两次Session;然后在一次Session的所有数据中取时间最早和最晚的数据来统计本次Session Duration;

二 统计示例

输入数据

(user1, 2018-12-01 01:00:00, t1)
(user1, 2018-12-01 01:01:30, t1)
(user1, 2018-12-01 01:06:00, t1)
(user1, 2018-12-01 01:20:00, t1)
(user1, 2018-12-01 01:24:00, t1)

可以统计出

PV=5,UV=1

过期时间阈值设置为5分钟,以上数据应该统计出来2次Session,分别是:

Session1: (2018-12-01 01:00:00 到 2018-12-01 01:06:00),Duration:6分钟
Session2: (2018-12-01 01:20:00 到 2018-12-01 01:24:00),Duration:4分钟

实际处理时还要数据乱序的问题,尤其是在实时计算中,你想好怎样做了吗?

容易想到的方式是先做group然后将所有的timestamp排序后一次遍历统计出SD和SC,不过这种方式占用内存比较大,性能略差,而且只能用在离线计算中。

三 代码实现

下面给出scala实现,来见证scala的强大:

scala核心代码(一步foldLeft)

scala

  val expireInSecond = 300
def mergeTimeArray(arr1 : ArrayBuffer[(Long, Long)], arr2 : ArrayBuffer[(Long, Long)]) : ArrayBuffer[(Long, Long)] = {
if (arr1.head._1.equals(0l)) arr2
else if (arr2.head._1.equals(0l)) arr1
else (arr1 ++ arr2).sortBy(_._1).foldLeft(ArrayBuffer[(Long, Long)]())((result, item) => if (!result.isEmpty && result.last._2 + expireInSecond >= item._1) {result.update(result.length - 1, (result.last._1, math.max(result.last._2, item._2))); result} else result += item)
}

spark核心代码(2步map 1步aggregateByKey)

scala

  /**
* @param data (user, timestamp, target)
* @return (user, target, session_count, session_duration)
*/
def process(data : RDD[(String, Long, String)]) : RDD[(String, String, Integer, Double)] = {
//((user, target), timestamp)
data.map(item => ((item._1, item._3), item._2))
//((user, target), Array[(startTime, endTime)])
.aggregateByKey(ArrayBuffer((0l, 0l)))((result : ArrayBuffer[(Long, Long)], timestamp: Long) => mergeTimeArray(result, ArrayBuffer((timestamp, timestamp))), (result1 : ArrayBuffer[(Long, Long)], result2 : ArrayBuffer[(Long, Long)]) => mergeTimeArray(result1, result2))
//(user, target, session_count, session_duration)
.map(item => (item._1._1, item._1._2, item._2.length, item._2.foldLeft(0l)((result, item) => result + (item._2 - item._1)).toDouble / item._2.length))
}

测试运行

  def main(args : Array[String]) : Unit = {
val conf = new SparkConf().setAppName("UserAnalysis").setMaster("local[2]")
val sc = new SparkContext(conf)
val arr = Array(("user1", 1546054000l, "t1"), ("user1", 1546054090l, "t1"), ("user1", 1546054360l, "t1"), ("user1", 1546055200l, "t1"), ("user1", 1546055440l, "t1"))
//(user, timestamp, target)
val data : RDD[(String, Long, String)] = sc.parallelize(arr)
this.process(data).foreach(println)
}

输出

(user1,t1,2,300.0)

【原创】大叔案例分享(3)用户行为分析--见证scala的强大的更多相关文章

  1. 【原创】大叔案例分享(4)定位分析--见证scala的强大

    一 场景分析 定位分析广泛应用,比如室外基站定位,室内蓝牙beacon定位,室内wifi探针定位等,实现方式是三点定位 Trilateration 理想情况 这种理想情况要求3个基站‘同时’采集‘准确 ...

  2. 【原创】大叔案例分享(5)id打通

    经常有一些需要做id打通的场景,比如用户id打通等, 问题抽象是每条数据都可以解析出一个或多个kv pair:(id_type,id),然后需要将某一个kv pair匹配的多条数据进行merge: 比 ...

  3. 老李案例分享:MAT分析应用程序服务出现内存溢出过程

    老李案例分享:MAT分析应用程序服务出现内存溢出过程   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.在poptest的loa ...

  4. Office 2010 KMS激活原理和案例分享

    Office 2010 KMS激活原理和案例分享     为了减低部署盗版(可能包含恶意软件.病毒和其他安全风险)的可能性,Office 2010面向企业客户推出了新的批量激活方式:KMS和MAK.这 ...

  5. Office 2010 KMS激活原理和案例分享 - Your Office Solution Here - Site Home - TechNet Blogs

    [作者:葛伟华.张玉工程师 ,  Office/Project支持团队, 微软亚太区全球技术支持中心 ] 为了减低部署盗版(可能包含恶意软件.病毒和其他安全风险)的可能性,Office 2010面向企 ...

  6. 性能调优案例分享:jvm crash的原因 1

    性能调优案例分享:jvm crash的原因   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq: ...

  7. mysql的"双1设置"-数据安全的关键参数(案例分享)

    mysql的"双1验证"指的是innodb_flush_log_at_trx_commit和sync_binlog两个参数设置,这两个是是控制MySQL 磁盘写入策略以及数据安全性 ...

  8. MySQL数据库详解之"双1设置"的数据安全的关键参数案例分享

    mysql的"双1验证"指的是innodb_flush_log_at_trx_commit和sync_binlog两个参数设置,这两个是是控制MySQL 磁盘写入策略以及数据安全性 ...

  9. 【案例分享】使用ActiveReports报表工具,在.NET MVC模式下动态创建报表

    提起报表,大家会觉得即熟悉又陌生,好像常常在工作中使用,又似乎无法准确描述报表.今天我们来一起了解一下什么是报表,报表的结构.构成元素,以及为什么需要报表. 什么是报表 简单的说:报表就是通过表格.图 ...

随机推荐

  1. aelf帮助C#工程师10分钟零门槛搭建DAPP&私有链开发环境

    aelf是一个可扩展的去中心化云计算区块链平台,支持高性能合约并行执行.原生多链数据交互.存储使用高性能分布式数据库. aelf整个系统可以在windows.osx及linux运行,团队在osx环境下 ...

  2. MySQL备份恢复-mysqldump原理

    +++++++++++++++++++++++++++++++++++++++++++标题:mysqldump对MySQL数据库备份恢复原理时间:2019年2月23日内容:mysqldump工具重点: ...

  3. 【转】Python爬虫:抓取新浪新闻数据

    案例一 抓取对象: 新浪国内新闻(http://news.sina.com.cn/china/),该列表中的标题名称.时间.链接. 完整代码: from bs4 import BeautifulSou ...

  4. svg(可缩放矢量图形)

    入门推荐: http://www.ruanyifeng.com/blog/2018/08/svg.html (教程) http://www.runoob.com/svg/svg-reference.h ...

  5. Linux operating system basic knowleadge

    1.Linux目录系统结构  It makes sense to explore the Linux filesystem from a terminal window. In fact, that ...

  6. MyBatis基础:MyBatis关联查询(4)

    1. MyBatis关联查询简介 MyBatis中级联分为3中:association.collection及discriminator. ◊ association:一对一关联 ◊ collecti ...

  7. Word Representations 词向量

    常用的词向量方法word2vec. 一.Word2vec 1.参考资料: 1.1) 总览 https://zhuanlan.zhihu.com/p/26306795 1.2) 基础篇:  深度学习wo ...

  8. 修改host,上github

    操作如下: 1.http://ping.chinaz.com/ 搜索github.com 海外ip,其实能找到的就两个;然后再搜gist.github.com 海外ip,也是两个. 192.30.25 ...

  9. OOM实例

    1. 使用Executors.newFixedThreadPool()方法,当不断创建新任务,而任务执行速度比创建速度慢时,任务对象就会在任务队列里面排队,堆内存得不到释放,导致OOM: 2. 使用P ...

  10. 【XSY2962】作业 数学

    题目描述 有一个递推式: \[ \begin{align} f_0&=1-\frac{1}{e}\\ f_n&=1-nf_{i-1} \end{align} \] 求 \(f_n\) ...