背景
有一亿条数字,怎么判断一个数字是否在这一亿条数字当中?时间复杂度、空间复杂度越低越好
想一想如果是你,你会怎么解决?以及你的解决方案的成本是多少?
实现方式
使用map存储这一亿条数字,然后判断是否在map中
package main
import (
"fmt"
"runtime"
)
func PrintMemory() {
var memStats runtime.MemStats
runtime.ReadMemStats(&memStats)
// 将字节转换为兆字节(MB)
toMB := func(bytes uint64) uint64 {
return bytes / 1024 / 1024
}
fmt.Printf("Allocated Memory: %d MB\n", toMB(memStats.Alloc))
fmt.Printf("Total Allocated Memory: %d MB\n", toMB(memStats.TotalAlloc))
fmt.Printf("Heap Memory: %d MB\n", toMB(memStats.HeapAlloc))
fmt.Printf("Heap In-use Memory: %d MB\n", toMB(memStats.HeapInuse))
fmt.Printf("Stack Memory: %d MB\n", toMB(memStats.StackInuse))
fmt.Println("========")
}
func main() {
fmt.Println("初始化内存")
PrintMemory()
var intMap = make(map[int]struct{})
for i := 0; i < 10000*10000; i++ {
intMap[i] = struct{}{}
}
if _, ok := intMap[10]; ok {
fmt.Println("key existed")
}
fmt.Println("map 创建完成后的内存")
PrintMemory()
runtime.GC()
fmt.Println("gc之后的内存")
PrintMemory()
}
初始化内存
Allocated Memory: 0 MB
Total Allocated Memory: 0 MB
Heap Memory: 0 MB
Heap In-use Memory: 0 MB
Stack Memory: 0 MB
========
key existed
map 创建完成后的内存
Allocated Memory: 2357 MB
Total Allocated Memory: 3271 MB
Heap Memory: 2357 MB
Heap In-use Memory: 2359 MB
Stack Memory: 0 MB
========
gc之后的内存
Allocated Memory: 0 MB
Total Allocated Memory: 3271 MB
Heap Memory: 0 MB
Heap In-use Memory: 0 MB
Stack Memory: 0 MB
========
数据库存储这一亿条数字,然后使用select查询
create table data_map
(
id int(11) unsigned auto_increment comment '自增ID'
primary key,
data_id int(11) unsigned not null comment '数据ID',
index data_id_index (data_id)
)
每行包含一个 id 字段(4字节),一个 data_id 字段(4字节) 8字节 * 100000000 大概 800M(没统计索引等占用的存储空间)
redis set 存储这一亿条数字,然后使用SISMEMBER判断是否存在
其他的分布式存储等等
布隆过滤器
布隆过滤器
当一个元素被加入集合时,通过K个散列函数将这个元素映射成一个位数组中的K个点,把它们置为1。检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了:如果这些点有任何一个0,则被检元素一定不在;如果都是1,则被检元素很可能在。这就是布隆过滤器的基本思想。
原理简述
布隆过滤器是一个 bit 向量或者说 bit 数组,长这样:
输入baidu,经过K个hash函数计算
输入tencent,经过K个hash函数计算
优缺点分析
优点
- 占用存储空间低,只使用一个bitmap存储
- 查找效率和新增元素效率高,布隆过滤器存储空间和插入/查询时间都是常数 O(K)
- 不存储元素本身,对保密要求非常严格的场合有优势
缺点
- **误算率!!! **
- 不支持删除 可以了解下布谷鸟过滤器
如何选择哈希函数个数和布隆过滤器长度
- bitmap长度不能太短,不然查询值大部分都是“可能存在”
- hash函数个数不能太少也不能太多,太多影响性能,太少误报率会增高
使用在线工具去计算出满足业务场景的值
应用场景
脱离业务场景的讲架构都是耍流氓!!!
URL 去重
需求
一个爬虫程序抓取上亿条url,url可能存在重复,已经抓取过的url就不要再次抓取,减少请求量
功能分析
- 可以使用布隆过滤器存储抓取过的url,误判导致的影响很低,再抓取一次也可以
- 爬虫程序可能部署在多个节点,布隆过滤器要考虑分布式环境,可以采用redis实现布隆过滤器
总结
- 大数据量判断数据是否存在的各种方式
- 布隆过滤器的原理及应用场景