最近有需求需要将推荐系统的日志数据接入到 Hbase 中 ,
最初的 RowKey 实际方案为 : 时间 + 手机号 + 推荐唯一标识 ,但是由于该数据量级很大 ( 1亿条/天 ) ,经常由于热点写入问题导致程序停止 ,因此设计了一种预分区方案来解决热点写入问题
散列 RowKey 设计方案为 : 根据原 RowKey 获取散列值 + 原 RowKey
获取散列值思路 :
- 首先要保证相同的 RowKey 得到的散列值相同 ,由此想到了 MD5 加密
- MD5 加密是否是均匀的散列 ? 这个答案为 : 是 ,这个是别人的 文章 : MD5 散列函数的结果是均匀分布吗?
- 如果直接以 MD5 做散列值的话 存在两点问题 : RowKey 很长 ,抽取数据时不方便
- 根据前文可以知道 ,MD5 的每个字符都是均匀分布的 ,因此可以取 MD5 中的一个字符来做散列值
- 由于 MD5 有 0 - 9 和 a - f 共 16 种字符 ,可以转化为 000 - 016 这种形式 ( 具体转换形式通过 ASCII )
散列工具类 :
/**
* 根据传入的RowKey做MD5散列,然后取第一个字符的ASCII码并进行处理,返回16个分区的RowKey
* 使用该散列方法应该配合HBase預分區
*
* SPLITS => ['000','001','002','003','004','005','006','007','008','009','010','011','012','013','014','015','016']
*
* @param rowKey 需要做散列的RowKey
* @return 已经散列过的RowKey
*/
def getHashRowKey(rowKey: String): String = {
val md5 = MessageDigest.getInstance(CodeConstant.MD5)
val encoded = md5.digest(rowKey.getBytes)
val array = encoded.map("%02x".format(_)).mkString.take(1).toCharArray
var int = array(0).toInt
if (int < 97) int = int - 48 else int = int - 97 + 10
f"$int%3d".replaceAll(" ", "0") + rowKey
}
Hbase 建表语句 :
create 'multi:t_wx_recommend_log_test', 'cf1' , SPLITS => ['000','001','002','003','004','005','006','007','008','009','010','011','012','013','014','015','016']
写入情况如下 ,由此可见散列还是蛮均匀的 :
分日提取数据 SQL ( Hbase 的 Hive 映射表 ) :
INSERT OVERWRITE TABLE trace.t_test_wx_recommend_log PARTITION (opera_day = 20200406)
SELECT recommend_type,
opera_time,
phone_number,
activity_id,
rule_id,
channel_code,
recommend_position,
goods1,
goods2,
goods3,
goods4,
goods5,
goods6,
goods7,
goods8,
goods9,
goods10,
goods11,
goods12,
goods13,
goods14,
goods15,
goods16,
goods17
FROM (
SELECT *
FROM trace.t_test_wx_recommend_log_map
WHERE key >= '00020200406'
AND key < '00020200407'
UNION ALL
SELECT *
FROM trace.t_test_wx_recommend_log_map
WHERE key >= '00120200406'
AND key < '00120200407'
UNION ALL
SELECT *
FROM trace.t_test_wx_recommend_log_map
WHERE key >= '00220200406'
AND key < '00220200407'
UNION ALL
SELECT *
FROM trace.t_test_wx_recommend_log_map
WHERE key >= '00320200406'
AND key < '00320200407'
UNION ALL
SELECT *
FROM trace.t_test_wx_recommend_log_map
WHERE key >= '00420200406'
AND key < '00420200407'
UNION ALL
SELECT *
FROM trace.t_test_wx_recommend_log_map
WHERE key >= '00520200406'
AND key < '00520200407'
UNION ALL
SELECT *
FROM trace.t_test_wx_recommend_log_map
WHERE key >= '00620200406'
AND key < '00620200407'
UNION ALL
SELECT *
FROM trace.t_test_wx_recommend_log_map
WHERE key >= '00720200406'
AND key < '00720200407'
UNION ALL
SELECT *
FROM trace.t_test_wx_recommend_log_map
WHERE key >= '00820200406'
AND key < '00820200407'
UNION ALL
SELECT *
FROM trace.t_test_wx_recommend_log_map
WHERE key >= '00920200406'
AND key < '00920200407'
UNION ALL
SELECT *
FROM trace.t_test_wx_recommend_log_map
WHERE key >= '01020200406'
AND key < '01020200407'
UNION ALL
SELECT *
FROM trace.t_test_wx_recommend_log_map
WHERE key >= '01120200406'
AND key < '01120200407'
UNION ALL
SELECT *
FROM trace.t_test_wx_recommend_log_map
WHERE key >= '01220200406'
AND key < '01220200407'
UNION ALL
SELECT *
FROM trace.t_test_wx_recommend_log_map
WHERE key >= '01320200406'
AND key < '01320200407'
UNION ALL
SELECT *
FROM trace.t_test_wx_recommend_log_map
WHERE key >= '01420200406'
AND key < '01420200407'
UNION ALL
SELECT *
FROM trace.t_test_wx_recommend_log_map
WHERE key >= '01520200406'
AND key < '01520200407'
UNION ALL
SELECT *
FROM trace.t_test_wx_recommend_log_map
WHERE key >= '01620200406'
AND key < '01620200407') TEMP;
Comments | NOTHING