图+代码 | Bloom Filter实现及应用

news2024/9/25 13:25:47

什么是布隆过滤器(Bloom Filter)?

布隆过滤器是一种空间复杂度很低的概率型数据结构,用于判断一个元素是否在一个集合中。它有两种可能的返回结果:

  • 元素可能在集合中:这可能是一个真阳性(确实在集合中)或假阳性(实际上不在集合中)。
  • 元素肯定不在集合中:这是一个真阴性。

简单来说,布隆过滤器能告诉你一个元素可能存在或肯定不存在。它非常节省内存,但有一定概率会给出错误的“存在”结果(即假阳性)。

布隆过滤器是如何工作的?

假设我们要比较两个字符串是否相同,我们不会存储整个字符串,而是计算出这些字符串的哈希值,然后比较哈希值即可,如果两个哈希值不相等,可以肯定这2个字符串不相同,否则这两个字符串可能相同

但是,有一个问题:哈希函数的值域是有限的,比如它可能只能生成 0 到 999 之间的数值。这意味着不同的字符串可能会生成相同的哈希值,这种情况叫做 哈希冲突。因此,仅仅依赖一个哈希值来判断字符串相等是有风险的。

为了降低这种冲突带来的风险,我们可以使用 多个哈希函数。即对同一个字符串使用不同的哈希函数,得到多个哈希值。如果两个字符串的所有哈希值都相同,那么它们很有可能相等;如果其中任何一个哈希值不同,我们就可以确定字符串不同。

布隆过滤器是一种使用多个哈希函数的具体应用,它用来判断一个元素是否在一个集合中。

布隆过滤器是一个只包含 0 和 1 的位数组,每个位置代表一个比特(bit)。当你插入一个元素时,你用多个哈希函数计算它们的位置,并将位数组这些位置上的比特设置为 1。如果你想检查一个元素是否在集合中,同样对待检查元素用多个哈希函数计算它们的位置,然后只需检查位数组这些位置是否全都是 1。只要有一个位置是 0,那么这个元素一定不在集合中。

将元素插入到布隆过滤器

假设我们要将字符串 “coding” 插入布隆过滤器。首先,我们使用多个哈希函数对这个字符串进行哈希运算,得到不同的哈希值。例如,我们这里使用三个不同的哈希函数:

  • h1(“coding”) = 125
  • h2(“coding”) = 67
  • h3(“coding”) = 19

现在,我们假设布隆过滤器的大小是 10,即我们有一个长度为 10 的位数组。我们需要将哈希值对 10 取模以确保索引在布隆过滤器的位数组范围 0 到 9 之间:

  • 125 % 10 = 5
  • 67 % 10 = 7
  • 19 % 10 = 9
    于是,我们在位数组的索引 5、7 和 9 处设为1。

同样,我们可以将"music"这个字符串也添加到布隆过滤器中:

  • h1(“music”) = 290
  • h2(“music”) = 145
  • h3(“music”) = 2

对 10 取模:

  • 290 % 10 = 0
  • 145 % 10 = 5
  • 2 % 10 = 2

添加了2个字符串的布隆过滤器如下:

其中,索引为5的位置为 1 是 这两个单词都做了贡献。

查询一个元素是否存在

如果我们想查询一个元素是否存在于布隆过滤器中,我们将待查询的元素使用相同的哈希函数然后对位数组大小求模,然后判断对应位数组的索引位是否都设置为1,如果都为1,则该元素可能存在布隆过滤器中,只要有一个索引位为0,我们就能肯定该元素不存在布隆过滤器中。

100%不存在的案例

现在假设我们想查询 “cat” 是否在布隆过滤器中。我们同样使用相同的哈希函数对"cat"进行哈希运算,得到:

  • h1(“cat”) = 233 % 10 = 3
  • h2(“cat”) = 155 % 10 = 5
  • h3(“cat”) = 9 % 10 = 9

然后,我们检查位数组索引 3、5 和 9。如果这些索引中的所有位都为1,则表示 “cat” 可能存在。但如果其中任何一位是0,那么我们可以确定 “cat” 不在集合中。

我们可以看到,尽管位数组索引5和9的位为1,但是 索引3处是0,因此我们可以100%肯定"cat"不在集合中。

可能存在的案例

