hive的五种去重方式

本文通过四个SQL示例,展示了如何利用大数据处理技术解决实际问题,如用户去重、新增用户计算等。其中,介绍了distinct、groupby、row_number()、leftjoin和位操作等方法,并对比了它们在不同场景下的应用。在大数据环境下,位操作在处理新增用户问题时表现出高效性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.distinct

问题:
每个app下只保留一个用户
案例:

spark-sql> with test1 as
         > (select 122 as userid,100024 as apptypeid
         > union all
         > select 123 as userid,100024 as apptypeid
         > union all
         > select 123 as userid,100024 as apptypeid)
         > select 
         >   distinct userid,apptypeid
         > from test1;
122     100024                                                                  
123		100024
Time taken: 4.781 seconds, Fetched 2 row(s)
2.group by

问题:
每个app下只保留一个用户
案例:

spark-sql> with test1 as
         > (select 122 as userid,100024 as apptypeid
         > union all
         > select 123 as userid,100024 as apptypeid
         > union all
         > select 123 as userid,100024 as apptypeid)
         > select 
         >   userid,
         >   apptypeid
         > from 
         > (select 
         >   userid,
         >   apptypeid
         > from test1) t1
         > group by userid,apptypeid;
122     100024                                                                  
123		100024
Time taken: 10.5 seconds, Fetched 2 row(s)
3.row_number()

问题:
每个app下,每个用户取最近的渠道、版本、操作系统数据
分析:
distinct只是简单的去重,解决不了问题;group by也是简单的分组去重,也解决不了问题;order by只是简单的排序,也解决不了问题。那这个时候row_number()就派上用场了,分组完再排序
案例:

spark-sql> with test1 as
         > (select 122 as userid,100024 as apptypeid,'appstore' as qid,'ios' as os,'1.0.2' as ver,1627440618 as dateline
         > union all
         > select 123 as userid,100024 as apptypeid,'huawei' as qid,'android' as os,'1.0.3' as ver,1627440620 as dateline
         > union all
         > select 123 as userid,100024 as apptypeid,'huawei' as qid,'android' as os,'1.0.4' as ver,1627440621 as dateline)
         > select 
         >   userid,
         >   apptypeid,
         >   qid,
         >   os,
         >   ver
         > from 
         > (select 
         >   userid,
         >   apptypeid,
         >   qid,
         >   os,
         >   ver,
         >   row_number() over(distribute by apptypeid,userid sort by dateline desc) as rank
         > from test1) t1
         > where t1.rank=1;
122     100024  	appstore        ios     	1.0.2                                   
123		100024		huawei			android		1.0.4
Time taken: 5.286 seconds, Fetched 2 row(s)
4.left join

问题:
求每天的新增用户。现在有一张每天的用户表test1,有一张历史的新用户表test2(新用户:每个app下,每个用户只有一条数据)
分析:
1.每天的用户表test1用group by进行去重,得到每天的用户数据
2.再将用户数据根据历史新用户表进行关联,不在历史新用户表里面的,即为每天新增用户
案例:

spark-sql> with test1 as
         > (select 122 as userid,100024 as apptypeid
         > union all
         > select 123 as userid,100024 as apptypeid
         > union all
         > select 123 as userid,100024 as apptypeid),
         > 
         > test2 as
         > (select 122 as userid,100024 as apptypeid
         > union all
         > select 124 as userid,100024 as apptypeid
         > union all
         > select 125 as userid,100024 as apptypeid)
         > select 
         >   t1.userid,
         >   t1.apptypeid
         > from 
         > (select 
         >   userid,
         >   apptypeid
         > from test1
         > group by userid,apptypeid) t1
         > 
         > left join
         > (select 
         >   userid,
         >   apptypeid
         > from test2) t2
         > on t1.apptypeid=t2.apptypeid and t1.userid=t2.userid
         > where t2.userid is null;
123     	100024                                                                  
Time taken: 19.816 seconds, Fetched 1 row(s)
5.位操作:union all+group by

问题:
求每天的新增用户。现在有一张每天的用户表test1,有一张历史的新用户表test2(新用户:每个app下,每个用户只有一条数据)
分析:
1.每天的用户表test1用group by进行去重,得到每天的用户数据
2.将每天的用户数据打上标签10,历史的新用户数据打上标签1(位操作的标签)
3.进行union all拼接,对标签进行汇总,取标签为10的数据,即为每天的新增用户
案例:

