【HiveSql面试题】统计在线高峰期人数及出现高峰期的时间线

一、需求

id      start_time              end_time

1001	2021-12-01 08:08:05	    2021-12-01 19:02:07
1002	2021-12-01 08:15:07	    2021-12-01 19:05:10
1003	2021-12-01 09:10:20	    2021-12-01 21:02:07
1005	2021-12-01 09:26:05	    2021-12-01 19:52:15
1006	2021-12-01 10:08:05	    2021-12-01 22:05:06
1004	2021-12-01 10:20:07	    2021-12-01 18:03:05
1001	2021-12-01 20:08:05	    2021-12-01 23:02:07

        数据id为主播ID,start_time表示上播时间,end_time表示下播时间
        数据为某平台主播上下播时间表,统计出该平台主播同时在线高峰期人数及出现高峰期的时间线

准备数据:

//创建表player
create table if not exists player(
	id string,
	start_time string,
	end_time string) 
row format delimited fields terminated by '\t'; 
//装载数据
load data local inpath '/opt/module/data/play1.txt' into table player;

二、解决思路

        本题如果直接从SQL本身很难下手,不妨我们换个思路,假定我们拿到的是一条数据,现在用java程序怎么做?其实就是一个累加器的思想(如SPARK的累加器)。首先我们需要将这样的的一条记录进行拆分,分成不同的记录或数据流进入累加器,然后给每条记录标记类型,此时的数据流按照时间顺序依次进入累加器,然后在累加器中进行叠加,其中累计的结果最大时候就是所求的结果。其实本质是利用累加器思想,但进入累加器的数据是按时间排好序的时序流数据(数据进入按时间先后顺序进入)

        1)将数据按上播时间、下播时间切分,并标记上播、下播,然后用union all合并到一列,并按时间排序

        2)数据进入累加器进行累加算出该时间段在线人数,并补全该在线人数时间段的结束时间

        3)获取累加器中当前最大在线人数

        4)获取累加器中当前最大在线人数对应的数据

三、分步代码及测试

1.将数据按上播时间、下播时间切分,并标记上播、下播,然后用union合并到一列,并按时间排序

select 
	id,
	start_time at_time,
	'login' type
from player
union all
select
	id,
	end_time at_time,
	'logout' type
from player
order by at_time; t1

查询结果:

id      at_time             type

1001	2021-12-01 08:08:05	login 
1002	2021-12-01 08:15:07	login 
1003	2021-12-01 09:10:20	login 
1005	2021-12-01 09:26:05	login 
1006	2021-12-01 10:08:05	login 
1004	2021-12-01 10:20:07	login 
1004	2021-12-01 18:03:05	logout
1001	2021-12-01 19:02:07	logout
1002	2021-12-01 19:05:10	logout
1005	2021-12-01 19:52:15	logout
1001	2021-12-01 20:08:05	login 
1003	2021-12-01 21:02:07	logout 
1006	2021-12-01 22:05:06	logout 
1001	2021-12-01 23:02:07	logout 

2.数据进入累加器进行累加算出该时间段在线人数,并补全该在线人数时间段的结束时间

        该在线时间段在线人数:sum()开窗计算,type为login则+1,type为logout则-1,范围上无边界到当前行
        该在线人数时间段的结束时间:下一条数据时间即为本次时间段结束时间,使用lead()即可轻松算出,没有下一条数据则取本次数据时间

select
	at_time,
	lead(at_time,1,at_time) over(order by at_time) lead_time,
	sum(if(type = 'login',1,-1)) over(order by at_time rows between unbounded preceding and current row) online_ct
from t1; t2

查询结果:

