【算法】布隆过滤器

一、引言

        在现实世界的计算机科学问题中,我们经常需要判断一个元素是否属于一个集合。传统的做法是使用哈希表或者直接遍历集合,但这些方法在数据量较大时效率低下。布隆过滤器(Bloom Filter)是一种空间效率极高的概率型数据结构,用于测试一个元素是否属于集合。本文将详细介绍布隆过滤器的原理、数据结构、使用场景、算法实现,并与其他算法进行对比,最后给出多语言实现及一个实际的服务应用场景代码框架。

二、算法原理

        布隆过滤器由一个很长的二进制向量和一系列随机映射函数组成。当我们要添加一个元素时,该元素会被多个哈希函数映射到二进制向量的不同位置,并将这些位置设为1。查询时,通过同样的哈希函数计算位置,如果所有对应的位置都是1,则该元素可能存在于集合中;如果有任何一个位置是0,则该元素一定不存在于集合中。

        布隆过滤器由一个比特数组(Bit Array)和多个哈希函数组成。

        初始时,所有的比特位都被置为 0。

        当元素被加入时,通过多个哈希函数计算出多个哈希值,然后将对应的比特位设置为 1。

        当查询一个元素是否存在时,同样通过多个哈希函数计算出哈希值,检查对应的比特位,如果所有对应的比特位都为 1,则该元素可能存在;如果有任何一个比特位为 0,则该元素一定不存在。

三、数据结构

布隆过滤器主要包含以下部分:

        一个大的位数组(bit array)。

        一组哈希函数。

四、使用场景

布隆过滤器适用于以下场景:

        网络爬虫过滤已抓取的URL。

        防止缓存穿透,如数据库查询缓存。

        查询重复元素,如邮件系统过滤重复邮件。

        空间敏感:当元素集合非常大,但只关心是否存在时。

        允许误报:当系统可以容忍少量错误判断时。

        快速查找:需要快速判断元素是否在集合中时。

五、算法实现

以下是布隆过滤器的简单实现步骤:

        初始化一个长度为m的位数组,并设置所有位为0。

        选择k个不同的哈希函数,它们将元素映射到位数组的位置。

        添加元素:对元素进行k次哈希,将得到的k个位置设为1。

        查询元素:对元素进行k次哈希,检查所有对应位置是否为1。

六、其他同类算法对比

        哈希表:精确匹配,空间占用大。

        位图(Bitmap):只能处理整数集合,不支持哈希函数。

        Cuckoo Filter:支持删除操作,空间利用率更高。

        后缀数组:适用于字符串搜索,空间和时间效率较高,但实现复杂。

        Trie树:适用于字符串集合,空间效率较高,但存在空间浪费。

七、多语言实现

布隆过滤器的伪代码实现:

java

// Java
public class BloomFilter {private BitSet bitSet;private int bitSetSize;private int addedElements;private static final int[] SEEDS = new int[]{5, 7, 11, 13, 31};public BloomFilter(int bitSetSize) {this.bitSetSize = bitSetSize;this.bitSet = new BitSet(bitSetSize);this.addedElements = 0;}public void add(String element) {for (int seed : SEEDS) {int hash = hash(element, seed);bitSet.set(hash);}addedElements++;}public boolean contains(String element) {for (int seed : SEEDS) {int hash = hash(element, seed);if (!bitSet.get(hash)) {return false;}}return true;}private int hash(String element, int seed) {// Implement a simple hash function}
}

python

# Python
class BloomFilter:def __init__(self, bit_array_size, hash_functions):self.bit_array = [0] * bit_array_sizeself.hash_functions = hash_functionsdef add(self, element):for hash_function in self.hash_functions:index = hash_function(element)self.bit_array[index] = 1def contains(self, element):return all(self.bit_array[hash_function(element)] for hash_function in self.hash_functions)# Example hash functions
def hash_function_1(element):# Implement a simple hash functiondef hash_function_2(element):# Implement another simple hash function

c++

// C++
#include <vector>
#include <functional>class BloomFilter {
private:std::vector<bool> bit_array;std::vector<std::function<size_t(const std::string&)>> hash_functions;public:BloomFilter(size_t size, const std::vector<std::function<size_t(const std::string&)>>& funcs): bit_array(size, false), hash_functions(funcs) {}void add(const std::string& element) {for (const auto& func : hash_functions) {size_t index = func(element) % bit_array.size();bit_array[index] = true;}}bool contains(const std::string& element) const {for (const auto& func : hash_functions) {size_t index = func(element) % bit_array.size();if (!bit_array[index]) {return false;}}return true;}
};

