[[IT知识]] 揭秘:如何精准统计连续登录三天及以上的用户?

[复制链接]
查看: 39|回复: 0
发表于 2025-2-7 09:35:00 | 显示全部楼层 | 阅读模式
易博V9下载

揭秘:如何精准统计连续登录三天及以上的用户?

[TOC] ### 一、需求 > 统计连续登录三天及以上的用户 + 这个问题可以扩展到很多相似的问题:连续几个月充值会员、连续天数有商品卖出、连续打滴滴、连续逾期。 示例 | uid | times | start_date | end_date | | ------ | ----- | ---------- | ---------- | | guid01 | 4 | 2018-03-04 | 2018-03-07 | | guid02 | 3 | 2018-03-01 | 2018-03-03 | ### 二、数据准备 + `v_user_login.csv`
  1. uid,datatime
  2. guid01,2018-02-28
  3. guid01,2018-03-01
  4. guid01,2018-03-02
  5. guid01,2018-03-04
  6. guid01,2018-03-05
  7. guid01,2018-03-06
  8. guid01,2018-03-07
  9. guid02,2018-03-01
  10. guid02,2018-03-02
  11. guid02,2018-03-03
  12. guid02,2018-03-06
复制代码
说明 + uid:登录用户ID + datatime:登录时间 ### 三、SQL实现 #### 3.1 步骤 1.查询用户登录详情,并且根据访问时间顺序对每个用户访问次数进行累计 2.查询出连续登录日期 - 思考:如何能够确定是否是连续时间登录 - 寻找规律:登录累积次数减登录时间,如果相同则代码是连续时间登录 3. 对uid和dif进行分组,统计数量 #### 3.2 代码
  1. import org.apache.spark.sql.{DataFrame, SparkSession}
  2. object UserContinueLoginSQL {
  3. def main(args: Array[String]): Unit = {
  4. val spark = SparkSession.builder().appName("UserContinueLoginSQL").master("local[*]").getOrCreate()
  5. import spark.implicits._
  6. val df: DataFrame = spark.read
  7. .option("header", "true")
  8. .option("inferSchema", "true")
  9. .csv("data_sql/v_user_login.csv")
  10. df.createOrReplaceTempView("v_access_log")
  11. //1.查询用户登录详情,并且根据访问时间顺序对每个用户访问次数进行累计
  12. //row_number()函数将针对SELECT语句返回的每一行,从1开始编号,赋予其连续的编号。
  13. spark.sql(
  14. """
  15. | select
  16. | uid,
  17. | datatime,
  18. | ROW_NUMBER() OVER(PARTITION BY uid ORDER BY datatime ASC) rn
  19. | from v_access_log
  20. """.stripMargin).createOrReplaceTempView("t1")
  21. //2.查询出连续登录日期
  22. //思考:如何能够确定是否是连续时间登录
  23. //寻找规律:登录累积次数减登录时间,如果相同则代码是连续时间登录
  24. //DATE_SUB():日期相减
  25. spark.sql(
  26. """
  27. | select
  28. | uid,
  29. | datatime,
  30. | DATE_SUB(datatime,rn) dif
  31. | from t1
  32. """.stripMargin).createOrReplaceTempView("t2")
  33. //3.对uid和dif进行分组,统计数量
  34. spark.sql(
  35. """
  36. | select
  37. | uid,
  38. | MIN(datatime) start_date,
  39. | MAX(datatime) end_date,
  40. | count(1) counts
  41. | from t2
  42. | group by uid,dif HAVING counts >= 3
  43. """.stripMargin).show()
  44. }
  45. }
