经典bloom算法(**布隆过滤器**)-levelDB拆分

news2024/9/30 11:39:18

bloom算法(布隆过滤器)

原理

先说一下什么是布隆过滤器,Bloom Filter是1970年由布隆提出的,它实际上是一个很长的二进制向量,和一系列随机值映射的函数,主要用于判断一个元素是否在一个集合中。

通常判断一个元素是否在一个集合中,一般是将元素和所有集合中的元素进行对比,当前元素和集合中元素某个元素完全一致的时候,就认为当前元素在该集合中,这时常借助树、散列表、链表以及数组等先存储对应的元素,然后在进行对比。这种情况下时间复杂度为O(logn) , O(1), O(n)

当元素数量比较小时,使用这些数据接口进行比对没有什么问题,但是随着元素个数的增加,对比的时间最低也是线性增长的,为了解决这个问题Bloom Filter就应运而生了。

布隆过滤器由一个固定大小的二进制向量或者位图和一系列映射函数组成,在初始化状态下所有状态都会被置为零。

在这里插入图片描述

创建过滤器的过程中,将集合中的所有值,通过k个映射函数,映射为过滤器中对应的点。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C24IJIpu-1669952236125)(https://ny5odfilnr.feishu.cn/space/api/box/stream/download/asynccode/?code=OTU4NWY1ZmExODNlZmExODJjZjk0NmVkODcyMTc4YTFfaFYxckNkREFYRHVDU0dFRTVWSmoxd1RrV1dPMGZJZnJfVG9rZW46Ym94Y25LRWJGcm5qZTNZdHVpM0xyTmNhUExjXzE2Njk5NTIxMDg6MTY2OTk1NTcwOF9WNA)]

当查询某个变量是否存在时,只需要按照同样的操作步骤,然后看对应的对应位置上是否全部为1,来判断集合中是否有这个值。

  • 如果集合中有任意一个k映射出来的值不符合,说明被查询的标量一定不存在集合中

  • 如果k映射的所有值都是存在的,则说明被查询的值有可能在集合中。

误判性

为什么可能存在? 当hash函数生成的散列值发生碰撞时,就有可能发生两个不同的值生成的散列值缺失相同的,还有就是经过多个元素映射的布隆过滤器,某个值的散列值经过k的映射刚好全部为1,但是这些1是多个元素一起映射的结果,而不是由单个元素映射在布隆过滤器上的。

特性

  1. 一个元素被判断存在的时候不一定存在,但是被判断结果为不存在的时候一定不存在

  2. 布隆过滤器可以添加元素,但是不能删除元素,因为删除元素会导致判断误判性增加,除非重新映射一遍

优势

相比于其他数据结构,布隆过滤器在空间和时间方面都有巨大的优势,插入和查询的时间空间复杂度都是常数O(K)

劣势

误算率比较高,随着元素的增加误算率也会随之增加,但是元素太少时,还不如直接使用散列表,因此要把握好元素的度。

不能在布隆过滤器中删除元素

代码实现

接口定义


class LEVELDB_EXPORT FilterPolicy {
 public:
  virtual ~FilterPolicy();

  // Return the name of this policy.  Note that if the filter encoding
  // changes in an incompatible way, the name returned by this method
  // must be changed.  Otherwise, old incompatible filters may be
  // passed to methods of this type.
  virtual const char* Name() const = 0;

  // keys[0,n-1] contains a list of keys (potentially with duplicates)
  // that are ordered according to the user supplied comparator.
  // Append a filter that summarizes keys[0,n-1] to *dst.
  //
  // Warning: do not change the initial contents of *dst.  Instead,
  // append the newly constructed filter to *dst.
  virtual void CreateFilter(const Slice* keys, int n,
                            std::string* dst) const = 0;

  // "filter" contains the data appended by a preceding call to
  // CreateFilter() on this class.  This method must return true if
  // the key was in the list of keys passed to CreateFilter().
  // This method may return true or false if the key was not on the
  // list, but it should aim to return false with a high probability.
  virtual bool KeyMayMatch(const Slice& key, const Slice& filter) const = 0;
};

hash函数,levelDB中使用的hash函数不是stl中标准的Hash函数是自己实现的一个hash函数

uint32_t BloomHash(const Slice &key) {
    return Hash(key.data(), key.size(), 0xbc9f1d34);
}

    uint32_t Hash(const char *data, size_t n, uint32_t seed) {
        // Similar to murmur hash
        const uint32_t m = 0xc6a4a793;
        const uint32_t r = 24;
        const char *limit = data + n;
        uint32_t h = seed ^(n * m);

        // Pick up four bytes at a time
        while (data + 4 <= limit) {
            uint32_t w = DecodeFixed32(data);
            data += 4;
            h += w;
            h *= m;
            h ^= (h >> 16);
        }

        // Pick up remaining bytes
        switch (limit - data) {
            case 3:
                h += static_cast<uint8_t>(data[2]) << 16;
                FALLTHROUGH_INTENDED;
            case 2:
                h += static_cast<uint8_t>(data[1]) << 8;
                FALLTHROUGH_INTENDED;
            case 1:
                h += static_cast<uint8_t>(data[0]);
                h *= m;
                h ^= (h >> r);
                break;
        }
        return h;
    }

函数实现


        class BloomFilterPolicy : public FilterPolicy {
        public:
            explicit BloomFilterPolicy(int bits_per_key) : bits_per_key_(bits_per_key) {
                // We intentionally round down to reduce probing cost a little bit
                // 按照计算公式 k = m/n * (ln2)来计算hash函数个数, m bit个数,n插入元素个数
                // leveldb 中简单处理了,一般这里会直接传入 bits_per_key 为 10进行计算
                k_ = static_cast<size_t>(bits_per_key * 0.69);  // 0.69 =~ ln(2)
                // 保证K_是处于  [1,30] 之间
                if (k_ < 1) k_ = 1;
                if (k_ > 30) k_ = 30;
            }

            const char *Name() const override { return "leveldb.BuiltinBloomFilter2"; }

            // 将传入的n个 key 存储到bloomfilter 中,bloomfilter结果使用string存储。
            void CreateFilter(const Slice *keys, int n, std::string *dst) const override {
                // Compute bloom filter size (in both bits and bytes)
                // bloomfilter需要多少bit  bits_per_key_ = (m/n) m bit个数,n插入元素个数
                size_t bits = n * bits_per_key_;

                // For small n, we can see a very high false positive rate.  Fix it
                // by enforcing a minimum bloom filter length.
                // 当bits太小的时候,会导致过滤器一直虚报错误,这里保证bits不小于64就可以了
                if (bits < 64) bits = 64;

                // 这里只是保证bits能够按照8位对齐
                size_t bytes = (bits + 7) / 8;
                bits = bytes * 8;
                // 在string中分配空间
                const size_t init_size = dst->size();
                dst->resize(init_size + bytes, 0);
                // string最后一个元素存储使用的 hash函数的个数
                dst->push_back(static_cast<char>(k_));  // Remember # of probes in filter
                // 获取string 内部的char型数组,数组指向多申请出来的内存,多申请出来的内存,用来存放Bloom hash映射值
                char *array = &(*dst)[init_size];
                for (int i = 0; i < n; i++) {
                    // 通过一次hash计算 一次delta计算,循环K_次将对应的 key在bits上进行置位
                    // Use double-hashing to generate a sequence of hash values.
                    // See analysis in [Kirsch,Mitzenmacher 2006].
                    // leveldb使用一个hash函数,每次对hash值向右移位17bit来模拟实现多个hash函数
                    uint32_t h = BloomHash(keys[i]);
                    const uint32_t delta = (h >> 17) | (h << 15);  // Rotate right 17 bits
                    // 多次重新计算hash模仿多个 hash函数,这里换成多个hash函数也是一样的
                    for (size_t j = 0; j < k_; j++) {
                        // 保证h 的长度不大于bloom过滤器的长度
                        const uint32_t bitpos = h % bits;
                        // 对对应位置进行置位
                        array[bitpos / 8] |= (1 << (bitpos % 8));
                        // 更新获得一个新的hash数值
                        h += delta;
                    }
                }
            }

            bool KeyMayMatch(const Slice &key, const Slice &bloom_filter) const override {
                const size_t len = bloom_filter.size();
                if (len < 2) return false;

                const char *array = bloom_filter.data();
                // 最后一个byte代表了使用多少hash函数
                // 除最后一个byte之外代表bit数组,详情将CreateFilter函数
                const size_t bits = (len - 1) * 8;

                // Use the encoded k so that we can read filters generated by
                // bloom filters created using different parameters.
                // 存储的是hash函数的个数
                const size_t k = array[len - 1];
                if (k > 30) {
                    // Reserved for potentially new encodings for short bloom filters.
                    // Consider it a match.
                    return true;
                }

                uint32_t h = BloomHash(key);
                const uint32_t delta = (h >> 17) | (h << 15);  // Rotate right 17 bits
                for (size_t j = 0; j < k; j++) {
                    const uint32_t bitpos = h % bits;
                    // (array[bitpos / 8] & (1 << (bitpos % 8)))
                    // 查找对应的bit位是否为0 若为0说明肯定不存在,就直接返回
                    if ((array[bitpos / 8] & (1 << (bitpos % 8))) == 0) return false;
                    h += delta;
                }
                // 只是说明可能存在
                return true;
            }

        private:
            // 平均每个key拥有的bit数目
            size_t bits_per_key_;
            // hash func的个数
            size_t k_;
        };

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

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

相关文章

Hasse diagram

In order theory, a Hasse diagram (/ˈhsə/; German: [ˈhasə]) is a type of mathematical diagram used to represent a finite partially ordered set, in the form of a drawing of its transitive reduction. Concretely, for a partially ordered set (S, ≤) one rep…

2023最新SSM计算机毕业设计选题大全(附源码+LW)之java高校学生宿舍管理信息系统3x4rz

做毕业设计一定要选好题目。毕设想简单&#xff0c;其实很简单。这里给几点建议&#xff1a; 1&#xff1a;首先&#xff0c;学会收集整理&#xff0c;年年专业都一样&#xff0c;岁岁毕业人不同。很多人在做毕业设计的时候&#xff0c;都犯了一个错误&#xff0c;那就是不借鉴…

記錄下用google colab 进行GPU(TPU)训练

文章目录温馨提示打开网站上传资源下载资源到google colab温馨提示 需要科学上网&#xff0c;没有的话可以点这个 https://shandianpro.com/#/register?codewCXwkCOU下个clashx进行 挂载 https://download.csdn.net/download/monk96/87231589 配置自行百度 打开网站 google…

Win11系统提示backgroundtaskhost.exe系统错误解决方法

Win11系统提示backgroundtaskhost.exe系统错误解决方法分享。backgroundTaskHost.exe是与Microsoft Cortana的虚拟助手相关联的关键系统进程。近期有Win11用户在电脑的使用中遇到了系统提示“backgroundTaskHost.exe – ApplicATIon Error”的错误&#xff0c;今天我们一起来看…

[附源码]计算机毕业设计JAVA学生考试成绩分析系统

[附源码]计算机毕业设计JAVA学生考试成绩分析系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM my…

疫情可视化part3

前言 之前在part2中说的添加自定义主题配色已经开发完成了&#xff0c;除此之外我还添加了一些的3d特效。 前期文章 这是part1的文章&#xff1a;https://blog.csdn.net/xi1213/article/details/126824752这是part2的文章&#xff1a;https://blog.csdn.net/xi1213/article/…

[附源码]Python计算机毕业设计Django基于VUE的网上订餐系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

【Linux】进程

1.linux操作系统要不要管理进程呢&#xff1f;必须要&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 2.linux是如何管理大量进程的呢&#xff1f;先组织&#xff0c;再描述。 1.什么是进程 进程就是系统运行中…

WordPress批量修改数据库内文章内容文字关键字标题

WordPress网站内容标题文字一键修改&#xff0c;注意到了网站上很多要一个个的修改&#xff0c;那工作了巨大&#xff0c;怎么快速在数据库中用SQL命令批量替换呢&#xff1f; 通过数据库替换方法 1.进入宝塔面板-数据库-选择对应的数据库-管理数据库-登录进来。就可以直接对数…

2022年小美赛“认证杯”数学建模ABCD题初步分析选题建议

​ 2022年小美赛数学建模赛题已经发布&#xff1a; A题 翼龙是如何飞行的 B题 序列的遗传过程 C题 对人类活动进行分类 D题 是否应长期禁止野生动物贸易 总体来说&#xff0c;从赛题难度来看B>A>C>D&#xff0c;其中CD属于ICM交叉学科类赛题&#xff0c;难度系数相对…

腾讯云原生安全“3+1”一体化方案发布,重构云上安全防御体系

12月1日&#xff0c;2022腾讯全球数字生态大会上&#xff0c;以“安全守护&#xff0c;行稳致远”为主题的「云原生安全专场」顺利召开&#xff0c;论坛深入讨论了云原生安全的行业发展趋势、技术探索、产品创新和落地实践。 会上&#xff0c;腾讯安全发布了云原生安全“31”一…

java面向对象-----再谈方法

目录 方法的重载(overload) 可变个数的形参 方法参数的值传递机制 基本数据类型的参数传递 引用数据类型的参数传递 递归(recursion)方法 总结 方法的重载(overload) 重载的概念 &#xff1a;在同一个类中&#xff0c;允许存在一个以上的同名方法&#xff0c;只要它们的参…

基于粒子群优化的神经网络PID控制(Matlab)代码实现

&#x1f352;&#x1f352;&#x1f352;欢迎关注&#x1f308;&#x1f308;&#x1f308; &#x1f4dd;个人主页&#xff1a;我爱Matlab &#x1f44d;点赞➕评论➕收藏 养成习惯&#xff08;一键三连&#xff09;&#x1f33b;&#x1f33b;&#x1f33b; &#x1f34c;希…

“空间代谢组学“用于食管鳞状细胞癌早期筛查的研究

​ 代谢组学文献分享—研究背景 近几年代谢组学的研究如火如荼的开展&#xff0c;极大地促进了各学科的发展&#xff0c;如疾病诊断与治疗、营养学、环境毒理学、进化和发育及药物等&#xff1b;与此同时&#xff0c;质谱成像技术&#xff08;mass spectrometry imaging, MSI…

动态规划思想

1.动态规划思想&#xff1a;因为计算量太大而提出的解放方式。将一件大的事情分成若干个小的事情。2.找一个最优的隐藏序列&#xff0c;结合动态规划思想&#xff0c;可以把这个隐藏序列分成多个时间步&#xff0c;如果每个时间步都是最优的&#xff0c;那么最终的这个序列就是…

软件测试流程分享

工作以来&#xff0c;大大小小参与的项目也有十几个了&#xff0c;涵盖财务类、保险类、OA办公类软件&#xff0c;从测试流程上看&#xff0c;基本也都大同小异&#xff0c;这里将常见的测试流程做一些梳理&#xff0c;供刚入行的朋友学习参考&#xff0c;也欢迎大家完善补充。…

GD32F30x系列ADC源码,对初学者参考价值巨大,(非常详细篇)万字源码

GD32F30x系列ADC源码【1】adc_reg.h [参考]【2】ctrl_adc.h [重点]【3】gd32f30x_dma_reg.h [参考]【4】mon_adc.h [参考 1]【5】rcu.h [参考]【6】ctrl_adc.c [重要]【7】mon_adc.c [参考1]【8】main.c [参考2]这篇文章必须配合这个连接文件一起看&#xff0c;即ADC手册 嵌入式…

我的学校网页期末作业(纯html+css实现)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

在js中使用grpc(包括代理)后端使用Go

叙述 最近在研究web端的聊天系统&#xff0c;准备使用grpc作为通讯协议&#xff0c;因为客户端要主动的接受到消息&#xff0c;所以想要使用双向流的grpc。 但是经过几天的研究发现&#xff0c;grpc在浏览器上是不支持的&#xff0c;因为浏览器使用的协议是http1.1&#xff0c…

Apipost自动化测试功能详解

如何快速掌握接口自动化测试&#xff1f;首先我们看看&#xff1a; 1、什么是接口自动化测试&#xff1f; 通常&#xff0c;在设计了测试用例并通过评审之后&#xff0c;由测试人员根据测试用例中描述的规程一步步执行测试&#xff0c;得到实际结果与期望结果的比较。自动化测…