首页 > 试题广场 >

25年网易云音乐-歌手新歌首发后听众分层次日留存与时段活跃矩

[编程题]25年网易云音乐-歌手新歌首发后听众分层次日留存与时段活跃矩
  • 热度指数:5 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解

1. 题目描述

背景
某音乐流媒体平台的内容运营团队在做独立音乐人新歌发布效果分析。每当一首新歌在某位歌手的主页首发上线,团队希望分析:首发当日完整听完该新歌的听众("首发完听用户"),在接下来的 D+1、D+3、D+7 日,是否还在该歌手的任意歌曲下继续产生完整收听(即再次回流听这位歌手)。同时按听众在首发日的收听时段做分层,产出一张歌手 × 时段 × 回流日的矩阵。

表 1:t_song(歌曲表)

  • song_id:BIGINT,歌曲 ID
  • artist_id:BIGINT,歌手 ID
  • song_name:VARCHAR(64),歌曲名
  • duration_sec:INT,歌曲总时长(秒)
  • release_time:DATETIME,首发上线时间(2025 年内,含时分秒;每首歌一个)

表 2:t_play(收听流水表)

  • play_id:BIGINT,收听记录 ID
  • user_id:BIGINT,用户 ID
  • song_id:BIGINT,歌曲 ID(关联 t_song.song_id)
  • play_start:DATETIME,开始收听时间
  • play_sec:INT,实际收听秒数(可能小于 duration_sec)

2. 问题

第一步:识别"首发完听用户"
对每首新歌,首发日 =DATE(release_time)。定位每个歌手首发日当天收听了该歌手该首新歌,且至少有一条 play_sec >= duration_sec(即完整听完一次)的用户。把这些用户记为该歌手的"首发完听用户"。同一用户若在多首新歌的首发日都完听,可重复计入不同歌手的基数。

第二步:按首发日收听时段分层(对每个"首发完听用户 × 歌手"组合单独判定)
取该用户当天对该歌手该新歌最早一条 play_start,按小时归入:

  • morning:HOUR(play_start) ∈ [6, 11](即 06:00:00–11:59:59)
  • afternoon:HOUR(play_start) ∈ [12, 17]
  • night:其他所有时间([18, 23]与[0, 5]都算 night)

第三步:回流判定
回流 = 该用户在 D+N 当天(日历日) 对同一歌手的任意歌曲产生至少一次完整收听(play_sec >= duration_sec)。

  • D+1 =DATE_ADD(release_date, INTERVAL 1 DAY)
  • D+3 =DATE_ADD(release_date, INTERVAL 3 DAY)
  • D+7 =DATE_ADD(release_date, INTERVAL 7 DAY)
  • 若同一歌手同日有多首新歌首发(不同 song_id),以各自的 release_date 分别判定用户回流;同一用户对同一歌手可能被多首新歌各自计入基数(允许重复)。

输出字段

  • artist_id(歌手 ID)
  • time_slot(时段:morning / afternoon / night)
  • base_user_cnt(该歌手该时段的首发完听用户基数,即"用户 × 新歌"组合数)
  • d1_rate(D+1 回流率,四舍五入保留 2 位小数)
  • d3_rate(D+3 回流率,同上)
  • d7_rate(D+7 回流率,同上)

只输出base_user_cnt > 0的行;无需输出空组合。