spark-sql> with test1 as
         > (select 122 as userid,100024 as apptypeid
         > union all
         > select 123 as userid,100024 as apptypeid
         > union all
         > select 123 as userid,100024 as apptypeid),
         > 
         > test2 as
         > (select 122 as userid,100024 as apptypeid
         > union all
         > select 124 as userid,100024 as apptypeid
         > union all
         > select 125 as userid,100024 as apptypeid)
         > 
         > select 
         >   userid,
         >   apptypeid
         > from 
         > (select 
         >   sum(tag) as tag,
         >   userid,
         >   apptypeid
         > from 
         > (select 
         >   10 as tag,
         >   t1.userid,
         >   t1.apptypeid
         > from 
         > (select 
         >   userid,
         >   apptypeid
         > from test1
         > group by userid,apptypeid) t1
         > 
         > union all
         > select 
         >   1 as tag,
         >   userid,
         >   apptypeid
         > from test2) t2
         > group by userid,apptypeid) t3
         > where t3.tag=10;
123    	 100024                                                                  
Time taken: 10.428 seconds, Fetched 1 row(s)

总结:
1.简单数据去重建议用group by替代distinct的方式;distinct去重,所有数据都在一个reduce里面,很浪费资源,效率又很低,会有内存溢出的风险
2.对于求每天新增用户,如果数据量很大的情况下,建议用位操作的方式;

### 在 Hive 中对 `size` 字段进行处理的方法 在 Hive 中,可以利用多种方式来实现字段的操作。以下是几种常见的方法及其适用场景: #### 方法一:使用 `DISTINCT` 关键字 最简单的方式是对目标字段直接应用 `DISTINCT` 进行。这种方式适用于单字段或者少量字段的需求。 ```sql SELECT DISTINCT size FROM your_table; ``` 此查询会返回 `your_table` 表中 `size` 字段的所有唯一值[^1]。 --- #### 方法二:结合 `GROUP BY` 实现复杂逻辑下的 如果需要基于其他条件进一步筛选或聚合,则可以通过 `GROUP BY` 来完成更复杂的逻辑。 ```sql SELECT size FROM your_table GROUP BY size; ``` 上述语句的功能与 `DISTINCT` 类似,但在实际开发中,通常会在 `GROUP BY` 的基础上加入额外的聚合计算(如求和、计数等),从而满足更多业务需求。 --- #### 方法三:通过 `collect_set()` 函数收集并 当需要将某个字段的结果作为一个集合返回时,可以使用 Hive 提供的内置函数 `collect_set()`。该函数能够自动复项并将结果存储在一个数组中。 ```sql SELECT collect_set(size) AS unique_sizes FROM your_table; ``` 这种方法特别适合于多字段联合以及后续统计分析的需求。例如,在某些情况下可能还需要对这些唯一的 `size` 值做进一步的操作,比如计算其数量或其他属性[^3]。 --- #### 方法四:解决大数据量下性能问题——优化 `COUNT(DISTINCT)` 对于大规模数据集而言,单纯依赖 `COUNT(DISTINCT)` 可能会引起严的性能瓶颈甚至导致作业失败。此时可考虑采用分步策略减少中间状态的数据规模,具体做法包括但不限于以下几点: - **预过滤**:提前剔除不必要的记录; - **分区/桶化**:按照特定维度划分输入源以便更好地分布负载; - **调整 Reducer 数目**:合理设置 MapReduce 阶段中的资源分配参数以平衡工作强度。 下面是一个改进版的例子展示如何高效地估算不同 `size` 值的数量而不会引发明显的倾斜现象: ```sql SET hive.groupby.skewindata=true; INSERT OVERWRITE TABLE result_table SELECT COUNT(*) AS cnt_size_distinct FROM ( SELECT size FROM your_table DISTRIBUTE BY rand() SORT BY size -- 手动打散防止倾斜 GROUP BY size WITH ROLLUP ) t WHERE size IS NOT NULL AND _c0 IS NULL; -- 排除汇总行 ``` 此处引入了随机因子 (`rand`) 和排序机制帮助均匀散布 key-value 对到不同的 reducer 上面,有效缓解因部分 keys 占据过多比例所造成的阻塞状况[^4]。 --- ### 注意事项 尽管以上提到的技术手段各有优势,但也可能存在局限性。因此,在实际运用过程中应当综合考量诸如硬件配置、集群环境等因素后再决定最终方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值