首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 开源软件 >

Cassandra中布隆过滤器实现详解

2012-07-03 
Cassandra中布隆过滤器实现详解【原创】?Cassandra中BloomFIlter实现详解零、BloomFilter原理概述http://hi.b

Cassandra中布隆过滤器实现详解【原创】

?

CassandraBloomFIlter实现详解

零、BloomFilter原理概述

http://hi.baidu.com/waxiga/blog/item/33ef2ff49b138530bd3109ad.html

http://pages.cs.wisc.edu/~cao/papers/summary-cache/node8.html(cassandra中用到了其中的结论,特别注意那个表格)

一、从getFilter()函数入手

1.1第一个getFilter()函数:传入参数为元素的个数numElements、期望每个元素的桶个数targetBucketsPerElem(即m/n,m为比特数组位数,n为元素个数)。核心代码:

publicstaticBloomFilter getFilter(longnumElements, inttargetBucketsPerElem)

{

intmaxBucketsPerElement = Math.max(1,maxBucketsPerElement(numElements));

intbucketsPerElement = Math.min(targetBucketsPerElem,maxBucketsPerElement);

BloomCalculations.BloomSpecificationspec = BloomCalculations.computeBloomSpec(bucketsPerElement);

returnnewBloomFilter(spec.K,bucketsFor(numElements,spec.bucketsPerElement));

}

?

?

1)maxBucketsPerElement(numElements)函数返回每个元素最大的桶数目。返回值为:min(BloomCalculations.probs.length- 1, (Integer.MAX_VALUE- 20)/ (double)numElements);其中前一项值为15.maxBucketsPerElement变量最大值为15

2)实际每个元素的桶数目为min(targetBucketsPerElem,maxBucketsPerElement);即取期望的桶数目和实际可能最大的桶数目中间的小值。

3)根据实际每个元素的桶数目,选择哈希函数的个数。BloomCalculations.BloomSpecificationspec =BloomCalculations.computeBloomSpec(bucketsPerElement);其中computeBloomSpec(bucketsPerElement)函数主要是创建BloomSpecification对象,newBloomSpecification(optKPerBuckets[bucketsPerElement],bucketsPerElement);其中构造函数参数为在当前bucketsPerElement的情况下,误报率最低的哈希函数的个数(即最优的哈希函数的个数optK)。

4)创建BloomFilter对象并返回。参数为哈希函数个数spec.K,以及BitSet对象(由bucketsFor()函数返回。该函数主要是根据元素数目和每个元素的桶数目,创建具有min(Integer.MAX,(numElements* bucketsPer + 20))大小的BitSet)。

?

1.2第二个getFilter()函数:传入参数是元素个数和错误率。

publicstaticBloomFilter getFilter(longnumElements, doublemaxFalsePosProbability)

{

assertmaxFalsePosProbability <= 1.0 : "Invalidprobability";

intbucketsPerElement = maxBucketsPerElement(numElements);

BloomCalculations.BloomSpecificationspec = BloomCalculations.computeBloomSpec(bucketsPerElement,maxFalsePosProbability);

returnnewBloomFilter(spec.K,bucketsFor(numElements,spec.bucketsPerElement));

}

?

1)同上,maxBucketsPerElement(numElements)函数返回每个元素最大的桶数目。返回值为:min(BloomCalculations.probs.length- 1, (Integer.MAX_VALUE- 20)/ (double)numElements);其中前一项值为15.maxBucketsPerElement变量最大值为15

2根据每个元素的最大的桶数目和错误率,创建BitSet对象。

3)主要函数BloomCalculations.computeBloomSpec(bucketsPerElement,maxFalsePosProbability);

主要作用就是求出满足错误率要求的最小的butcktsPerElement和最小的哈希函数个数K。

4)最后构造BloomFilter对象返回,跟前一个一样。

可以总结下,maxBucketsPerElement最大是15,故哈希函数个数最多为8个。

?

二、BloomFilter

?

addStringkey)函数分析

1)创建了BloomFilter对象后,接下来分析其中的函数,调用add函数将相应的值加入布隆过滤器,即对其经过哈希后相应的BitSet位置位。

publicvoid add(Stringkey){

for(intbucketIndex : getHashBuckets(key))

{

filter_.set(bucketIndex);

}

}

getHashBuckets(key)函数返回key经过哈希后需要置位的int类型数组,filter_即为创建的BitSet对象。然后调用filter_.set(bucketIndex)对BitSet相应的位置位。

?

2)getHashBuckets(key)->Filter.getHashBuckets(key)->Filter.getHashBuckets(key,hashCount,buckets())->Filter.getHashBuckets(byte[]b, inthashCount, intmax)。

其中buckets()函数即返回filter_.size()。一个小点注意下:BItSet构造函数创建对象时,如果你指定的大小不是字对齐的,则创建后的大小会自动对其。比如你指定大小为100,实际创建的大小就是128

?

3)关键的哈希函数就是Filter.getHashBuckets(byte[]b, inthashCount, intmax)。

staticint[]getHashBuckets(byte[]b, inthashCount, intmax)

{

int[]result = newint[hashCount];

inthash1 = hasher.hash(b,b.length,0);

inthash2 = hasher.hash(b,b.length,hash1);

for(inti = 0; i < hashCount; i++)

{

result[i]= Math.abs((hash1 + i * hash2) % max);

}

returnresult;

}

?

从代码中可以看出,这个哈希函数用到了双重散列,我们知道在所有的开放寻址法中,双重散列是最好方法之一。因为双重散列用到了O(m^2)种探查序列。具体分析可参见算法导论11.4节。

?

哈希函数用的是MurmurHash对象的hash函数,该函数很复杂,就不分析了。代码如下:

publicinthash(byte[]data, intlength, intseed) {

intm = 0x5bd1e995;

intr = 24;

?

inth = seed ^ length;

?

intlen_4 = length >> 2;

?

for(inti = 0; i < len_4; i++) {

inti_4 = i << 2;

intk = data[i_4 + 3];

k = k << 8;

k = k | (data[i_4+ 2] & 0xff);

k = k << 8;

k = k | (data[i_4+ 1] & 0xff);

k = k << 8;

k = k | (data[i_4+ 0] & 0xff);

k *= m;

k ^= k >>>r;

k *= m;

h *= m;

h ^= k;

}

?

//avoid calculating modulo

intlen_m = len_4 << 2;

intleft = length - len_m;

?

if(left != 0) {

if(left >= 3) {

h ^= (int)data[length - 3] << 16;

}

if(left >= 2) {

h ^= (int)data[length - 2] << 8;

}

if(left >= 1) {

h ^= (int)data[length - 1];

}

?

h *= m;

}

?

h ^= h >>>13;

h *= m;

h ^= h >>>15;

?

returnh;

}

?

isPresent(Stringkey)函数分析

1)函数代码如下:

publicbooleanisPresent(String key)

{

for(intbucketIndex : getHashBuckets(key))

{

if(!filter_.get(bucketIndex))

{

returnfalse;

}

}

returntrue;

}

?

2)由add函数分析就很容易了,根据key值哈希后得到的数组,判断数组中的值是否置位,只有所有的位都置位了才可能在里面,只要有一位没有置位,则key值肯定不在里面。

?

?

热点排行