其他分享
首页 > 其他分享> > 布隆过滤器

布隆过滤器

作者:互联网

布隆过滤器

定义

原理

在这里插入图片描述

次;也就是不知道被多少个str1哈希映射以及是被哪个hash函数映射过来的;所以不支持删除操作;

储多少元素?另外如何控制假阳率(布隆过滤器能明确一定不存在,不能明确一定存在,那么存在

的判断是有误差的,假阳率就是错误判断存在的概率)?

n -- 布隆过滤器中元素的个数,如上图 只有str1和str2 两个元素 那么 n=2
p -- 假阳率,在0-1之间 0.000000
m -- 位图所占空间
k -- hash函数的个数
公式如下:
n = ceil(m / (-k / log(1 - exp(log(p) / k))))
p = pow(1 - exp(-k / (m / n)), k)
m = ceil((n * log(p)) / log(1 / pow(2, log(2))));
k = round((m / n) * log(2));

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

测试用例

#include <stdio.h>
#include <stdint.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>

//字节大小
#define BYTE_BITS (8)
#define MIX_UINT64(v)       ((uint32_t)((v>>32)^(v)))

//设置位图
#define SETBIT(filter, n)   (filter->pstFilter[n/BYTE_BITS] |= (1 << (n%BYTE_BITS)))

//获取位图
#define GETBIT(filter, n)   (filter->pstFilter[n/BYTE_BITS] & (1 << (n%BYTE_BITS)))
 
typedef struct {
    uint32_t dwMaxItems;                            // n - BloomFilter中最大元素个数 (输入量)
    double dProbFalse;                              // p - 假阳概率 (输入量,比如万分之一:0.00001)
    uint32_t dwFilterBits;                          // m = ceil((n * log(p)) / log(1.0 / (pow(2.0, log(2.0))))); - BloomFilter的比特数,位图所占空间
    uint32_t dwHashFuncs;                           // k = round(log(2.0) * m / n); - 哈希函数个数
 
    uint32_t dwSeed;                                // MurmurHash的种子偏移量
 
    uint32_t dwFilterSize;                          // dwFilterBits / BYTE_BITS
    unsigned char *pstFilter;                       // BloomFilter存储指针,使用malloc分配
 
    uint32_t *pdwHashPos;                           // 存储上次hash得到的K个bit位置数组(由bloom_hash填充)
}BaseBloomFilter;
 
 
 
void _CalcBloomFilterParam(uint32_t n,double p, uint32_t *pm,uint32_t *pk){
    /*
    n -- 布隆过滤器中元素的个数,如上图 只有str1和str2 两个元素 那么 n=2
    p -- 假阳率,在0-1之间 0.000000
    m -- 位图所占空间
    k -- hash函数的个数
    公式如下:
    n = ceil(m / (-k / log(1 - exp(log(p) / k))))
    p = pow(1 - exp(-k / (m / n)), k)
    m = ceil((n * log(p)) / log(1 / pow(2, log(2))));
    k = round((m / n) * log(2));
    */
    uint32_t m, k;
 
    m = (uint32_t) ceil(-1.0 * n * log(p) / 0.480453 );//log以e为底的对数函数
    m = (m - m%64 ) + 64;//8字节对齐
 
    k = (uint32_t) round(0.69314 * m / n);
 
    *pm = m;
    *pk = k;
}
 
int InitBloomFilter(BaseBloomFilter* pstBloomfilter, \
    uint32_t dwSeed, uint32_t dwMaxItems, double dProbFalse){
    
    if(pstBloomfilter == NULL)
        return -1;
    
    if(dProbFalse <=0 || dProbFalse >= 1){
        return -2;
    }
 
    if(pstBloomfilter->pstFilter != NULL){
        free(pstBloomfilter->pstFilter);
    }
    if(pstBloomfilter->pdwHashPos != NULL){
        free(pstBloomfilter->pdwHashPos);
    }
 
    pstBloomfilter->dwMaxItems = dwMaxItems;
    pstBloomfilter->dProbFalse = dProbFalse;
    pstBloomfilter->dwSeed = dwSeed;
 
    _CalcBloomFilterParam(pstBloomfilter->dwMaxItems,pstBloomfilter->dProbFalse,\
                           &pstBloomfilter->dwFilterBits,&pstBloomfilter->dwHashFuncs);
    
 
    pstBloomfilter->dwFilterSize = pstBloomfilter->dwFilterBits / BYTE_BITS;
    pstBloomfilter->pstFilter = (unsigned char *) malloc(pstBloomfilter->dwFilterSize);
    if(NULL == pstBloomfilter->pstFilter){
        return -100;
    }
 
    pstBloomfilter->pdwHashPos = (uint32_t *) malloc(sizeof(uint32_t) * pstBloomfilter->dwHashFuncs);
    if(NULL == pstBloomfilter->pdwHashPos){
        return -200;
    }
 
    printf(">>> Init BloomFilter(n=%u, p=%e, m=%u, k=%d), malloc() size=%.2fMB, items:bits=1:%0.1lf\n",
           pstBloomfilter->dwMaxItems, pstBloomfilter->dProbFalse, pstBloomfilter->dwFilterBits,
           pstBloomfilter->dwHashFuncs, (double)pstBloomfilter->dwFilterSize/1024/1024,
           pstBloomfilter->dwFilterBits*1.0/pstBloomfilter->dwMaxItems);
 
    memset(pstBloomfilter->pstFilter,0,pstBloomfilter->dwFilterSize);
    return 0;
}
 
