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

布隆过滤器

时间:2022-12-03 22:22:35浏览次数:60  
标签:函数 元素 布隆 filter 哈希 过滤器

布隆过滤器

介绍

布隆过滤器(Bloom Filter)是1970年由布隆提出的

它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中

优点:

  • 可以高效地进行查询,可以用来告诉你“某样东西一定不存在或者可能存在”
  • 可以高效的进行插入
  • 相比于传统的List、Set、Map等数据结构,它占用空间更少,因为其本身并不存储任何数据(重点)

缺点:

  • 其返回的结果是概率性(存在误差)的
  • 一般不提供删除操作
  • 布隆过滤器一般使用在数据量特别大的场景下,一般不会使用

用的使用场景:

  • 使用word文档时,判断某个单词是否拼写正确。例如我们在编写word时,某个单词错误那么就会在单词下显示红色波浪线
  • 网络爬虫程序,不去爬相同的url页面
  • 垃圾邮件的过滤算法
  • 缓存崩溃后造成的缓存击穿
  • 集合重复元素的判别
  • 查询加速(比如基于key-value的存储系统,如redis等)

原理

布隆过滤器是一个bit向量或者说是一个bit数组(下面的数字为索引):

在这里插入图片描述

为什么布隆过滤器要使用多个Hash函数?

  • Hash面临的问题就是冲突。假设Hash函数是良好的,如果我们的位阵列长度为\(m\)个点,那么如果我们想将冲突率降低到例如 \(1%\),这个散列表就只能容纳 \(m/100\)个元素
  • 解决方法较简单,使用\(K>1\)的布隆过滤器,即\(K\)个函数将每个元素改为对应于\(K\)个bits,因为误判度会降低很多,并且如果参数\(K\)和\(m\)选取得好,一半的\(m\)可被置为1

假设我们的布隆过滤器有三个哈希函数,分别名为hash1、hash2、hash3,主要流程如下:

1、初始化

image-20221203155233958

针对于“baidu”这个元素,我们调用三个哈希函数,将其映射到bit向量的三个位置(分别为1、4、7),并且将对应的位置置为1

img

2、插入

image-20221203155258496

现在针对于“tencent”这个元素,我们也调用三个哈希函数,将其映射到bit向量的三个位置(分别为3、4、8),并且将对应的位置置为1

img

此时,整个bit向量的1、3、4、7、8这几个位置被置为1了。其中4这个索引被覆盖了,因为“baidu”和“tencent”都将其置为1,覆盖的索引与误判率有关

3、查找

image-20221203155409460

  • 去查询一个不存在的元素,并且确定其肯定不存在:例如现在我们去查询“dongshao”这个元素,假设调用上面的三个哈希函数返回的索引是1、5、8,通过上图我们知道5这个索引处为0,因此“dongshao”这个元素一定不存在,因为如果存在的话,那么5这个位置应该被置为1才对。
  • 去查询“baidu”这个元素,不能判断其百分百存在:我们将“baidu”传入上面的三个哈希函数中,哈希返回的对应索引值为1、4、7,发现1、4、7这几个索引处都为1,因此我们判断“baidu”这个元素可能存在。

误判率(假阳率)

  • 布隆过滤器允许存在一定的误判断,误判率也称为“假阳”。
  • 误判率一般是出现在查询的时候

例如上面我们去查询“baidu”的时候,由于“baidu”之前被我们插入过,为什么还不能百分百确定它一定存在呢?

  • 因为“tencent”这个元素在插入的时候,将4这个索引置为1了。
  • 假设我们查询“baidu”的时候实际返回的是1、7索引为1,4索引为0。而4索引又被tencent覆盖为1,所以最终“baidu”最终看到的是1、4、7索引都为1,不能百分百确定“baidu”这个元素存在

因此,当随着增加的值越来越多时,bit向量被置为1的数量也就会越来越多,因此误判率会越来越大。例如,当查询“taobao”时,万一所有的哈希函数返回的对应bit都为1,那么布隆过滤器可能也认为“taobao”这个元素存在。

那如何控制误判率?

  • 哈希函数越多、插入元素越少,误判率越低
  • 满足\(m=\frac{w k}{\ln ^2 2}\)条件,则误判率最低!

\(k\):哈希函数个数;\(w\):带插入元素个数;\(m\):BF数组的长度。

\(n\):布隆过滤器最大处理的元素的个数;\(P\):希望的误差率;\(m\):布隆过滤器的bit位数目;\(k\):哈希函数的个数

代码实现

1、python简单实现

这里的哈希函数是简单定义的

import math
import random
import time

def hash_function(a, b, c, item, tablelen):
    return (a * item ** 2 + b * item + c) % tablelen  #哈希函数

def construction_of_SBF(tablelen = 1000, set = []):

    k = int(math.log(2, math.e) * (tablelen / len(set))) #哈希函数的个数
    print("k=",k)
    hash = []
    random.seed(time.time())
    for i in range(k):  #随机生成哈希函数的三个参数
        a = random.randint(1, 1000)
        b = random.randint(1, 1000)
        c = random.randint(1, 1000)
        hash.append((a, b, c))

    bitArray = [0] * tablelen   #BF数组

    for element in set:     #映射集合元素到位数组
        for i in range(k):
            hx = hash_function(hash[i][0], hash[i][1], hash[i][2], element, tablelen)
            bitArray[hx] = 1

    print("BF=",bitArray)
    filter = [bitArray, hash]
    return filter

