2019-02-12

   今天是猪年工作第二天 。

   今年的必须在工作、业务能力上下功夫 。

   工作时间绝不看微博。股票 。

   每天学习的晚上总结。打印出来重复看 。

   学而不思则罔,思而不学则殆 。

 

   老梁故事汇

   讲朋友:每个人都喜欢听赞美、赞同的声音 。不能太直接 。以为自己是刀子嘴豆腐心 。如果是豆腐心就不会刀子嘴 。

   讲说话:两岁学讲话,一辈子学闭嘴 。

   讲学习:人习惯于舒适的环境,舒适的环境会导致懒惰 。

 

 

    

转载于:https://www.cnblogs.com/huangzhuzhe/p/10365852.html

你提供的日志数据包含三列:**日期、用户、年龄**,并且你提到“活跃用户”是指**连续两天都有访问记录的用户**。你希望用 **Hive SQL** 实现“计算日期及排名的差值”,这个描述稍显模糊,但结合上下文,我们可以理解为: > **找出每个用户连续访问的日期对,并计算这些日期之间的差值(比如相邻登录天数差是否为1),进而识别出“活跃用户”(即存在至少一对连续两天登录的用户)** 我们将分步骤实现以下目标: --- ### ✅ 目标: 1. 去重(同一天同一个用户多次访问只算一次) 2. 对每个用户按日期排序并打上排名 3. 计算当前日期与上一次访问日期的差值(`date_diff`) 4. 筛选出 `date_diff = 1` 的记录 → 表示连续两天访问 5. 找出所有满足“连续两天访问”的用户(即活跃用户) 6. 可选:统计每个用户的连续访问次数 --- ### 📌 Hive SQL 实现代码如下: ```sql WITH daily_visit AS ( -- 步骤1: 去重,确保每个用户每天只保留一条记录 SELECT DISTINCT date, user_id, age FROM ( SELECT split(trim(line), ',')[0] AS date, split(trim(line), ',')[1] AS user_id, split(trim(line), ',')[2] AS age FROM logs_table ) raw ), ranked_log AS ( -- 步骤2: 按用户分组,按日期升序排序,生成排名 SELECT date, user_id, age, row_number() OVER (PARTITION BY user_id ORDER BY date) AS rn FROM daily_visit ), lagged_log AS ( -- 步骤3: 使用 LAG 获取上一次的日期 SELECT date, user_id, age, rn, LAG(date, 1) OVER (PARTITION BY user_id ORDER BY date) AS prev_date FROM ranked_log ) -- 步骤4: 计算当前日期与前一天的差值,筛选出差值为1的(即连续访问) SELECT date, user_id, age, prev_date, datediff(from_unixtime(unix_timestamp(date, 'yyyy-MM-dd')), from_unixtime(unix_timestamp(prev_date, 'yyyy-MM-dd'))) AS date_diff FROM lagged_log WHERE prev_date IS NOT NULL AND datediff(from_unixtime(unix_timestamp(date, 'yyyy-MM-dd')), from_unixtime(unix_timestamp(prev_date, 'yyyy-MM-dd'))) = 1; ``` --- ### 🔍 代码解释: 1. **`daily_visit` CTE**: - 使用 `DISTINCT` 去除同一用户在同一天的重复访问。 - 假设原始数据存储在一个文本表 `logs_table` 中,每行是字符串如 `"2019-02-11,test_1,23"`。 2. **`ranked_log` CTE**: - 使用 `row_number()` 给每个用户的访问按时间排序编号,便于后续使用 `LAG`。 3. **`lagged_log` CTE**: - 使用 `LAG(date, 1)` 获取该用户上一次访问的日期。 4. **最终 SELECT**: - 使用 `datediff` 函数计算当前日期和前一次日期的差值。 - `unix_timestamp(date, 'yyyy-MM-dd')` 将字符串转为时间戳,再用 `from_unixtime` 转为 Hive 可识别的日期格式进行差值计算。 - 筛选 `date_diff = 1`,即连续两天访问的情况。 --- ### ✅ 输出结果示例(基于你的数据): | date | user_id | age | prev_date | date_diff | |------------|---------|-----|------------|-----------| | 2019-02-12 | test_2 | 19 | 2019-02-11 | 1 | | 2019-02-16 | test_2 | 19 | 2019-02-15 | 1 | 说明: - `test_2` 在 2019-02-11 和 2019-02-12 连续访问 → 是活跃用户 - `test_2` 在 2019-02-15 和 2019-02-16 也连续 → 再次贡献一次连续记录 - `test_1` 虽然有 2019-02-11 和 2019-02-13,但中间缺了一天,差值为2,不算连续 --- ### ✅ 最终识别“活跃用户” 如果你想只列出所有**活跃用户**(即至少有一次连续两天访问): ```sql SELECT DISTINCT user_id FROM lagged_log WHERE datediff(from_unixtime(unix_timestamp(date, 'yyyy-MM-dd')), from_unixtime(unix_timestamp(LAG(date, 1) OVER (PARTITION BY user_id ORDER BY date), 'yyyy-MM-dd'))) = 1; ``` 或者基于上面的结果: ```sql SELECT DISTINCT user_id FROM ( SELECT user_id, datediff(from_unixtime(unix_timestamp(date, 'yyyy-MM-dd')), from_unixtime(unix_timestamp(prev_date, 'yyyy-MM-dd'))) AS date_diff FROM lagged_log WHERE prev_date IS NOT NULL ) t WHERE date_diff = 1; ``` 输出: ``` test_2 ``` (注意:`test_1` 没有连续两天访问,所以不是活跃用户) --- ### ❗注意事项: - Hive 中 `datediff` 要求参数为 `string` 类型且格式为 `yyyy-MM-dd`,我们通过 `unix_timestamp` 和 `from_unixtime` 安全转换。 - 如果你的 Hive 表已经是结构化表(非文本解析),可跳过第一层 `split` 解析。 - 若日期字段已是 `DATE` 类型,则可直接使用 `datediff(date, prev_date)`。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值