排序规则(严格按此顺序):

  1. d7_rate降序
  2. base_user_cnt降序
  3. artist_id升序
  4. time_slot按固定顺序 morning → afternoon → night(不是字典序

3. 示例数据表

t_song

song_id artist_id song_name duration_sec release_time
1001 501 Midnight Drive 210 2025-04-10 00:00:00
1002 501 Summer Light 180 2025-04-15 00:00:00
1003 502 Quiet Street 240 2025-04-10 00:00:00

t_play

play_id user_id song_id play_start play_sec
1 9001 1001 2025-04-10 08:15:00 210
2 9001 1002 2025-04-11 09:00:00 180
3 9001 1001 2025-04-13 22:00:00 210
4 9002 1001 2025-04-10 14:00:00 210
5 9002 1001 2025-04-10 14:40:00 100
6 9002 1001 2025-04-17 15:00:00 210
7 9003 1001 2025-04-10 23:30:00 209
8 9004 1001 2025-04-10 20:00:00 210
9 9004 1001 2025-04-11 10:00:00 150
10 9001 1002 2025-04-15 10:00:00 180
11 9001 1001 2025-04-16 10:00:00 210
12 9001 1001 2025-04-18 10:00:00 210
13 9001 1001 2025-04-22 10:00:00 210
14 9005 1003 2025-04-10 07:00:00 240
15 9005 1003 2025-04-17 07:00:00 240

4. 示例数据查询结果表

推导

歌手 501 共有两次新歌首发(1001 日首发于 04-10,1002 首发于 04-15),"首发完听用户"组合(user × song):

  • (9001, 1001):首发日完听 at 08:15(morning);D+1 04-11 听 1002 完听 ✓;D+3 04-13 听 1001 完听 ✓;D+7 04-17 无 501 完听记录 ✗
  • (9002, 1001):首发日完听 at 14:00(afternoon);D+1 04-11 ✗;D+3 04-13 ✗;D+7 04-17 听 1001 完听 ✓
  • (9003, 1001):首发日未完听(209<210),不进基数
  • (9004, 1001):首发日完听 at 20:00(night);D+1 04-11 play_sec=150<210 ✗;D+3/D+7 无 ✗
  • (9001, 1002):首发日 04-15 完听 at 10:00(morning);D+1 04-16 听 1001 完听 ✓;D+3 04-18 听 1001 完听 ✓;D+7 04-22 听 1001 完听 ✓

歌手 501 分组:

  • morning:(9001,1001)、(9001,1002) → base=2;D+1=1.00;D+3=1.00;D+7=0.50
  • afternoon:(9002,1001) → base=1;D+1=0.00;D+3=0.00;D+7=1.00
  • night:(9004,1001) → base=1;D+1=0.00;D+3=0.00;D+7=0.00

歌手 502:

  • morning:(9005,1003) → base=1;D+1=0.00;D+3=0.00;D+7=1.00

按严格排序规则(d7 降序 → base 降序 → artist_id 升序 → slot 固定序):

artist_id time_slot base_user_cnt d1_rate d3_rate d7_rate
501 afternoon 1 0.00 0.00 1.00
502 morning 1 0.00 0.00 1.00
501 morning 2 1.00 1.00 0.50
501 night 1 0.00 0.00 0.00
示例1

输入

CREATE TABLE t_song (
    song_id       BIGINT,
    artist_id     BIGINT,
    song_name     VARCHAR(64),
    duration_sec  INT,
    release_time  DATETIME
);

CREATE TABLE t_play (
    play_id     BIGINT,
    user_id     BIGINT,
    song_id     BIGINT,
    play_start  DATETIME,
    play_sec    INT
);

INSERT INTO t_song VALUES
(1001, 501, 'Midnight Drive',   210, '2025-04-10 00:00:00'),
(1002, 501, 'Summer Light',     180, '2025-04-15 00:00:00'),
(1003, 502, 'Quiet Street',     240, '2025-04-10 00:00:00');

INSERT INTO t_play VALUES
(1,  9001, 1001, '2025-04-10 08:15:00', 210),
(2,  9001, 1002, '2025-04-11 09:00:00', 180),
(3,  9001, 1001, '2025-04-13 22:00:00', 210),
(4,  9002, 1001, '2025-04-10 14:00:00', 210),
(5,  9002, 1001, '2025-04-10 14:40:00', 100),
(6,  9002, 1001, '2025-04-17 15:00:00', 210),
(7,  9003, 1001, '2025-04-10 23:30:00', 209),
(8,  9004, 1001, '2025-04-10 20:00:00', 210),
(9,  9004, 1001, '2025-04-11 10:00:00', 150),
(10, 9001, 1002, '2025-04-15 10:00:00', 180),
(11, 9001, 1001, '2025-04-16 10:00:00', 210),
(12, 9001, 1001, '2025-04-18 10:00:00', 210),
(13, 9001, 1001, '2025-04-22 10:00:00', 210),
(14, 9005, 1003, '2025-04-10 07:00:00', 240),
(15, 9005, 1003, '2025-04-17 07:00:00', 240);

输出

artist_id|time_slot|base_user_cnt|d1_rate|d3_rate|d7_rate
501|afternoon|1|0.00|0.00|1.00
502|morning|1|0.00|0.00|1.00
501|morning|2|1.00|1.00|0.50
501|night|1|0.00|0.00|0.00

这道题你会答吗?花几分钟告诉大家答案吧!