1问题遇到的现象和发生背景
需要处理数据量上亿的数据来去重,根据数据库某一个字段来作为唯一键来判断是否重复
2我的解答思路和尝试过的方法
我想用python dataframe自带的一个去重函数,但是数据量实在太大,内存承受不住,使用列表循环去重也不行
3我想要达到的结果
我想要最好能实现分批读取数据去重,不用redis等转库办法
上亿的数据量,读出来都很费时间了,不仅内存扛不住,网络带宽、磁盘io都会有压力。为什么不直接在源数据库里用sql去重呢?
题主:
有几个地方,第一,你说你处理上亿的数据,这些数据来源是什么,换句话说你的这些数据在你准备读取前存储在什么数据库中。第二,你的物理设备配置是什么样的,多大内存,CPU核数,硬盘多大?
最后提供你一个案例可以参考:
你可以使用BloomFilter
BloomFilter 是一个定容的过滤器,是指最大的误报率是0.1%(可以省略),capacity 是容量大小,而 ScalableBloomFilter 是一个不定容量的布隆过滤器,它可以不断添加元素。运算符即可了。
from pybloom import BloomFilter
bf = BloomFilter(capacity=10000, error_rate=0.001)
bf.add("www.baidu.com")
print("www.baidu.com" in bf) # True print("www.douban.com" in bf) # False
上亿级太大了,光是2^32B就是4GB,这只是字节上亿,数据上亿的话肯定内存是装不下这么多的。可以借助文件存一部分。分开去重。比如说根据字段的前几位划分开,然后再对这个文件再分开去重(分治下去,达到10^5差不多就可以使用python自带的set去重了)。最后把去重的传回数据库。
刚才看了题主的评论,用的是mysql,本地内存不大
这个肯定就不能蛮干
只能用时间去弥补空间的不足,方法可以有很多种,大体上分为两类
1.依赖数据库的自带功能,用sql来实现,mysql有自带的唯一键索引,可以达到去重的情况,是重启一张新表来存还是利用存储过程 delete +select形式,根据唯一键去重
2.依赖程序了,这个方法就太多了,根据唯一键查询或者盲查多条数据,根据唯一键去重,删数据,存数据
用 DISTINCT 去重分页, 然后联表/内嵌
select * from t1 left join (select DISTINCT uid from t1 limit 0, 10) as t2 on t1.uid=t2.uid
为什么全是给的数据库去重的,这些还用得着你们教,我闭着眼睛都能写出来,都说了我连redis我都不用,你们公司都是让你们在数据库操作的?服务器受不受得了,我每次都认真给别人解答,至少被采纳几次了都,我就问一个问题,一点实质性帮助都没,我入行四五年了,连私聊加微信问代码我都给过,求求来个认真解惑的
别人都在认真的回答你,你入行这么久不可能不知道 时间和空间只能选一个的道理。我不知道你有没有了解过ES或是大数据系统的设计,即便是一个强大如ES也做不到准确的大数据量去重还不耗时。去重是没有办法做分批的,除非你重复的数量特别多(这种你确实可以分批把去重的结果汇聚后在做一次总去重)。假设你几亿数据只有一个重复值,那么你就是要对比所有批的,就如同用ES也是要查所有分区的(搞不好就崩了)。公司对于这种去重操作有一种方案是每天跑定时任务拿着新增的数据和以往已经去重的对比插入,而目的就是为了去重计数,这是在大数据系统里跑的,也只跑了一年数据量达到几十亿就放弃了这种方式,数据量大了之后我们是要放弃准确性的,后面的统计都是有误差的我们不会告诉用户准确值,只说多少亿。
至于服务器受不受了的问题,任何系统设计的时候一定要考虑横行扩展的,服务器受不了就得分库,而去重还是插入去重的,不可能查出来在去重的。
你的这个太大了,Python处理不过来
创建一个新表,在新表将那个字段设为UNIQUE,然后将数据从旧表中插入到新表中,比如你可以用INSERT IGNORE来去重。完后你可以将旧表删除,新表重命名为旧表的名字
数据既然在mysql ,mysql 本身不能去重麽,直接在mysql 先去重好了