int FreeBloomFilter(BaseBloomFilter *pstBloomfilter){
    if(pstBloomfilter == NULL){
        return -1;
    }
 
    free(pstBloomfilter->pstFilter);
    pstBloomfilter->pstFilter = NULL;
    free(pstBloomfilter->pdwHashPos);
    pstBloomfilter->pdwHashPos = NULL;
    return 0;
}
 
 
// MurmurHash2, 64-bit versions, by Austin Appleby
// https://sites.google.com/site/murmurhash/
uint64_t MurmurHash2_x64 ( const void * key, int len, uint32_t seed )
{
    const uint64_t m = 0xc6a4a7935bd1e995;
    const int r = 47;
 
    uint64_t h = seed ^ (len * m);
 
    const uint64_t * data = (const uint64_t *)key;
    const uint64_t * end = data + (len/8);
 
    while(data != end)
    {
        uint64_t k = *data++;
 
        k *= m;
        k ^= k >> r;
        k *= m;
 
        h ^= k;
        h *= m;
    }
 
    const uint8_t * data2 = (const uint8_t*)data;
 
    switch(len & 7)
    {
    case 7: h ^= ((uint64_t)data2[6]) << 48;
    case 6: h ^= ((uint64_t)data2[5]) << 40;
    case 5: h ^= ((uint64_t)data2[4]) << 32;
    case 4: h ^= ((uint64_t)data2[3]) << 24;
    case 3: h ^= ((uint64_t)data2[2]) << 16;
    case 2: h ^= ((uint64_t)data2[1]) << 8;
    case 1: h ^= ((uint64_t)data2[0]);
        h *= m;
    };
 
    h ^= h >> r;
    h *= m;
    h ^= h >> r;
 
    return h;
}
 
// 双重散列封装
void bloom_hash(BaseBloomFilter *pstBloomfilter, const void * key, int len)
{
    //if (pstBloomfilter == NULL) return;
    int i;
    uint32_t dwFilterBits = pstBloomfilter->dwFilterBits;
    uint64_t hash1 = MurmurHash2_x64(key, len, pstBloomfilter->dwSeed);
    uint64_t hash2 = MurmurHash2_x64(key, len, MIX_UINT64(hash1));
 
    for (i = 0; i < (int)pstBloomfilter->dwHashFuncs; i++)
    {
        pstBloomfilter->pdwHashPos[i] = (hash1 + i*hash2) % dwFilterBits;
    }
 
    return;
}
 
int BloomFilter_Add(BaseBloomFilter *pstBloomfilter, const void* key,int len){
    if(pstBloomfilter == NULL || key == NULL || len<=0){
        return -1;
    }
 
    bloom_hash(pstBloomfilter,key,len);
    int i;
    for(i=0;i<(int)pstBloomfilter->dwHashFuncs;i++){
        SETBIT(pstBloomfilter,pstBloomfilter->pdwHashPos[i]);
    }
 
    return 0;
}
 
int BloomFilter_Check(BaseBloomFilter *pstBloomfilter, const void* key, int len){
    if(pstBloomfilter == NULL || key == NULL || len<=0){
        return -1;
    }
 
    bloom_hash(pstBloomfilter,key,len);
    int i;
    for(i=0;i<(int)pstBloomfilter->dwHashFuncs;i++){
        if(GETBIT(pstBloomfilter,pstBloomfilter->pdwHashPos[i]) == 0){
            return 1;//没找到
        }
    }
 
    return 0;
}
 
int main(){
    int MAX_ITEMS = 400000;
    int ADD_ITEMS = 1000;
    double P_ERROR = 0.0000001;
    BaseBloomFilter stBloomfilter = {0};
    InitBloomFilter(&stBloomfilter,0,MAX_ITEMS,P_ERROR);
 
    char url[128] = {0};
    int i;
    for(i=0;i<ADD_ITEMS;i++){
        sprintf(url,"https://0voice.com/%d.html", i);
        BloomFilter_Add(&stBloomfilter,url,strlen(url));
    }
 
    printf("0 exist, 1 not exist\n");
    sprintf(url,"https://0voice.com/%d.html",0);
    printf("%s exist %d\n",url,BloomFilter_Check(&stBloomfilter,url,strlen(url)));
 
    sprintf(url,"https://0voice.com/%d.html",ADD_ITEMS);
    printf("%s exist %d\n",url,BloomFilter_Check(&stBloomfilter,url,strlen(url)));

    return 0;
}

标签:hash,log,int,布隆,pstBloomfilter,过滤器,return,uint32
来源: https://blog.csdn.net/w451062810/article/details/123070141