学习笔记-bloom filter
来源:互联网 发布:thinkphp分销商城源码 编辑:程序博客网 时间:2024/06/06 15:38
实例学习Bloom Filter
0. 科普
1. 为什么需要Bloom Filter
2. 基本原理
3. 如何设计Bloom Filter
4. 实例操作
5. 扩展
0. 科普
Bloom Filter是由Bloom在1970年提出的一种多哈希函数映射的快速查找算法。通常应用在一些需要快速判断某个元素是否属于集合,但是并不严格要求100%正确的场合。
1. 为什么需要Bloom Filter
举例说明:假设有2000万个url,现在判断一个新的url是否在这2000万个之中。可以有的思路:
- 将访问过的URL保存到数据库。
- 用HashSet将访问过的URL保存起来。那只需接近O(1)的代价就可以查到一个URL是否被访问过了。
- URL经过MD5等单向哈希后再保存到HashSet或数据库。
- Bit-Map方法。建立一个BitSet,将每个URL经过一个哈希函数映射到某一位。
分析
思路1:当数据量很大时,查询数据库变得效率底下
思路2:太消耗内存,还得把字符串全部储存起来
思路3:字符串经过MD5处理后有128个bit,比思路2省了很多空间
思路4:一个字符串仅用一位来表示,比思路3还节省空间
当然前提是会出现误判(哈希后表示相同),为了继承这么好的思路,同时减少误判的情况,可以来个折衷:一个哈希函数生成一个位,用多个哈希函数生成多个位来存储一个字符串。这样比Bit-Map多用了些空间,但是减少了误判率。
2. 基本原理
这样把大量的字符串存起来。查找时,用同样的哈希处理待查串,如果对应的各位上都为1,说明该字符串可能在这些字符串中,否则一定不在其中。
3. 如何设计Bloom Filter
如何降低误判率是关键,这需要
- 选取区分度高的哈希函数
- 根据存储数组、哈希函数个数、误判率之间的关系,分配空间、个数
直接利用前人的结论:
其中f'是自己期望的误判率,m是总共开辟的存储空间位数,n是待存储字符串的个数,k是哈希函数的个数,f是真正的误判率。
4. 实例操作
需求:2000万个已知url,100个待查url
设计:
1. 设定误判率为0.1, n=2000万,计算
m = n * 1.44 * math.log(1/f)/math.log(2)=287014588k = 0.693 * m / n= 10f = (1 - math.exp(-1 * k * n / m)) ** k = 0.00101298781512
参考代码(c++)
objects = main.o hash.o bloomfilter.omain : $(objects) g++ -o main $(objects)main.o : hash.h bloomfilter.hbloomfilter.o : bloomfilter.hhash.o : hash.hclean: rm *.o main
main.cc
#include <iostream>#include <fstream>#include <sstream>#include <cstring>#include <string>#include "bloomfilter.h"using namespace std;const int MAXSIZE = 400000000; int main(int argc, char **argv){ char *poolfile = argv[1]; char *testfile = argv[2]; cout << poolfile << endl; ifstream fpool(poolfile); ifstream ftest(testfile); if(!fpool) { cout << "cannot open the file:" << poolfile << endl; return 0; } if(!ftest) { cout << "cannot open the file:" << testfile << endl; return 0; } BloomFilter bf(MAXSIZE); bf.setBit(fpool); cout << "Store OK" << endl; bf.checkBit(ftest); cout << "Check OK" << endl; fpool.close(); ftest.close();}
bloomfilter.h
#include <iostream>#include <string>#include <fstream>#include <vector>#include "hash.h"using namespace std;class BloomFilter{ public: BloomFilter(int size) : SIZE(size) { vec.resize(size); }; void setBit(ifstream &f); void setBit(const string &s); void setBit(unsigned int count); bool checkBit(ifstream &f); bool checkBit(const string &s); bool checkBit(unsigned int count); private: vector<char> vec; const unsigned int SIZE;};
bloomfilter.cc
#include "bloomfilter.h"void BloomFilter::setBit(ifstream &f){ string line; while(f >> line) { setBit(line); }}bool BloomFilter::checkBit(ifstream &f){ string line; while(f >> line) { if(!checkBit(line)) cout << line << endl; }}void BloomFilter::setBit(const string &s){ unsigned int bitpos = 0; const char *str = s.c_str(); int len = s.size(); bitpos = RSHash(str, len); setBit(bitpos); bitpos = JSHash(str, len); setBit(bitpos); bitpos = PJWHash(str, len); setBit(bitpos); bitpos = ELFHash(str, len); setBit(bitpos); bitpos = BKDRHash(str, len); setBit(bitpos); bitpos = SDBMHash(str, len); setBit(bitpos); bitpos = DJBHash(str, len); setBit(bitpos); bitpos = DEKHash(str, len); setBit(bitpos); bitpos = BPHash(str, len); setBit(bitpos); bitpos = FNVHash(str, len); setBit(bitpos);}bool BloomFilter::checkBit(const string &s){ unsigned int bitpos = 0; const char *str = s.c_str(); int len = s.size(); bool rev = true; bitpos = RSHash(str, len); rev &= checkBit(bitpos); bitpos = JSHash(str, len); rev &= checkBit(bitpos); bitpos = PJWHash(str, len); rev &= checkBit(bitpos); bitpos = ELFHash(str, len); rev &= checkBit(bitpos); bitpos = BKDRHash(str, len); rev &= checkBit(bitpos); bitpos = SDBMHash(str, len); rev &= checkBit(bitpos); bitpos = DJBHash(str, len); rev &= checkBit(bitpos); bitpos = DEKHash(str, len); rev &= checkBit(bitpos); bitpos = BPHash(str, len); rev &= checkBit(bitpos); bitpos = FNVHash(str, len); rev &= checkBit(bitpos); return rev;}void BloomFilter::setBit(unsigned int count){ count = count % (SIZE * 8); vec[count / 8] |= (1 << (count % 8));}bool BloomFilter::checkBit(unsigned int count){ count = count % (SIZE * 8); return vec[count / 8] &= (1 << (count % 8));}
hash.h
unsigned int RSHash(const char* str, unsigned int len);unsigned int JSHash(const char* str, unsigned int len);unsigned int PJWHash(const char* str, unsigned int len);unsigned int ELFHash(const char* str, unsigned int len);unsigned int BKDRHash(const char* str, unsigned int len);unsigned int SDBMHash(const char* str, unsigned int len);unsigned int DJBHash(const char* str, unsigned int len);unsigned int DEKHash(const char* str, unsigned int len);unsigned int BPHash(const char* str, unsigned int len);unsigned int FNVHash(const char* str, unsigned int len);
hash.cc
#include "hash.h"unsigned int RSHash(const char* str, unsigned int len){ unsigned int b = 378551; unsigned int a = 63689; unsigned int hash = 0; unsigned int i = 0; for(i=0; i<len; str++, i++) { hash = hash*a + (*str); a = a*b; } return hash;}/* End Of RS Hash Function */unsigned int JSHash(const char* str, unsigned int len){ unsigned int hash = 1315423911; unsigned int i = 0; for(i=0; i<len; str++, i++) { hash ^= ((hash<<5) + (*str) + (hash>>2)); } return hash;}/* End Of JS Hash Function */unsigned int PJWHash(const char* str, unsigned int len){ const unsigned int BitsInUnsignedInt = (unsigned int)(sizeof(unsigned int) * 8); const unsigned int ThreeQuarters = (unsigned int)((BitsInUnsignedInt * 3) / 4); const unsigned int OneEighth = (unsigned int)(BitsInUnsignedInt / 8); const unsigned int HighBits = (unsigned int)(0xFFFFFFFF) << (BitsInUnsignedInt - OneEighth); unsigned int hash = 0; unsigned int test = 0; unsigned int i = 0; for(i=0;i<len; str++, i++) { hash = (hash<<OneEighth) + (*str); if((test = hash & HighBits) != 0) { hash = ((hash ^(test >> ThreeQuarters)) & (~HighBits)); } } return hash;}/* End Of P. J. Weinberger Hash Function */unsigned int ELFHash(const char* str, unsigned int len){ unsigned int hash = 0; unsigned int x = 0; unsigned int i = 0; for(i = 0; i < len; str++, i++) { hash = (hash << 4) + (*str); if((x = hash & 0xF0000000L) != 0) { hash ^= (x >> 24); } hash &= ~x; } return hash;}/* End Of ELF Hash Function */unsigned int BKDRHash(const char* str, unsigned int len){ unsigned int seed = 131; /* 31 131 1313 13131 131313 etc.. */ unsigned int hash = 0; unsigned int i = 0; for(i = 0; i < len; str++, i++) { hash = (hash * seed) + (*str); } return hash;}/* End Of BKDR Hash Function */unsigned int SDBMHash(const char* str, unsigned int len){ unsigned int hash = 0; unsigned int i = 0; for(i = 0; i < len; str++, i++) { hash = (*str) + (hash << 6) + (hash << 16) - hash; } return hash;}/* End Of SDBM Hash Function */unsigned int DJBHash(const char* str, unsigned int len){ unsigned int hash = 5381; unsigned int i = 0; for(i = 0; i < len; str++, i++) { hash = ((hash << 5) + hash) + (*str); } return hash;}/* End Of DJB Hash Function */unsigned int DEKHash(const char* str, unsigned int len){ unsigned int hash = len; unsigned int i = 0; for(i = 0; i < len; str++, i++) { hash = ((hash << 5) ^ (hash >> 27)) ^ (*str); } return hash;}/* End Of DEK Hash Function */unsigned int BPHash(const char* str, unsigned int len){ unsigned int hash = 0; unsigned int i = 0; for(i = 0; i < len; str++, i++) { hash = hash << 7 ^ (*str); } return hash;}/* End Of BP Hash Function */unsigned int FNVHash(const char* str, unsigned int len){ const unsigned int fnv_prime = 0x811C9DC5; unsigned int hash = 0; unsigned int i = 0; for(i = 0; i < len; str++, i++) { hash *= fnv_prime; hash ^= (*str); } return hash;}/* End Of FNV Hash Function */
数据下载:http://pan.baidu.com/s/1hqBTks0
Github 地址:https://github.com/jihite/Bloom-Filter
5. 扩展
如何删除存储数组中的元素?
思路:把存储数组的每一个元素扩展一下(原来是1b)用来存储该位置被置1的次数。存储是,计数次数加一;删除的时候,计数次数减一。
- 学习笔记-bloom filter
- Bloom filter学习
- Bloom Filter学习资料
- Bloom Filter算法学习
- Bloom Filter一站式学习
- 【学习笔记】Bloom Filter(布隆过滤器)
- 大数据笔记--Bloom Filter
- Bloom Filter
- Bloom Filter
- Bloom Filter
- Bloom Filter
- Bloom Filter
- Bloom Filter
- Bloom Filter
- Bloom Filter
- bloom filter
- bloom filter
- Bloom Filter
- Android系统触屏事件传递派发浅析
- J2EE学习路线图
- jdbc基础 (一) MySQL的简单使用
- OCA、OCP、OCM的了解
- PAT 09-散列3. Hashing - Hard Version (30)
- 学习笔记-bloom filter
- 标准的HTML头部写法
- 使用LevelListDrawable实现Html.fromHtml多张图片显示
- mac系统Command键几个小用法
- bootstrap 登录页面
- iOS 设置UIActionSheet 按钮颜色
- 2.1.16 Plus One
- 从 NSURLConnection 到 NSURLSession
- 不要告诉我你懂margin