hive实现用户连续登陆的最大天数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hive实现用户连续登陆的最大天数相关的知识,希望对你有一定的参考价值。

参考技术A 假设说我们现在有这样一张表

连续登陆,也就是在连续登陆的期间内,后一天和前一天的差值为1,不能为大于1的值,直到间断。那么在这里其实我们可以设置一列序号,如果是连续的话,这列序号也是会随着日期同步增长的,那么日期减去这个序号,应该都是一个确定的日期。比如说9月16号对应的序号是1,9月17号对应的序号是2,9月18号对应的序号是3,那么9月16号-1=9月15号,同理,9月17号-2=9月15号,都是同样的日期。那么我们根据这个日期和user_id和日期标示进行分组即可。

我们可以看到用ROW_NUMBER()函数已经成功加上了一列。

我们用log_date这一列减去row_number这一列得到一个时间标志

在这里做的事情是把之前的rn从string的格式改为了int的格式,这样才能够传入到date_sub函数里面做减法。这里要注意,做subquery的时候要制定子表格的名字,比如我在这里就指定了子表格名字为c。

接下来我们要根据user_id和log_date进行分组然后统计。

现在我们已经得到了每个日期的分组的数目统计,这里的天数实际上是开始连续的那个日期-1(因为不连续的都不是同一个标志日,不会分到一组)但是还有两个问题,一个是要求出每个id的最大值,另外就是要将天数加1回到一开始连续开始的日期。

以上解决了找到最大值,但是最大值的日期没有返回。
由于嵌套写得太多了,接下来还是新建一张表格,用连接的方式找出最大日期

如果原始数据表有连续的日期,应该考虑用dense_number(),同样的操作后,用select distinct的方法来选出user_id, date以及symbol_date都不一样的一行。
关于这个问题可以参考链接:

获取连续登陆天数,连续签到天数 ,方法优化

          获取连续登陆天数,连续签到天数,类似这样的需求应该是一个常见的需求,那么我们有没有一套成熟的解决方案呢 ?下面我来跟大家分享一下我的故事。

在猴年马月的一天,有个用户反馈个人中心打开缓慢,需要7、8秒,做为一个认真负责任的程序员GG,我尼玛放下手中的其他工作,跟踪调查并且解决该问题。

第一步重现问题:

  连着登陆了好几个账号到个人中心,打开都不慢呀 ,那是什么问题呢,就你一个人出问题,是你人品差吧,正当打算以此敷衍用户的时候,测试组的小陶说,他也遇到了这个问题,纳尼 !!你个人品差的家伙 ,让俺来看看,你要重现不了,看我不打死你。 于是他登陆账号试了一下,果然是有些缓慢,大概在4、5秒的样子,嗯,至此,这个问题重现成功了 。嗯,厉害 。

第二步查找问题根本原因:

   总不是这两个人人品都差吧,经过一番严密的调查,问题最终锁定在获取连续签到次数上,别问我怎么查到的,因为这两个奇葩居然做到连续签到近100天的牛逼战绩,然后获取连续签到的存储过程采用的循环算法是连续登陆天数越多,算法复杂度就越高。下面贴存储过程代码:

 1  --循环法

declare @day int = 1, -- 2 @userId int =1, --用户id 3 @count int = 0 , --连续签到多少天 4 @isSinginToday int --今天是否签到 5 6 while exists ( select * from #SignInLog 7 where UserId = @UserId and DATEDIFF(day ,createtime ,getdate() ) = @day ) 8 begin 9 set @count = @count + 1 -- 【循环方法】 10 set @day = @day + 1 -- 11 end 12 13 select @isSinginToday =COUNT(*) from #SignInLog where UserId = @UserId and DATEDIFF(day ,createtime ,getdate() ) = 0 --今天是否登录 14 15 16 select @isSinginToday , --当天是否签到 17 @count + @isSinginToday -- 连续签到n天

把表结构也贴出来吧 ,省得你们这些懒人造数据麻烦,检验代码麻烦

 

--用户签到日志表
create table #SignInLog (   UserId  int,  --用户id
CreateTime  datetime )--签到时间
insert into #SignInLog  values
(1,20160924 ),
(1,20160923 ),
(1,20160922 ),
(1,20160921 ),
(1,20160919 ),
(2,20160924 ),
(2,20160923 ),
(2,20160920 )

 

 

可以看到这个存储过程采用循环的方法,去检查前一天是否签到,有的话继续查前一天,并把用于统计连续签到天数的计数器加一 ,前一天没有签到的话作为退出循环的条件,真是段思路清晰的好代码。但是随着连续次数的增多,select语句的执行次数也会增多,所以才会出现了那些连续签到天数多的人缓慢,连续签到天数少的人正常的情况 。 嗯....... 原因也找到了。喝杯茶压压惊先。

 

最后一步了,也是最难的,解决问题:

     这代码也没毛病,不换个思路的话,问题应该也得不到解决。正当我绞尽脑汁的时候,我有点想上厕所了,正当我上厕所的时候,灵感来了,(为了有意让灵感发生在洗手间,容易吗我)一个sql的函数映入我的眼帘,rownumber()  。于是最后给这个方法取的名字就叫rownumber法。看代码:

 

--【row_number 法 】
declare @now datetime  = getdate() ,    
@count int ,
@userid int = 1 ,
@isSinginToday int 
select @count  = count(*) from (
    select  datediff( day  , CreateTime  , @now )         aa ,  --签到时间对比今天的差值
        row_number() over (order by createtime  desc )    bb    --排序字段 
    from  #SignInLog
    where UserId  = @userId   and  datediff( day , CreateTime , @now )  > 0  --条件排除今天的签到记录 
) T where aa = bb  



select @isSinginToday =COUNT(*)  from  #SignInLog    where UserId  = @UserId  and DATEDIFF(day ,createtime ,getdate() ) = 0  --今天是否登录
    
select  @isSinginToday , --当天是否签到
@count + @isSinginToday  -- 连续签到n天

 

 

  这代码思路也算清晰的, 同学们,不知道你们看完这个故事,学到了没。

 

以上是关于hive实现用户连续登陆的最大天数的主要内容,如果未能解决你的问题,请参考以下文章

hive之连续登录问题

hive sql之:最大登录天数,获取连续登录指定天数

面试题: Hive-SQL查询连续活跃登录用户思路详解

面试题: Hive-SQL查询连续活跃登录用户思路详解

面试题: Hive-SQL查询连续活跃登录用户思路详解

spark sql 连续登录最大天数