# 测试
def test_bloom_filters(bloom_filter = None):
    if bloom_filter == None:
        return False

    testSet = [1, 3, 7, 11, 9, 5, 4, 67, 81]
    for item in testSet:
        flag = True
        for i in range(len(filter[1])):
            hx = hash_function(filter[1][i][0], filter[1][i][1], filter[1][i][2], item, len(filter[0]))
            if bloom_filter[0][hx] != 1:
                flag = False
                break

        if flag is True:
            print("%d is in filter\n" % item)
        else:
            print("%d is not in filter\n" % item)

    return True


if __name__ == "__main__":
    filter = construction_of_SBF(set = list(range(10)))
    test_bloom_filters(filter)

2、C++实现

这里哈希函数使用的是MurmurHash2算法,输出64位哈希值

#include "bloomfilter.h"
 
#define MAX_ITEMS 6000000      // 设置最大元素个数,BF容量
#define ADD_ITEMS 1000      // 添加测试元素
#define P_ERROR 0.0001// 设置误差
 
//
int main(int argc, char** argv)
{
 
    printf(" test bloomfilter\n");
 
    // 1. 定义BaseBloomFilter
    static BaseBloomFilter stBloomFilter = {0};
 
    // 2. 初始化stBloomFilter,调用时传入hash种子,存储容量,以及允许的误判率
    InitBloomFilter(&stBloomFilter, 0, MAX_ITEMS, P_ERROR);
 
    // 3. 向BloomFilter中新增数值
    char url[128] = {0};
    for(int i = 0; i < ADD_ITEMS; i++){
        sprintf(url, "https://blog.csdn.net/qq_41453285/%d.html", i);
        if(0 == BloomFilter_Add(&stBloomFilter, (const void*)url, strlen(url))){
            printf("add %s success\n", url);
        }else{
            printf("add %s failed\n", url);
        }
        memset(url, 0, sizeof(url));
    }
 
    // 4. check url exist or not
    char* str = "https://blog.csdn.net/qq_41453285/0.html";
    if (0 == BloomFilter_Check(&stBloomFilter, (const void*)str, strlen(str)) ){
        printf("https://blog.csdn.net/qq_41453285/0.html exist\n");
    }
 
    char* str2 = "https://blog.csdn.net/qq_41453285/10001.html";
    if (0 != BloomFilter_Check(&stBloomFilter, (const void*)str2, strlen(str2)) ){
          printf("https://blog.csdn.net/qq_41453285/10001.html not exist\n");
    }
 
    // 5. free bloomfilter
    FreeBloomFilter(&stBloomFilter);
    return 0;
}

参考

1、https://blog.csdn.net/qq_40989769/article/details/126781815

2、https://www.cnblogs.com/ciel717/p/16179892.html

标签:函数,元素,布隆,filter,哈希,过滤器
From: https://www.cnblogs.com/pam-sh/p/16948920.html

相关文章

  • Vue2(笔记15) - Vue核心 - 过滤器
    可学可不学,可用可不用过滤器需求:把一个时间戳格式化成可读的年月日时间;需要引入一个dayjs 的 JS库,专门用来处理时间的;​​dayjs在这可以下载​​<scriptsrc="./res/vue.......
  • ASP .NET Core Api使用过滤器
    Asp.netwebapi为我们提供的ActionFilterAttribute拦截器,通过重写OnActionExecuting,来拦截action的请求消息,当执行OnActionExecuting完成以后才真正进入请求的action......
  • Vue的指令与过滤器
    1.内容渲染指令v-text覆盖标签原有内容{{}}插值表达式v-html2.属性绑定指令v-bind为属性动态绑定值简写':'3.事件绑定指令v-on简写'@'vue提供了内置......
  • spring mvc环境之监听器、过滤器、拦截器(六)
    1.监听器Servlet的监听器Listener,它是实现了javax.servlet.ServletContextListener接口的服务器端程序,它也是随web应用的启动而启动,只初始化一次,随web应用的停止而销毁。......
  • SpringBoot过滤器工具类解决跨域问题模板
    放入目录config即可@ConfigurationpublicclassCorsConfigimplementsFilter{@OverridepublicvoiddoFilter(ServletRequestreq,ServletResponseres,F......
  • Spring Boot中使用Filter过滤器
    Filter过滤器一、引入在和管理员有关的Controller中,接口都需要判断当前用户是否为管理员,如果是管理员,则可以操作目录;如果不是管理员,则不能操作;这一连串的身份验证代码都......
  • day27-过滤器Filter02
    Filter过滤器025.Filter过滤器生命周期Filter生命周期图解验证-Tomcat来创建Filter实例,只会创建一个实例packagecom.filter;importjavax.servlet.*;importj......
  • spring mvc 环境 过滤器设置utf8字符编码和配置Logback日志及json支持(四)
    web.xml配置过滤器支持中文的请求和响应<filter><filter-name>characterEncodingFilter</filter-name><filter-class>org.springframework.web.filter.Char......
  • day26-过滤器Filter
    Filter过滤器1.Filter过滤器说明为什么需要过滤器?先来看一个例子:我们在登录网站页面时,需要先进行登录验证。用户访问的正常的流程应该是:用户先通过登录页面进......
  • spring mvc环境过滤器请求响应编码和maven编译等设置(二)
    springmvc环境通过过滤器设置请求响应字符编码1.web.xml配置过滤器进行字符编码设置<filter><filter-name>characterEncodingFilter</filter-name><filt......