大数据与算法系列之海量数据查找算法

时间:2024-03-31 22:29:05

在某些时候,可能会涉及在海量数据中的查找,如果采用通常的做法,则很难达到一定的效果,在实际工程实践中,海量数据的查找性能很肯恩鬼成为整个系统的性能瓶颈,在海量数据中的查找包括基于布隆过滤器的方式,以及基于倒排索引的数据结构。

基于布隆过滤器查找

布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制矢量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,确定是有一定的误判率和删除困难。

概念

如果要判断一个元素是不是在一个集合中,通常的方法是将集合中所有的元素保存起来,然后通过比较去确定,链表,树,哈希表等数据结构都是使用这种思路。但是随着集合中元素的增加,需要的存储空间越来越大,同时,检索速度也越来越慢,上述三种结构的检索时间复杂度分别为O(n),O(logn),O(n/k).

布隆过滤器的原理是,当一个元素加入集合中时,通过K个散列函数将这个元素映射为一个位组数中的K个点,把他们置为1,检索时,只要查看这些点是不是都是1就大约知道集合中有没有它了:如果这些点有任何一个是0,则被检测元素一定不再元素中,如果都是1,则被检测元素很可能在,这就是布隆过滤器的基本思想。

相比于其他的数据结构,布隆过滤器在空间和时间方面有巨大的优势,布隆过滤器存储空间和插入/查询时间都是常数(O(k))。另外,散列函数相互之间没有关系,方便由硬件并行实现,布隆过滤器本身不需要存储元素,在某些对保密性要求非常严格的场合有优势。此外,布隆过滤器可以表示全集,其他任何数据结构都没有此功能。

但是布隆过滤器的确定和优点一样明显,误算率就是其中之一。随着存入的元素数量增加,误算率随之增加,但是如果元素数量太少,则使用散列表即可。

另外,一般情况下不能从布隆过滤器中删除元素,例如,把位数组变成整数数组,没插入一个元素则计数器相应的加1,这样删除元素时将计数器减掉就可以了,然后要保证安全的删除元素并非如此简单,首先必须保证删除的元素的确在布隆过滤器里面,而这一点单凭这个过滤器是无法保证的,另外,计数器回绕也会造成问题。

在降低误算率方面,也有不少工作,因此出现了很过布隆过滤器的变种。

应用:搜索引擎中的URL过滤

假设要编写一个网络爬虫程序,由于网络间的链接错综复杂,爬虫在网络间爬行很可能会形成“环”,为了避免形成“环”,就需要知道爬虫程序已经访问过哪些URL。给一个URL,怎样知道爬虫程序是否已经访问过呢?有一下几种方法。

  1. 将访问过的URL保存到数据库
  2. 用HashSet将访问过的URL保存起来,只需接近O(1)的代价就可以查到一个URL是否被访问过了。
  3. URL经过MD5或SHA-1等单向哈希后再保存到 Hash Set或数据库。
  4. Bit-Map方法。建立一个 BitSet,将每个URL经过一个哈希函数映射到某一位。

方法1~3都是将访问过的URL完整保存,方法(4)则只标记URL的一个映射位。以上方法在数据量较小的情况下都能完美解决问题,但是当数据量变得非常庞大时问题就来了。

方法(1)的缺点:数据量变得非常庞大后,关系型数据库查询的效率会变得很低。而且每来一个URL就启动一次数据库查询是不是太小题大做了。

方法(2)的缺点:太消耗内存。随着URL的增多,占用的内存会越来越多。就算只有1亿个URL,每个URL仅为50bit,就需要5GB内存。

方法(3):由于字符串经过MD5处理后的信息摘要长度只有128bit,SHA-1处理后也只有160bit,因此方法(3)比方法(2)节省了好几倍的内存。

方法(4)消耗内存是相对较小的,但缺点是单一哈希函数发生冲突的概率太高。还记得数据结构课上学过的Hash表冲突的各种解决方法吗?若要降低冲突发生的概率到1%,就要将 BitSet的长度设置为URL个数的100倍。

除了URL去重外,在海量文本中查找某个词语的出现也会采用布隆过滤器。由于单词数量的巨大,需要在超过一亿的数量级上判断某个单词是否存在,因此需要一种极其高效的方式去实现。传统的方法是,将所有数据存放在一个集合里面,或许是链表,或许是树或许是散列表,然后分别通过时间复杂度O(n),O(lgn),O(n/k)找到。虽然散列表的性能已经很好,但是依然觉得在亿级以上数据查找不是很理想。

布隆过滤器是由一个很长的二进制向量及多个随机函数组成的。当添加一个元素到大集合中时,需要利用N个哈希方法将此元素映射为N个点,这N个点组成一个位阵列形式,且它们的值设定为1。当判断是否存在时,只需判断新产生的位阵列是否均为1即可,可按照“&”运算进行。如果“&”运算的最终结果为0,则需要判断的元素一定不存在。反之,结果为1,则说明该元素存在。可利用布隆过滤器的基本思想来为语料库中词组是否存在进行判断。

倒排索引查找

索引是一种用于数据快速查找的数据结构,哈希表、二分查找、分块查找也可以视为一种索引,这类索引的价值在于在较短的时间内获得最相关、最全、最深的数据集合。在通常使用的索引中,大多是基于顺序表、哈希表或B+树的索引。倒排索引( InvertedIndex)主要用于信息检索领域,它是其中最常用的数据索引存储结构,被用来存储文档集合中某个单词对应的文档集合及单词在文件中存在的位置,因此也称为反向索引,与其相对应的是正向索引,正向索引用于存储每个文件的单词列表,并记录其位置,以下表中的文件及对应句子内容为例

大数据与算法系列之海量数据查找算法

大数据与算法系列之海量数据查找算法

大数据与算法系列之海量数据查找算法

在信息检索中,可以根据文件生成的倒排索引,当用户检索“数据算法”时,会将词语对应的文件集合取出,并且会根据相关性对文件进行排序处理,得到最终检索后的结果。

此外,在某些检索系统中,可能会有不存储词语在文件中位置的情况,但是目前大多数检索系统都会存储,主要基于两个原因:

一是在海量数据的检索情况下,全文检索过程中如果没有记录位置,在获取文件动态摘要时,会通过遍历文件的方式查找关键词出现的位置,存在性能损耗,而这对于数据量级较小的系统则影响较小;

二是在检索结果展示过程中,为获得较好的动态摘要,需要对文件内搜索词分布情况进行统计,一般情况下会在较集中词语的区域提取摘要,如果提前确定关键词位置,对检索体验有很好的提升。倒排索引的数据结果是检索系统中非常重要的组成部分,检索时间是检索系统中最重要的衡量指标之一,其核心在于倒排索引的设计。

虽然哈希表等其他数据结构也能够较好地处理数据索引问题,但是对于数据量较大的情况,哈希表的性能也会受到较大的影响。在数据量较大时,会将海量数据进行分布式索引,分布式哈希表和分布式倒排索引则是较好的处理方式,但从检索的综合评价角度,分布式索引更为合适。