复制代码
运行结果 +------+----------+----------+------+ | uid|start_date| end_date|counts| +------+----------+----------+------+ |guid02|2018-03-01|2018-03-03| 3| |guid01|2018-02-28|2018-03-02| 3| |guid01|2018-03-04|2018-03-07| 4| +------+----------+----------+------+ ### 四、RDD实现
  1. import java.text.SimpleDateFormat
  2. import java.util.{Calendar, Date}
  3. import org.apache.spark.rdd.RDD
  4. import org.apache.spark.{SparkConf, SparkContext}
  5. object UserContinueLoginRDD {
  6. def main(args: Array[String]): Unit = {
  7. val conf = new SparkConf().setAppName("UserContinueLoginRDD").setMaster("local[*]")
  8. val sc = new SparkContext(conf)
  9. //读取数据
  10. val rdd: RDD[String] = sc.textFile("data_sql/v_user_login.csv")
  11. //过滤掉第一行表头
  12. val header = rdd.first()
  13. val rdd1 = rdd.filter(row => row != header)
  14. //对数据进行处理
  15. val uidAndDate: RDD[(String, String)] = rdd1.map(x => {
  16. val fis = x.split(",")
  17. val uid = fis(0)
  18. val date = fis(1)
  19. (uid, date)
  20. })
  21. //根据uid进行分分组,将同一个用户的登录数据搞到同一个分组中
  22. val grouped: RDD[(String, Iterable[String])] = uidAndDate.groupByKey()
  23. //在组内进行排序
  24. val uidAndDateDif = grouped.flatMapValues(it => {
  25. //将迭代器中的数据toList/toSet,有可能会发生内存溢出
  26. val sorted = it.toSet.toList.sorted
  27. //定义一个日期的工具类
  28. val calendar = Calendar.getInstance()
  29. val sdf = new SimpleDateFormat("yyyy-MM-dd")
  30. var index = 0;
  31. sorted.map(desStr => {
  32. val date: Date = sdf.parse(desStr)
  33. calendar.setTime(date)
  34. calendar.add(Calendar.DATE, -index)
  35. index += 1
  36. (desStr, sdf.format(calendar.getTime))
  37. })
  38. })
  39. val result = uidAndDateDif.map(x => {
  40. ((x._1, x._2._2), x._2._1)
  41. }).groupByKey().mapValues(it=>{
  42. val list = it.toList
  43. val times = list.size
  44. val startTime = list.head
  45. val endTime = list.last
  46. (times,startTime,endTime)
  47. }).map(t=>{
  48. (t._1._1,t._2._1,t._2._2,t._2._3)
  49. }).filter(x=>{
  50. x._2>=3
  51. })
  52. val buffer = result.collect().toBuffer
  53. println(buffer)
  54. }
  55. }
复制代码
运行结果 ArrayBuffer((guid02,3,2018-03-01,2018-03-03), (guid01,4,2018-03-04,2018-03-07), (guid01,3,2018-02-28,2018-03-02))
易博软件介绍
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1、请认真发帖,禁止回复纯表情,纯数字等无意义的内容!帖子内容不要太简单!
2、提倡文明上网,净化网络环境!抵制低俗不良违法有害信息。
3、如果你对主帖作者的帖子不屑一顾的话,请勿回帖。谢谢合作!
3、问答求助区发帖求助后,如有其他用户热心帮您解决问题后,请自觉点击设为最佳答案按钮。

 
 
QQ在线客服
QQ技术支持
工作时间:
8:00-18:00
软著登字:
1361266号
官方微信扫一扫
weixin

QQ|小黑屋|Archiver|慈众营销 ( 粤ICP备15049986号 )|网站地图

自动发帖软件 | 自动发帖器 | 营销推广软件 | 网络营销工具 | 网络营销软件 | 网站推广工具 | 网络推广软件 | 网络推广工具 | 网页推广软件 | 信息发布软件 | 网站推广工具 | 网页推广软件

Powered by Discuz! X3.4   © 2012-2020 Comsenz Inc.  慈众科技 - Collect from 深圳吉宝泰佛文化有限公司 公司地址:罗湖区黄贝街道深南东路集浩大厦A1403

返回顶部 返回列表