8.1.8 Bitmap/HyperLogLog/Geo简介
在Redis的高级数据结构中,Bitmap、HyperLogLog与Geo常用于高效统计与地理位置检索。本节给出原理草图、安装与验证、命令示例、排错与练习,便于直接落地使用。
原理草图(简化)
安装与验证(适用于快速实验)
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install -y redis-server
sudo systemctl enable --now redis-server
# 验证
redis-cli ping
# 预期输出: PONG
Bitmap:高效布尔统计#
适用场景:签到、在线状态、日活统计
核心命令解释:
- SETBIT key offset value:设置第 offset 位为 0/1
- GETBIT key offset:读取第 offset 位
- BITCOUNT key:统计位为 1 的数量
- BITOP AND/OR/XOR/NOT dest key:位运算聚合
示例:统计 7 天游客签到
# 以用户id=1001为例,按天偏移(day0~day6)
redis-cli SETBIT signin:1001 0 1
redis-cli SETBIT signin:1001 1 1
redis-cli SETBIT signin:1001 3 1
redis-cli GETBIT signin:1001 3
# 预期输出: 1
redis-cli BITCOUNT signin:1001
# 预期输出: 3 (表示签到3天)
示例:统计当日活跃用户数(DAU)
# 将用户ID作为偏移位
redis-cli SETBIT dau:20250101 1001 1
redis-cli SETBIT dau:20250101 1002 1
redis-cli SETBIT dau:20250101 1050 1
redis-cli BITCOUNT dau:20250101
# 预期输出: 3
排错要点
- ERR bit offset is not an integer or out of range:offset 非整数或过大
- 位图占用内存与最大 offset 相关,若 offset 过大导致内存异常增长
- 建议设计 offset 规则并限制用户ID范围或做映射
练习
1. 统计连续 30 天签到用户数量,使用 BITOP 合并多日位图。
2. 设计用户ID到 offset 的映射策略并评估内存占用。
HyperLogLog:近似去重统计#
适用场景:UV、独立IP统计
特点:约 12KB 内存估算百万级基数,存在误差(约 0.81%)
核心命令解释:
- PFADD key element [element ...]:添加元素
- PFCOUNT key [key ...]:估算基数
- PFMERGE destkey sourcekey [sourcekey ...]:合并多个HLL
示例:统计每日UV
redis-cli PFADD uv:20250101 u1 u2 u3 u3
redis-cli PFCOUNT uv:20250101
# 预期输出: 3
redis-cli PFADD uv:20250102 u3 u4
redis-cli PFCOUNT uv:20250102
# 预期输出: 2
# 合并两天UV
redis-cli PFMERGE uv:20250101-02 uv:20250101 uv:20250102
redis-cli PFCOUNT uv:20250101-02
# 预期输出: 4
排错要点
- 误差属于正常现象,不适用于需要精确去重的场景
- 若结果异常偏小/偏大,确认是否误用了不同 key 或数据未写入成功
- 可用 MONITOR 临时观察写入命令流(生产慎用)
练习
1. 连续 7 天UV用HLL记录并合并周UV。
2. 将UV与Bitmap对比内存占用与精度差异。
Geo:地理位置检索#
适用场景:附近的人、门店、距离排序
原理:基于 ZSet 存储 GeoHash,支持距离计算
核心命令解释:
- GEOADD key longitude latitude member:写入坐标
- GEOPOS key member:查询坐标
- GEODIST key m1 m2 [unit]:计算距离
- GEORADIUS key lon lat radius unit:按坐标范围查询
- GEORADIUSBYMEMBER key member radius unit:按成员范围查询
示例:门店定位与范围查询
# 添加门店坐标(经度、纬度)
redis-cli GEOADD shop:geo 116.397128 39.916527 "店A"
redis-cli GEOADD shop:geo 116.405285 39.904989 "店B"
redis-cli GEOADD shop:geo 116.384377 39.913011 "店C"
# 查询店A坐标
redis-cli GEOPOS shop:geo "店A"
# 预期输出: 116.397128 39.916527
# 计算店A到店B距离(km)
redis-cli GEODIST shop:geo "店A" "店B" km
# 查询某坐标5km内门店并带距离与坐标
redis-cli GEORADIUS shop:geo 116.397128 39.916527 5 km WITHDIST WITHCOORD
排错要点
- ERR invalid longitude,latitude:经纬度范围非法
- 查询结果为空:确认 key 是否正确、坐标是否写入、范围单位是否匹配
- 数据规模大时,考虑分片或定期清理过期门店
练习
1. 以城市为单位分 key(如 geo:beijing),做 10km 范围查询。
2. 使用 ZCARD 对比 Geo 内存与数据规模关系。
运维建议汇总
- Bitmap:规划 offset 与命名规则,避免无效大偏移浪费内存
- HyperLogLog:适合统计类场景,不可用于精确去重
- Geo:适当设置 TTL 或分片,防止 ZSet 过大导致查询变慢