at_time 	            lead_time 	            online_ct
2021-12-01 08:08:05		2021-12-01 08:15:07		1
2021-12-01 08:15:07		2021-12-01 09:10:20		2
2021-12-01 09:10:20		2021-12-01 09:26:05		3
2021-12-01 09:26:05		2021-12-01 10:08:05		4
2021-12-01 10:08:05		2021-12-01 10:20:07		5
2021-12-01 10:20:07		2021-12-01 18:03:05		6
2021-12-01 18:03:05		2021-12-01 19:02:07		5
2021-12-01 19:02:07		2021-12-01 19:05:10		4
2021-12-01 19:05:10		2021-12-01 19:52:15		3
2021-12-01 19:52:15		2021-12-01 20:08:05		2
2021-12-01 20:08:05		2021-12-01 21:02:07		3
2021-12-01 21:02:07		2021-12-01 22:05:06		2
2021-12-01 22:05:06		2021-12-01 23:02:07		1
2021-12-01 23:02:07		2021-12-01 23:02:07		0

3.获取累加器中当前最大在线人数

        按照在线人数倒序排序取第一条数据即为最大在线人数对应的数据

select
	max(online_ct) max_ct
from t2; 

查询结果:

max_ct
6

4.获取累加器中当前最大在线人数对应的数据

select
	at_time,
	lead_time,
	online_ct
from t2
where  t2.online_ct 
in (
    select
        max(online_ct) max_ct
    from t2
); 

查询结果:

at_time 	        lead_time 	        online_ct
2021-12-01 10:20:07	2021-12-01 18:03:05	6

四、最终代码及测试

with t2 as
(
    select
        at_time,
        lead(at_time, 1, at_time) over(order by at_time) lead_time,
        sum(if(type = 'login', 1, -1)) over(order by at_time rows between unbounded preceding and current row) online_ct
    from
        (
         select
             id,
             start_time at_time,
             'login'    type
         from player
         union all
         select
             id,
             end_time at_time,
             'logout' type
         from player
         order by at_time
        ) t1
)
select
    at_time,
    lead_time,
    online_ct
from t2
where t2.online_ct
in (
    select
        max(online_ct) max_ct
    from t2
);

测试结果:

at_time 	           lead_time           	  online_ct
2021-12-01 10:20:07    2021-12-01 18:03:05    6

五、小结

        本文针对SQL统计同时在线人数问题进行了分析,利用累加器思想对该问题进行求解,最终划归为时序数据,进行时序数据分析(常用技巧:打标签,形成序列,多序列进行分析),最后利用sum() over()对标签进行累加求出当前在线人数。本题最关键的点在于转换为时序数据及累加器的思想

        事实上该问题的分析在业务上具有重要的意义,我们能够实时跟踪随着时间变化的在线人数,了解服务器的负载变化情况,服务器的实时并发数等。该问题在不同业务场景下,有不同意义,比如某个游戏的同时在线人数,比如某个服务器的实时并发数,比如某个仓库的货物积压数量,某一段时间内的同时处于服务过程中的最大订单量等。实际上求最大在线人数和求实时在线人数是一回事,最大人数依赖于当前在线人数表,只有先求出当前在线人数表,才能求出最大同时在线人数

  • 3
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Flink水位线是用来处理事件时间处理的一种机制,用于确定事件时间流的进度以及触发窗口操作的时机。在Flink中,水位线是由数据流中的时间戳和延迟阈值决定的一个特殊时间戳。 水位线的主要作用是确定窗口何时关闭以及触发窗口计算。当数据流中的时间戳达到或超过水位线时,Flink认为该窗口内的所有事件都已经到达,可以进行窗口计算操作了。 在面试中,常见的水位线面试题可能包括以下几个方面: 1. 解释水位线的概念和作用。 2. 如何确定水位线时间戳和延迟阈值。 3. 水位线如何处理乱序事件。 4. 如何处理迟到事件。 答题时可以参考引用中提供的相关信息,其中介绍了Flink新版本不再提供At-Most-Once语义,并提到了水位线的概念。此外,引用也提到了水位线在任务反压中的作用。可以综合这些信息来回答关于Flink水位线面试题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [【先收藏,早晚用得到】100个Flink高频面试题系列(四)](https://blog.csdn.net/dajiangtai007/article/details/125260522)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值