如何在大量数据集中快速查找某条记录是否存在的思考

问题

如果我们有1个billion的用户名,如何快速的查询某一个用户名是否已经存在呢?

解决方案

假如我们可以考虑使用工具来解决我们的问题,我们可以考虑使用数据库或者cache(比如Redis)来解决这个问题。在本文中,我们不对类似的使用某种服务或者工具的解决方案进行讨论。我们专注于两个基于算法的方案的讨论。

方案一

我们可以考虑使用prefix tree来解决这个问题。prefix tree又叫trie,或者字典树。简单来说,prefix tree使用字符串的prefix构建树。从树根到某一个节点的路径既是某一个字符串的前缀。例如下图所示即为一棵prefix tree:

如果我们将所有的名字构建成一棵prefix tree,我们就可以快速查出某一个名字否是已经存在。另一种和prefix tree可以比较的解决方案是hash table。关于prefix tree和与hash table的比较可以参看这篇文章

方案二

另一种方案是bloom filter。

Bloom Filter (布隆过滤器) 是一种高效的流带过滤算法。它能迅速判断一个元素是否在集合中。基本特点如下:

  • 能够 快速过滤 大量元素,不需要保存整个元素集合。

  • 它存在 一定的询问错误率 (偏向 偏积 错误),即可能报错元素在集合中,但是不会报错一个实际在集合中的元素为不在。

  • 低内存占用,为大规模流带分析提供优秀解决方案。

Bloom Filter 的工作原理

Bloom Filter 使用 一个字节串 (通常是一个大型数组) 来表示集合,并且使用 k 个哈希算法函数 对每个元素进行对应编码。基本步骤如下:

1. 添加元素

假设我们要将一个元素 X 添加到 Bloom Filter:

  • X 通过 k 个不同的哈希函数 计算出 k 个位置 (bit 位);

  • 将该 k 个位置在字节串中设置为 1

  • 完成添加。

2. 查询元素

要判断一个元素 Y 是否在 Bloom Filter 中:

  • Y 通过 k 个不同的哈希函数 计算出 k 个位置

  • 如果该 k 个位置都是 1,则该元素 可能在 集合中;

  • 如果任意一个位置为 0,则该元素 确实不在 集合中。

如下图所示是一个使用了3个hash函数的bloom filter:

假如我们需要判断“red”是否已经存在,我们就计算3个hash函数的值并查询所对应的位置的bit是否已经被设置。因为3个bit都被设置了,我们可以“red”非常有可能已经存在。

思考

首先我们会发现prefix tree的解决方案看起来更好。首先,该方案更为直接和易于理解。其次,该方案可以给出准确的结果。相反的,bloom filter的解决方案是基于概率的。这样决定了bloom filter的方案只能应用于对于false positive不那么敏感的情况中。这里我们可以举两个例子。例子一,假如我们想在用户创建用户名之前检查该名字是否已经被占用,我们就可以使用bloom filter,因为即便我们错误的将一个不存在的名字判定为已经存在,对用户的影响是极小的,该用户只需要稍微修改自己的用户名即可。例子二,假如我们是一个航空的用户管理系统。我们需要判断一个用户是否是VIP来给予某种优惠服务。那么对于false positive可能就无法接受,因为这意味着我们会错误的给与非VIP用户过多的优惠。

那么为什么还会有bloom filter这样的算法存在?答案是空间的代价。如果我们考虑使用prefix tree处理一个billion大小的字符串集合,我们大概需要500G的内存空间;而bloom filter只需要大概1G的内存空间。

所以我们可以简单的总结如下:如果对于positive false敏感,bloom filter不适用。否则如果数据集较小,可以优先考虑使用prefix tree;如果数据集较大,优先考虑使用bloom filter。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值