现在假设我们想查看"gaming"是否存在,我们将“gaming”这个元素通过相同的哈希函数(h1、h2、h3)得到了以下结果:

  • h1(“gaming”) = 235 % 10 = 5
  • h2(“gaming”) = 60 % 10 = 0
  • h3(“gaming”) = 22 % 10 = 2

然后,我们检查位数组处索引 0、2 和 5是否都被设置为1。我们看到这些索引都已经被设置为1。然而,我们知道“gaming”实际上并不在集合中,所以这是一个误报(False Positive)。

如何预测误报的概率?

我们可以通过数学公式来预测误报的概率。以下是一些符号的定义:

  • n:插入到Bloom过滤器中的元素数量。
  • m:Bloom过滤器的长度(位数组的大小)。
  • k:哈希函数的数量。

可以看出,当m趋向于无穷大时,误报率趋向于零。另一种减少误报率的方法是使用多个哈希函数。

布隆过滤器的实现示例

以下是一个简单的 Python 实现:

import mmh3  # MurmurHash 3,常用于布隆过滤器
import math

class BloomFilter:
    def __init__(self, m, k):
        self.m = m  # 布隆过滤器的大小(位数组的长度)
        self.k = k  # 哈希函数的数量
        self.n = 0  # 插入的元素数量
        self.bloomFilter = [0] * self.m  # 初始化位数组为0
        
    def getBitArrayIndices(self, item):
        """
        计算 item 的哈希值并返回需要设置的位数组索引列表
        """
        indexList = []
        for i in range(1, self.k + 1):
            indexList.append((hash(item) + i * mmh3.hash(item)) % self.m)
        return indexList
        
    def add(self, item):
        """
        插入一个元素到布隆过滤器
        """
        for i in self.getBitArrayIndices(item):
            self.bloomFilter[i] = 1
        self.n += 1
    
    def contains(self, key):
        """
        检查元素是否在布隆过滤器中
        """
        for i in self.getBitArrayIndices(key):
            if self.bloomFilter[i] != 1:
                return False
        return True
        
    def generateStats(self):
        """
        计算布隆过滤器的统计信息,比如错误率
        """
        n = float(self.n)
        m = float(self.m)
        k = float(self.k)
        probability_fp = math.pow((1.0 - math.exp(-(k*n)/m)), k)

        print("元素数量: ", n)
        print("布隆过滤器大小: ", m)
        print("哈希函数数量: ", k)
        print("假阳性概率: ", probability_fp)
        print("假阳性率: ", probability_fp * 100.0, "%")

对应的 Java代码如下:

import java.util.BitSet;
import java.util.Random;

public class BloomFilter {

    private int m;  // Bloom filter 的大小
    private int k;  // 哈希函数的数量
    private int n;  // 插入的元素数量
    private BitSet bloomFilter;
    private Random[] hashFunctions;

    public BloomFilter(int m, int k) {
        this.m = m;
        this.k = k;
        this.n = 0;
        this.bloomFilter = new BitSet(m);
        this.hashFunctions = new Random[k];
        for (int i = 0; i < k; i++) {
            this.hashFunctions[i] = new Random(i);
        }
    }

    private int[] getBitArrayIndices(String item) {
        int[] indexList = new int[k];
        for (int i = 0; i < k; i++) {
            indexList[i] = Math.abs(hashFunctions[i].nextInt(item.hashCode())) % m;
        }
        return indexList;
    }

    public void add(String item) {
        int[] indices = getBitArrayIndices(item);
        for (int index : indices) {
            bloomFilter.set(index);
        }
        n++;
    }

    public boolean contains(String key) {
        int[] indices = getBitArrayIndices(key);
        for (int index : indices) {
            if (!bloomFilter.get(index)) {
                return false;
            }
        }
        return true;
    }

    public int length() {
        return n;
    }

    public void generateStats() {
        double n = (double) this.n;
        double m = (double) this.m;
        double k = (double) this.k;
        double probability_fp = Math.pow((1.0 - Math.exp(-(k * n) / m)), k);

        System.out.println("Number of elements entered in filter: " + n);
        System.out.println("Number of bits in filter: " + m);
        System.out.println("Number of hash functions used: " + k);
        System.out.println("Predicted Probability of false positives: " + probability_fp);
        System.out.println("Predicted false positive rate: " + (probability_fp * 100.0) + "%");
    }

    public void reset() {
        this.n = 0;
        this.bloomFilter.clear();
    }