Go

package mainimport ("fmt""github.com/willf/bloom"
)func main() {filter := bloom.New(1000, 5) // 1000 items, 5 hash functions// Add items to the filterfilter.Add([]byte("hello"))filter.Add([]byte("world"))// Test if items are in the filterif filter.Test([]byte("hello")) {fmt.Println("hello is in the filter")}if !filter.Test([]byte("missing")) {fmt.Println("missing is not in the filter")}
}

八、实际服务应用场景代码框架

使用布隆过滤器来防止缓存穿透的简单服务应用场景代码框架:

java

// Java - Cache Service with Bloom Filter
public class CacheService {private final BloomFilter<String> bloomFilter;private final Map<String, String> cache;public CacheService(int cacheSize, int bloomFilterSize) {this.cache = new HashMap<>(cacheSize);this.bloomFilter = new BloomFilter<>(bloomFilterSize);}public String get(String key) {if (!bloomFilter.contains(key)) {// The key is definitely not in the cachereturn null;}// The key might be in the cache, check the actual cachereturn cache.get(key);}public void put(String key, String value) {bloomFilter.add(key);cache.put(key, value);}
}

python

# Python - Cache Service with Bloom Filter
class CacheService:def __init__(self, cache_size, bloom_filter_size):self.cache = {}self.bloom_filter = BloomFilter(bloom_filter_size, [hash_function_1, hash_function_2])def get(self, key):if not self.bloom_filter.contains(key):# The key is definitely not in the cachereturn None# The key might be in the cache, check the actual cachereturn self.cache.get(key)def put(self, key, value):self.bloom_filter.add(key)self.cache[key] = value# Define hash functions
def hash_function_1(element):# Implement a simple hash functiondef hash_function_2(element):# Implement another simple hash function

c++

// C++ - Cache Service with Bloom Filter
#include <unordered_map>
#include <string>class CacheService {
private:BloomFilter bloomFilter;std::unordered_map<std::string, std::string> cache;public:CacheService(size_t bloomFilterSize, const std::vector<std::function<size_t(const std::string&)>>& hashFuncs): bloomFilter(bloomFilterSize, hashFuncs) {}std::string get(const std::string& key) {if (!bloomFilter.contains(key)) {// The key is definitely not in the cachereturn "";}// The key might be in the cache, check the actual cachereturn cache[key];}void put(const std::string& key, const std::string& value) {bloomFilter.add(key);cache[key] = value;}
};

go

// Go - Cache Service with Bloom Filter
package mainimport ("fmt""github.com/willf/bloom"
)type CacheService struct {bloomFilter *bloom.BloomFiltercache       map[string]string
}func NewCacheService(bloomFilterSize int, cacheSize int) *CacheService {return &CacheService{bloomFilter: bloom.New(bloomFilterSize, 5),cache:       make(map[string]string, cacheSize),}
}func (s *CacheService) Get(key string) (string, bool) {if !s.bloomFilter.Test([]byte(key)) {// The key is definitely not in the cachereturn "", false}// The key might be in the cache, check the actual cachevalue, exists := s.cache[key]return value, exists
}func (s *CacheService) Put(key, value string) {s.bloomFilter.Add([]byte(key))s.cache[key] = value
}func main() {service := NewCacheService(1000, 100)service.Put("hello", "world")if value, exists := service.Get("hello"); exists {fmt.Println("Found in cache:", value)}
}

布隆过滤器在 HBase 中的使用:

在 HBase 中,布隆过滤器主要用于以下两个场景:

行键查找(Get 操作):当客户端发起一个 Get 操作来查询特定的行键时,布隆过滤器可以快速判断该行键是否存在于某个 HFile 中,从而避免不必要的磁盘 I/O。

范围扫描(Scan 操作):当客户端执行一个 Scan 操作来检索一定范围内的行键时,布隆过滤器可以帮助跳过那些肯定不包含目标行键的 HFile,减少扫描的数据量。

HBase 支持以下几种布隆过滤器:

  • NONE:不使用布隆过滤器。
  • ROW:对行键使用布隆过滤器。
  • ROWCOL:对行键加列族:列限定符的组合使用布隆过滤器。
  • PREFIX:对行键的前缀使用布隆过滤器。

在 HBase 中配置布隆过滤器、布隆过滤器的配置可以在表级别进行,具体操作如下:

创建表时配置

// Java 代码示例
Configuration config = HBaseConfiguration.create();
HTableDescriptor tableDescriptor = new HTableDescriptor(TableName.valueOf(tableName));
HColumnDescriptor columnDescriptor = new HColumnDescriptor(familyName);// 设置布隆过滤器类型为 ROW
columnDescriptor.setBloomFilterType(BloomType.ROW);// 设置布隆过滤器的误报率,例如 0.01 表示 1% 的误报率
columnDescriptor.setBloomFilterFalsePositiveChance(0.01f);
tableDescriptor.addFamily(columnDescriptor);
admin.createTable(tableDescriptor);

修改现有表的配置

// Java 代码示例
Configuration config = HBaseConfiguration.create();
Admin admin = ConnectionFactory.createConnection(config).getAdmin();
TableName tableName = TableName.valueOf(tableName);
HColumnDescriptor columnDescriptor = new HColumnDescriptor(familyName);// 获取表的描述符
HTableDescriptor tableDescriptor = admin.getTableDescriptor(tableName);// 设置布隆过滤器类型为 ROW
columnDescriptor.setBloomFilterType(BloomType.ROW);// 更新列族描述符
tableDescriptor.modifyFamily(columnDescriptor);
admin.modifyTable(tableName, tableDescriptor);

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

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

相关文章

二叉树以及堆的实现

树 树的定义及概念 树是⼀种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09; 个有限结点组成⼀个具有层次关系的集合。把它叫做树是因为它看起来像⼀棵倒挂的树&#xff0c;也就是说它是根朝上&#xff0c;而叶朝下的。 有⼀个特殊的结点&#xff0c;称…

不支持jdk8的jenkins部署jdk8项目

1、背景 目前最新的jenkins必须基于jdk8以上&#xff0c;才能安装。jenkins最新的插件部分也不支持jdk8了。 2、全局工具配置 配置一个jdk8 配置一个jdk8以上的版本&#xff0c;如jdk17 3、部署maven项目 jdk17项目 可以直接使用maven插件&#xff0c;部署。 jdk8项目 由…

01-调试开发k8s

使用 Docker 构建 Kubernete 官方 release 是使用 Docker 容器构建的。要使用 Docker 构建 Kubernetes&#xff0c;请遵循以下说明: Requirements docker Key scripts 以下脚本位于 build/ 目录中。请注意&#xff0c;所有脚本都必须从 Kubernetes 根目录运行 build/run.…

MySQL环境的配置文件json

突然了解到&#xff0c;使用json文件去进行环境的配置&#xff0c;这样修改参数的时候就只需要去改json文件中的内容&#xff0c;不需要去修改代码中的内容&#xff0c;其他人的MySQL和我的MySQL也不同&#xff0c;这时其他人只需要修改json文件中的内容&#xff0c;清晰明了&a…

代码随想录||day25 非递减子序列,全排列问题

491非递减子序列 力扣题目链接 题目描述&#xff1a; 给你一个整数数组 nums &#xff0c;找出并返回所有该数组中不同的递增子序列&#xff0c;递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。 数组中可能含有重复元素&#xff0c;如出现两个整数相等&#x…

双盲插便携屏方案:LDR6020系列便携显示

在当今这个追求高效与便携的时代&#xff0c;电子设备尤其是便携式显示器&#xff08;Portable Monitor&#xff09;的需求日益增长&#xff0c;成为商务人士、设计师、游戏玩家及移动办公族的理想伴侣。其中&#xff0c;6020系列便携屏以其卓越的显示效果、紧凑的机身设计赢得…

基于YOLO系列便捷式代码创新

目标检测 YOLOv5 与 YOLOv7 系列详细介绍 YOLOv5 详细介绍 版本与特点 网络结构 技术亮点 YOLOv7 详细介绍 主要贡献 网络结构 技术亮点 性能对比 基于YOLOv5和YOLOv7系列的多方面创新方法 融合BiFormer注意力机制 融合SImAM注意力机制 CBAM注意力机制 DBB多分枝模块 LSKA注意力…

NumpyPandas:pandas库的安装,不同对象的建立,文件的导入和了解数据

目录 前言 一、Pandas库的安装 二、不同对象的建立 1.Series对象的创建 1.用index方法指定索引 2.在创建的时候就指定索引 3.使用字典的方式创建 4.将一个常量与index一起传入创建 5.输出值和索引 2.DataFrame对象的创建 1.不指定列名则以键当列名 行索引为默认值 …

Hadoop3.3.5的安装与单机/伪分布式配置

文章目录 一、安装须知二、安装jdk三、安装shh四、安装配置hadoop五、运行hadoop 一、安装须知 本次安装的Hadoop版本为hadoop3.3.5。 在这之前完成了VMware虚拟软件的安装&#xff0c;并安装了Ubuntu22.04&#xff0c;在这基础上进行相关配置。 二、安装jdk 在Ubuntu中使用…

MySQL查询执行(一):count执行慢

查询处理器 MySQL查询处理器是MySQL数据库服务器的组件&#xff0c;它负责执行SQL查询。查询处理器的主要任务是解析查询&#xff08;把用户提交的SQL查询转换为可以被数据库引擎理解和执行的数据操作指令序列&#xff09;&#xff0c;生成查询计划&#xff0c;然后执行该计划。…

C++程序的UI界面闪烁问题的解决办法总结

Windows C++程序复杂的UI界面要使用多种绘图技术(使用GDI、GDI+、ddraw、D3D等绘图),并要贴图去美化,在窗口移动或者改变大小的时候可能会出现闪烁。下面罗列一下UI界面产生闪烁的几种可能的原因,并给出相应的解决办法。 1、原因一 如果熟悉显卡原理的话,调用GDI函数向屏…

JVM系列(三) -类加载器及双亲委派模型介绍

在之前的文章中&#xff0c;介绍了类的加载过程中&#xff0c;我们有提到在加载阶段&#xff0c;通过一个类的全限定名来获取此类的二进制字节流操作&#xff0c;其实类加载器就是用来实现这个操作的。 在虚拟机中&#xff0c;任何一个类&#xff0c;都需要由加载它的类加载器…

《Milvus Cloud向量数据库指南》——Milvus Cloud不同场景下的部署形态选型

不同场景下的部署形态选型 一般说选型肯定离不开阶段。用到向量数据库的应用基本有这么几个阶段: AI 应用的快速原型构建。比如你在做一个 AI 个人助手、一个小的搜索引擎原型、一个端到端的 RAG 原型,这类项目的迭代速度是很关键的,而且原型构建期不需要关心性能或者稳定性…

暑假第二周任务——3Gshare的仿写

3GShare的仿写 登陆注册页面 这个界面的UI比较简单&#xff0c;比较困难的地方在于限制我们的输入长度以及我们输入的字符类型。 在这里我是通过在textField的代理中设计限定输入字符的内容&#xff0c;从而实现限制输入长度和限制输入字符的内容&#xff0c;下面给出相关的代…

Day24|二叉树 PART08

235. 二叉搜索树的最近公共祖先 与236类似但可以利用二叉搜索树的性质来做 二叉搜索树&#xff1a;左子 小于头 小于右子 &#xff08;怪怪的 感觉是不是先记住比较好&#xff09;&#xff08;而且也没太理解二叉搜索树的规律&#xff09; 大体思路&#xff1a;从上到下遍历&a…

html 解决tooltip宽度显示和文本任意位置换行文本显示问题

.el-tooltip__popper {max-width: 480px;white-space: break-spaces; /* 尝试不同的white-space属性值 */word-break:break-all; }

干货:three.js中的六大光源的知识点。

我们在二维屏幕中感知三维场景的一个最重要的要素就是光&#xff0c;光和光源是three.js中一个非常重要的知识点。本文想借着这个话题&#xff0c;为老铁们分享以下六大光源知识点&#xff1a;环境光、点光源、聚光灯、方向光、半球光、平面光。 一、点光源 在 Three.js 中&a…

模拟string(四)详解

目录 判断string大小关系bool operator(const string&s1,const string s2)代码 bool operator<(const string& s1, const string& s2)代码 bool operator<(const string& s1, const string& s2)代码 bool operator>(const string& s1, const …

Stable Diffusion WebUI本地环境搭建

一、项目代码下载 git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui 二、环境配置 conda create --n stafu python3.10.6 实际上跟自己创建的环境没有关系&#xff0c;项目启动会自动复制这个环境&#xff0c;之后项目根据这个基础环境构建 也可以在自己…

机器学习——第一章 绪论

目录 1. 1 引言 1. 2 基本术语 1.3 假设空间 1.4 归纳偏好 1. 1 引言 机器学习致力于研究如何通过计算的手段&#xff0c;利用经验来玫善系统自身的性能在计算机系统中&#xff0c;"经验"通常以"数据"形式存在&#xff0c;因此&#xff0c;机器学习所研…