Spark合理分区:高基数列同值归同一分区(支持SparkSQL)
SparkSQL 实现同AlmostUID数据统一分区的方案
需求说明
- 数据集包含30亿个唯一的AlmostUID值,需将数据划分为1000个分区
- 硬性规则:同一AlmostUID的所有记录必须归属同一个分区,绝对不允许出现同一个UID的记录分散在多个分区的情况
输入数据
| AlmostUID | LoadMonth |
|---|---|
| 1 | April |
| 1 | May |
| 2 | April |
| 3 | June |
| 4 | June |
| 4 | August |
| 5 | September |
预期输出说明
GoodPartition:符合要求的分区,同一AlmostUID的所有记录都集中在同一个分区(比如AlmostUID=1、4的所有记录都各自处于同一分区)BadPartition:不符合要求的分区,存在同一AlmostUID的记录分散到不同分区的情况(比如AlmostUID=1的记录分别在分区1和2)
预期输出数据
| AlmostUID | LoadMonth | GoodPartition | BadPartition |
|---|---|---|---|
| 1 | April | 1 | 1 |
| 1 | May | 1 | 2 |
| 2 | April | 1 | 1 |
| 3 | June | 2 | 1 |
| 4 | June | 2 | 2 |
| 4 | August | 2 | 2 |
| 5 | September | 2 | 2 |
SparkSQL 实现方案
生成合规分区(GoodPartition)
通过hash函数对AlmostUID计算哈希值,再对目标分区数(1000)取模,最后加1保证分区从1开始计数:
SELECT AlmostUID, LoadMonth, MOD(HASH(AlmostUID), 1000) + 1 AS GoodPartition, -- 以下是错误分区示例:用LoadMonth作为分区依据,会导致同一UID分散 CASE LoadMonth WHEN 'April' THEN 1 WHEN 'May' THEN 2 WHEN 'June' THEN 1 WHEN 'August' THEN 2 WHEN 'September' THEN 2 END AS BadPartition FROM your_table_name;
原理说明
- 同一个AlmostUID的
HASH(AlmostUID)结果固定,取模1000后得到的分区值也固定,从根源上保证同一UID的所有记录进入同一个分区 - 错误分区示例中,用LoadMonth作为分区依据,导致AlmostUID=1的两条记录因LoadMonth不同被分到不同分区,直接违反需求规则
- 针对30亿条的大规模数据,这种基于UID哈希取模的方式还能保证各分区数据分布相对均匀,有效避免数据倾斜(前提是AlmostUID本身分布均匀)
内容的提问来源于stack exchange,提问作者Error_2646
相关产品推荐
相关产品推荐