    public static void main(String[] args) {
        BloomFilter bloomFilter = new BloomFilter(10, 3);
        bloomFilter.add("coding");
        bloomFilter.add("music");
        System.out.println(bloomFilter.contains("gaming")); // 输出 false(有可能是误报)
        bloomFilter.generateStats();
    }
}

布隆过滤器的应用场景

数据库查询的第一层过滤

在查询大型数据库时,可以先使用布隆过滤器。如果布隆过滤器判断某个元素不存在,则可以避免昂贵的数据库查询操作。例如缓存穿透就可以用布隆过滤器解决。

推荐系统

某些社交网站使用布隆过滤器来避免向用户推荐他们已经看过的文章。

总结

布隆过滤器是一种设计用来快速、节省内存地判断元素是否在集合中的数据结构。它的特点是有可能出现“假阳性”——即报告某个元素存在,而实际上不存在。但布隆过滤器的内存占用非常小,并且操作速度很快,适用于需要快速判断元素是否存在并且允许一定误差的场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1981450.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用Variadic Templates(可变参数模板)实现printf

最近学习了C2.0版本的一些新的特性&#xff0c;利用Variadic Templates&#xff08;可变参数模板&#xff09;实现printf函数。 语言环境 Dev-C 5.11 并需要自己的环境是支持C11的&#xff0c;例如:Dev-C 5.11可以通过以下步骤进行修改&#xff1a; 源码 #include <io…

编程与AI:保持竞争力的策略

人工智能时代&#xff0c;程序员如何保持核心竞争力&#xff1f; 随着AIGC&#xff08;如chatgpt、midjourney、claude等&#xff09;大语言模型接二连三的涌现&#xff0c;AI辅助编程工具日益普及&#xff0c;程序员的工作方式正在发生深刻变革。有人担心AI可能取代部分编程工…

顶刊、顶会、水刊的论文读哪个,如何做一个称职的学术裁缝_来自B站水论文的程序猿

系列文章目录 文章目录 系列文章目录一、顶刊、顶会要看二、水刊&#xff1a;SCI4区&#xff0c;部分3区 看水刊&#xff0c;发现新大陆1、数据集2、性能3、复现 三、如何做一个称职的学术裁缝1、缝合2、编故事 一、顶刊、顶会要看 通过顶刊、顶会知道好的东西长什么样子即可&…

【从零开始一步步学习VSOA开发】创建VSOA的client端

创建VSOA的client端 创建工程 参考 hellovsoa 工程&#xff0c;创建 client 工程&#xff0c;工程源码修改如下&#xff1a; #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/select.h> #include "vsoa_client.h&q…

全球情绪检测与识别市场规划预测:2030年市场规模将接近3166亿元,未来六年CAGR为22.6%

一、引言 随着人工智能和机器学习技术的飞速发展&#xff0c;情绪检测与识别在多个领域的应用日益广泛&#xff0c;其市场潜力日益凸显。本文旨在探索情绪检测与识别行业的发展趋势、潜在商机及其未来展望。 二、市场趋势 全球情绪检测与识别市场的增长主要受人工智能和机器学…

【mathtype】word中如何输入4×4的矩阵,甚至阶数更多

在写论文或者使用word操作的时候&#xff0c;我们可能会使用矩阵插入我们所写的word中&#xff0c;今天小编就分享一下如何在word中输入矩阵。首先&#xff0c;我们word中需要安装mathtype的插件。 ①打开word&#xff0c;鼠标点击mathtype&#xff0c;再点击内联 ② 出现以下…

C++学习记录

C学习 1.const,mutable,初始化列表,this指针2.static使用类友元作用友元全局函数友元类友元成员函数 运算符重载左移运算符 <<下标运算符赋值运算符括号运算符一元运算符 自动类型转换隐式类型转换 转换函数 继承继承方式构造函数继承名字遮蔽和类作用域名字覆盖类作用域…

大气能见度测量仪的功能优势:安心守护

大气能见度是衡量空气质量与交通安全的重要指标之一&#xff0c;它直接关系到人们的出行安全、航空航行的顺畅以及环境监测的准确性。为此&#xff0c;大气能见度测量仪应运而生&#xff0c;以其独特的功能优势&#xff0c;成为现代气象观测与交通管理中不可或缺的高科技设备。…

数据资源:机遇与挑战并存的新时代

