不能用set()做亿级日志去重统计,因其内存占用大(1亿条超20GB)、无法流式处理;应使用HyperLogLog,仅需12KB内存、支持百亿级估算、误差

亿级日志去重统计不能用 set(),内存会爆
直接 set() 存所有 user_id 或 ip,在 1 亿条日志下轻松吃掉 20+ GB 内存——这不是夸张,是 Python str 对象本身带引用头、哈希缓存、扩容冗余的必然结果。更糟的是,len(set(...)) 要等全部加载完才出结果,无法流式处理。
真实场景里,你往往只需要“大概有多少独立用户”,误差 ±2% 完全可接受,而 HyperLogLog(HLL)正是为此设计:固定 12KB 内存,支持百亿级去重估算,且支持合并(merge)。
- Python 标准库不提供 HLL,必须用第三方包:
redis(服务端)、pyhll(纯 Python)、或更推荐的hyperloglog(轻量、C 扩展、API 简洁) -
pip install hyperloglog后,核心就两个操作:hll.add()和len(hll) - 注意:HLL 不保存原始值,不可反查有哪些唯一项,只回答“有多少”
用 hyperloglog 库做单机流式去重统计
适合离线分析日志文件、Kafka 消费、或小规模实时 pipeline。关键点是别一次性读全再塞,要边读边 add。
from hyperloglog import HyperLogLog
hll = HyperLogLog()
<p>with open("access.log", "r") as f:
for line in f:</p><h1>假设每行 JSON,提取 user_id 字段</h1><pre class="brush:php;toolbar:false;"> try:
user_id = json.loads(line).get("user_id")
if user_id:
hll.add(str(user_id)) # HLL 只接受 bytes 或 str,务必转 str
except (json.JSONDecodeError, ValueError):
continueprint(len(hll)) # 输出估算基数,比如 9843212,误差通常
-
hll.add()是幂等的:重复add同一个值不会影响结果 - 输入必须是
str或bytes;传int会报TypeError,别想当然 - 如果日志字段含空格或特殊字符,先
.strip()再add,否则"123 "和"123"被视为不同
多进程/多文件合并时用 union(),别用 pickle
单机处理超大日志常拆成多个子任务(如按天分片、按 worker 分发),每个子任务生成自己的 HyperLogLog 实例。合并时不要用 pickle 序列化再反序列化——慢且可能版本不兼容;直接用内置 union() 方法。
# 处理 day1.log 得到 hll1,day2.log 得到 hll2... hll_total = hll1.union(hll2) print(len(hll_total))
-
union()返回新实例,原实例不变;也支持多参数:hll1.union(hll2, hll3, hll4) - 各子任务的
HyperLogLog必须用相同精度初始化(默认p=14,即约 12KB),否则union()会抛ValueError - 如果要用 Redis 做分布式聚合,改用
redis-py的pfadd/pfcount,但注意 Redis 的 HLL 是固定精度(p=14),不支持自定义
和 Redis 的 PFADD 对比:什么时候该用谁
如果你已有 Redis 集群,且日志是实时写入(如 Nginx → Kafka → Python consumer → Redis),用 PFADD 最省事;但如果只是跑一次离线分析,起 Redis 反而重,本地 hyperloglog 库更快启动、无网络开销、调试直观。
- Redis
PFADD key value:value 必须是 string,二进制安全;Python client 调用是r.pfadd("hll:users", user_id) - 本地库优势:支持任意 Python 对象转 str 后 add,调试时可随时
print(len(hll))中间结果;Redis 则需r.pfcount("hll:users") - 坑点:Redis 的
PFMERGE不支持通配符,合并多个 key 得显式列出;而本地union()可接任意数量实例,更灵活
实际用的时候,最易忽略的是数据清洗环节——HLL 对输入极其敏感。"123"、123、b"123"、"123\n" 全算不同值。基数不准,八成不是算法问题,是日志字段没对齐。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











