布隆过滤器的使用场景
在架构设计中,通常会涉及这样的场景:
- 词典服务中,查询某个单词是否合法(即是否存在于保存有海量单词的词典文件中)
- 爬虫服务中,检查某个网页是否已经收录(即是否存在于海量的已爬取网页库中)
- 文章/商品推荐服务中,检查某篇文章/某个商品是否已经被推荐过(已推荐过的文章或商品不重复推荐);
- 查询某个元素是否在缓存中存在(假设缓存中的元素非常多)
以上的场景,本质上都是从海量数据中判断某一个元素是否存在。这种场景通常有两种解决方式:
- 假设空间无限且无需考察元素查找的时间复杂度,那么就将海量元素按连续内存或链表结构进行存储,之后以此查询,此种方式的优势在于简单,劣势也非常明显,那就是无论是空间复杂度还是时间复杂度都非常差,空间/时间复杂度均为O(N),假设数据量非常大时,无论是存储空间的占用还是时间的开销都无法满足业务要求;
- 采用空间换时间的方式,比如采用HashSet的存储方式,将元素通过某种hash算法获取hashcode,存储到指定的分桶中。这种方式的优势在于时间复杂度有效地得到了提升,即O(1);但缺点依然很明显,其空间存储要求为O(N)。因此,随着元素个数N的增大,分桶数急剧增多,假设数据量很大时,则无法满足(因为如果分桶数不增多,会频繁发生hash碰撞,导致在某些分桶或绝大多数分桶上退化成链表,虽说在JDK8上采用了红黑树的方式提升查找效率,但依然只是一种权衡,因为不过将时间复杂度从O(N)变成了O(logN)。