数据资源&#xff1a;机遇与挑战并存的新时代 2023年全国数据生产总量达到32.85泽字节&#xff08;ZB&#xff09;&#xff0c;同比增长22.44%&#xff0c;数据生产规模持续扩大&#xff0c;其中非结构数据增长尤为突出&#xff0c;这得益于5G、AI技术的发展和智能设备的应用。…

ME31K-创建合同

ME31K创建合同 合同分为&#xff1a;数量合同和价值合同 CMK代表数量合同。CWK代表价值合同。 输入对应数量或价值后&#xff0c;点击保存。 点击保存后。系统会带出一个合同号。 可以引用这个合同号&#xff0c;去创建采购订单或者计划协议。

【从零开始一步步学习VSOA开发】创建VSOA的server端

创建VSOA的server端 创建工程 参考 hellovsoa 工程&#xff0c;创建 server 工程&#xff0c;工程源码修改如下&#xff1a; #include <stdio.h> #include <stdlib.h> #include <string.h> #include <netinet/in.h> #include <arpa/inet.h> #…

zabbix7.0TLS-02-客户端zabbix-agent部署和配置

文章目录 1 介绍2 工作模式2 部署2.1 RPM 包方式部署 3 配置3.1 配置文件位置3.2 主配置文件布局3.2.1 常规参数3.2.2 高级参数 3.3 部分配置参数详解3.3.1 通用参数3.3.2 被动模式参数3.3.3 主动模式参数 4 测试4.1 Agent 本机测试4.2 在服务端 Zabbix-server 测试和 Agent 的…

Opengl 安装

安装Cmake&#xff1a;Download CMake 安装GLFW&#xff08;source package&#xff09;:An OpenGL library | GLFW glad.dav1d.de 下载glad&#xff0c;选择version3.3 Core --Generate生成。然后点击glad.zip文件下载。 在cmake配置glfw&#xff1a;config-generate 构建GLF…

场外个股期权也可以随时平仓?场外期权行权是什么时候?

今天带你了解场外个股期权也可以随时平仓&#xff1f;场外期权行权是什么时候&#xff1f;A股场外个股有期权&#xff0c;主要对应的标的是沪深交易所上市的个股&#xff0c;除了st、次新股等受到限制&#xff0c;90%的股票都可以购买。 场外个股期权是否可以随时平仓 场外个…

MySQL数据库管理系统在Linux上安装部署

1. MySQL 5.7版本安装 1.1 安装 &#xff08;1&#xff09; 配置yum仓库 # 更新密钥 rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022 # 安装Mysql yum库 rpm -Uvh http://repo.mysql.com/mysql57-community-release-el7-7.noarch.rpm 注意&#xff1a; 由于M…

OpenCV及rembg去除图像背景

OpenCV去除图像背景 去除图像背景&#xff0c;需要综合使用二值化&#xff08;thresholding&#xff09;、腐蚀&#xff08;erosion&#xff09;、膨胀&#xff08;dilation&#xff09;以及位运算&#xff08;bitwise operations&#xff09;&#xff0c;代码如下&#xff1a…

【独家原创RIME-CNN-LSSVM】基于霜冰优化算法优化卷积神经网络(CNN)结合最小二乘向量机(LSSVM)的数据回归预测

【独家原创RIME-CNN-LSSVM】基于霜冰优化算法优化卷积神经网络(CNN)结合最小二乘向量机(LSSVM)的数据回归预测 目录 【独家原创RIME-CNN-LSSVM】基于霜冰优化算法优化卷积神经网络(CNN)结合最小二乘向量机(LSSVM)的数据回归预测效果一览基本介绍程序设计参考资料 效果一览 基本…

成品油综合监管云平台:系统功能全方位解析

成品油综合监管云平台&#xff0c;作为集数据收集、统计分析、监管、预警应急安全等功能于一体的信息化监管系统&#xff0c;正逐步成为政府监管部门提升管理效率、保障市场秩序的重要工具。 本文将详细解析成品油综合监管云平台的多项核心功能&#xff0c;展现其在现代成品油…

习题2.31

先上代码 (defn square [x](* x x)) (defn square-tree[tree](tree-map square tree) )(defn tree-map [op tree](cond (not (seq? tree)) (op tree)(empty? tree) nil:else (cons (tree-map op (first tree)) (tree-map op (rest tree)))) )题目实际上是想让我们将树的遍历…

【网络】|wireshark

1、wireshark 1.12的使用 参考: https://blog.csdn.net/xb_zed/article/details/116305363 重点&#xff1a; 1.1 设置混杂模式