下午茶拼单系统—4. Redis BitMap人群标签与库存可见性
前言
拼单活动不是所有用户都能看到。比如校园店只给某栋楼的用户发券,写字楼活动只给企业群用户展示,或者新用户专享一杯咖啡 9.9 元。这个时候人群标签就成了营销系统的基础能力。
如果每次判断用户是否命中标签都查数据库,高峰期商品页会把数据库打得很难受。Redis BitMap 的优势是用很低的空间成本保存大量布尔状态,判断用户是否在标签里只需要一次 bit 查询。
为什么用BitMap
BitMap 本质上是按位存储。用户 ID 经过映射得到一个整数下标,命中标签就把该下标设置为 1。判断时读取同一个下标即可。对于只需要“是否属于某人群”的场景,它比 Set 更省内存,也更适合做批量统计。
当然,BitMap 要求用户 ID 能稳定映射到下标。项目里通过 RedisService 的 getIndexFromUserId 做映射。实际系统里我会把这个映射策略固定下来,并避免不同环境产生不同下标。
标签写入
@Override
public void addCrowdTagsUserId(String tagId, String userId) {
CrowdTagsDetail detail = new CrowdTagsDetail();
detail.setTagId(tagId);
detail.setUserId(userId);
try {
crowdTagsDetailDao.addCrowdTagsUserId(detail);
RBitSet bitSet = redisService.getBitSet(tagId);
bitSet.set(redisService.getIndexFromUserId(userId), true);
} catch (DuplicateKeyException ignore) {
// 忽略唯一索引冲突
}
}
这段实现做了两件事:先把明细写入 MySQL,再同步写入 Redis BitSet。MySQL 负责可追溯和离线统计,Redis 负责线上快速判断。DuplicateKeyException 被忽略,是因为标签导入任务可能重复执行,唯一索引用来保证幂等。
用户ID映射
BitMap 最怕的是下标冲突和下标过大。如果 userId 是纯数字,可以直接转 long;如果是字符串,就需要 hash 或维护映射表。hash 会有冲突风险,映射表更准确但成本更高。我的取舍是:业务 userId 可控时优先使用数字化 ID,不可控时单独设计映射服务。
public int getIndexFromUserId(String userId) {
// 示例:实际项目要保证映射稳定,避免环境差异。
return Math.abs(userId.hashCode());
}
public boolean isTagged(String tagId, String userId) {
RBitSet bitSet = redisService.getBitSet(tagId);
return bitSet.get(getIndexFromUserId(userId));
}
如果用户规模很大,hashCode 直接取绝对值可能导致 BitMap 过稀,内存不划算。更稳的方案是给用户分配连续数字 ID,或者按标签分桶。文章里写这个细节,是因为面试官很容易追问 BitMap 的下标怎么来。
可见性判断
标签不仅能控制优惠,还能控制活动可见性。比如某个拼单活动只允许标签用户看到,此时 TagNode 可以读取 groupBuyDiscount 的 tagId,再查询 Redis BitMap。命中则 visible=true,否则返回普通商品信息。
boolean visible = true;
String tagId = dynamicContext.getGroupBuyActivityDiscountVO()
.getGroupBuyDiscount()
.getTagId();
if (StringUtils.isNotBlank(tagId)) {
visible = redisService.getBitSet(tagId)
.get(redisService.getIndexFromUserId(request.getUserId()));
}
dynamicContext.setVisible(visible);
这里我不会把“不命中标签”当成系统异常,而是业务结果。用户不在活动人群内,前端仍然可以展示商品原价,只是不展示拼单优惠。这样活动配置错误也不会影响普通购买路径。
小结
Redis BitMap 适合承载高频、简单、布尔型的人群判断。MySQL 保留明细,Redis 做在线判断,唯一索引保证导入幂等,规则树节点把标签结果转成可见性和参与状态。这个设计正好对应简历里的“用户标签与可售库存、人群可见性控制”。





