目录
轻量化人群标签数据采集与Redis BitMap应用
为什么需要人群标签?
设计思路:轻量化人群标签系统
1. 核心目标
2. 技术选型:Redis BitMap
3. 数据链路设计
技术实现:代码级拆解
1. 人群标签任务调度
2. 用户ID与BitMap索引映射
3. BitMap的读写验证
效果与优势
1. 存储成本对比
2. 查询场景示例
3. 运营价值
总结与扩展
1. 轻量化设计的意义
2. 未来扩展方向
欢迎关注我的博客!26届java选手,一起加油
最近在学习一个拼团项目中涉及到的人群模块的设计,写下一些实现与思考。
在电商平台中,精准的用户运营是提升转化率的核心。比如,拼多多需要通过用户行为(如拼团参与次数、消费金额)筛选目标人群,定向发放优惠券或推送活动通知。然而,面对海量用户数据(如百万级用户ID),传统数据库查询效率低、存储成本高,因此需要一种轻量化、高性能的解决方案。
AND/OR
操作快速计算交集、并集,适合多标签组合筛选。SETBIT
和GETBIT
命令保证高并发下的数据一致性。业务数据(拼团记录) → 数据库存储 → 标签计算 → 写入Redis BitMap → 运营投放
在实际业务中会有专门的记录用户标签的数据。
通过TagService.execTagBatchJob
执行标签计算任务:
public void execTagBatchJob(String tagId, String batchId) {
// 1. 查询批次任务配置(如标签类型、统计时间范围)
CrowdTagsJobEntity jobEntity = repository.queryCrowdTagsJobEntity(tagId, batchId);
// 2. 模拟数仓数据采集(实际场景从数仓读取)
List userIdList = getMockUserIds();
// 示例用户列表
// 3. 写入数据库
Redis BitMap for (String userId : userIdList) {
repository.addCrowdTagsUserId(tagId, userId);
}
// 4. 更新标签统计量
repository.updateCrowdTagsStatistics(tagId, userIdList.size()); }
在TagRepository
中,用户ID通过哈希函数映射到BitMap的索引位置:
public void addCrowdTagsUserId(String tagId, String userId) {
// 1. 写入数据库(持久化存储)
crowdTagsDetailDao.addCrowdTagsUserId(tagId, userId);
// 2. 写入Redis
BitMap RBitSet bitSet = redisService.getBitSet(tagId);
int index = redisService.getIndexFromUserId(userId);
// 用户ID → 哈希索引
bitSet.set(index, true);
}
MurmurHash
)。userId.hashCode() % 1_000_000
),确保索引在BitMap范围内。 default int getIndexFromUserId(String userId) {
try {
// 步骤1:获取 MD5 哈希算法实例
MessageDigest md = MessageDigest.getInstance("MD5");
// 步骤2:计算用户ID的 MD5 哈希值
byte[] hashBytes = md.digest(userId.getBytes(StandardCharsets.UTF_8));
// 步骤3:将哈希值转换为正整数
BigInteger bigInt = new BigInteger(1, hashBytes);
// 步骤4:对最大值取模,确保索引在合理范围内
return bigInt.mod(BigInteger.valueOf(Integer.MAX_VALUE)).intValue();
} catch (NoSuchAlgorithmException e) {
// 异常处理:MD5算法不存在时抛出运行时异常
throw new RuntimeException("MD5 algorithm not found", e);
}
}
通过测试用例验证数据是否正确写入:
@Test public void test_get_tag_bitmap() {
RBitSet bitSet = redisService.getBitSet("RQ_KJHKL98UU78H66554GFDV");
log.info("用户 wuwuw是否存在?{}", bitSet.get(redisService.getIndexFromUserId("xiaofuge"))); // 预期 true
log.info("用户 gudebai 是否存在{}",bitSet.get(redisService.getIndexFromUserId("gudebai"))); // 预期 false }
存储方式 | 100万用户内存占用 | 查询性能 |
---|---|---|
MySQL 索引表 | 约50MB | 毫秒级(带索引) |
Redis Set | 约16MB | 毫秒级 |
Redis BitMap | 122KB | 微秒级 |
GETBIT
操作)。BITOP AND
运算)。tagRule
(如JSON
配置),动态生成标签。通过本文,可以为你快速掌握如何在小规模数据下构建高效的人群标签系统提供一些思路。