Cuckoo Filter

news2025/5/15 0:16:58

其他判重数据结构

  • Bloom Filter
  1. 无法支持删除计数的功能,
  2. 需要更多的存储空间来存储数据

因为在CS中,删除计数是常见的操作,但是这会对布隆过滤器的存储空间产生影响,同样为了实现这一操作,需要更多的存储空间

  1. 数据量一旦达到了一定的层级,就需要进行一个扩容,对数据进行一个rehash

理论篇

如何工作

Cuckoo Filter可以支持删除有限计数有界FPP1来优化布隆过滤器,其存储效率高于标准布隆过滤器

Cuckoo hash table in action

  • cuckoo的每个元素使用两个bucket(每个元素对应到两个不同的bucket索引位置)
  • cuckoo的每个bucket可能会存储多个元素,不只有一个元素
  • bucket中存储的是data的低f位指纹而不是真实的数据(根据FPP确定的)
  • 使用部分对称密钥来计算两个bucket的索引位置

基础操作

  1. 查找元素的时候,cuckoo会使用哈希函数并检查两个桶中的指纹,没有找到匹配的指纹,说明数据一定不在,如果找到了指纹,那么数据可能在
  2. 当另一个元素将匹配到的指纹插入到两个已检查桶的任何一个时,就会报错
  3. 删除:删除该值对应存储桶中的指纹
  4. 计数:在cuckoo 中维护一个count来实现
  5. 插入:计算出两个bucket索引位置,将元素的指纹存放到两个bucket的其中一个空闲的位置中,冲突就需要进行递归的对元素迁移,重复上诉操作

实现

获得索引位置

bucketi=h1(x) = hash(x),
//使用对称加密
bucketj=h2(x) = h1(x) ⊕ hash(x’s fingerprint).
//使用对称加密很方便获得另一个hash位置
bucketi=bucketj^hash(x’s fingerprint).

    void generateIndexHash(const string &data, uint32_t fp, uint32_t &b1, uint32_t &b2) //根据该finger生成获得对应的存储位置
    {
        b1 = finger_hash_(data) % num_bucket_; //生成两个索引位
        b2 = (b1 ^ finger_hash_(to_string(fp))) % num_bucket_;
    }

插入

cuckoo 会使用hash函数将与元素hash到两个bucket中,并将指纹(低f位,根据hash函数计算出来的(和选择插入位置的哈希函数不同))插入到任意一个开放的位置(每个hash桶可以存储多个元素,而不仅仅只有一个)

  • 如果两个桶都有位置,那么cuckoo会将该元素的指纹随机选择一个桶插入(不是插入到两个桶),插入到该桶中的任意一个空闲的位置(由hash函数计算出来)
  • 如果随机选择的其中一个桶位置被占了,就会插入到另一个桶中
  • 如果两个桶都满了,cuckoo会将其中一个桶的某个元素踢走,新元素插入到该位置上,如果被题的元素有备用位置,就将其插入到备用的位置上,递归(递归的进行插入,在两个桶捣腾,重复上诉过程)这一过程,如果所有备用位置都完了,就认为失败
    在这里插入图片描述
    bool InsertImpl(uint32_t fp, uint32_t bucket_index)
    {
        vector<uint32_t> &bucket = table_[bucket_index]; //获得对应的桶
        //因为每个桶存4个元素
        for (uint8_t i = 0; i < num_entry_per_bucket_; i++)
        {
            if (!bucket[i])
            {
                max_entry_++; //存储的元素++
                bucket[i] = fp;
                return true;
            }
        }

        return false;
    }

    bool Insert(const string &data)
    {
        //获得指纹,获得低finger位置
        uint32_t fp = finger_hash_(data) & ((1 << fingerprint_size_) - 1); //这个是对应的指纹位最大也才10位,所以不会超出限制
        uint32_t b1, b2;                                                   //每个元素对应两个索引位置
        generateIndexHash(data, fp, b1, b2);
        if (InsertImpl(fp, b1))
            return true;
        if (InsertImpl(fp, b2))
            return true;
        //两个都满了(2个bucket的8个位置都满了),所以需要进行一个迭代kick
        for (uint32_t i = 0; i < kMaxNumKicks; i++)
        {
            //选择其中一个桶的元素,并让该元素离开
            uint32_t b = (rand() % 2 == 0) ? b1 : b2;
            uint32_t r = rand() % num_entry_per_bucket_; //获得要替代的元素
            uint32_t tmp_fp = table_[b][r];
            table_[b][r] = fp; //插入
            fp = tmp_fp;       //将该kick出去的fp要获得他其他的索引位
            //根据该fingerprint获得其对应的两个索引位置
            //还是b1和b2两个位置
            if (b == b1)
            {
                //因为在转化的时候,要替换的元素只有一个位置不一样
                if (b2 = (finger_hash_(to_string(fp)) ^ b1) % num_bucket_; InsertImpl(fp, b2))
                    return true;
            }
            if (b == b2)
            {
                if (b1 = (finger_hash_(to_string(fp)) ^ b2) % num_bucket_; InsertImpl(fp, b1))
                    return true;
            }
        }
        return false;
    }
    

查找


    bool lookUpImpl(uint32_t fp, uint32_t index)
    {
        vector<uint32_t> &bucket = table_[index];
        for (uint8_t i = 0; i < num_entry_per_bucket_; i++)
        {
            if (bucket[i] == fp)
            {
                return true;
            }
        }
        return false;
    }

    bool lookUp(const string &data) //查找一个元素
    {
        uint32_t fp = finger_hash_(data) & ((1 << fingerprint_size_) - 1); //这个是对应的指纹位最大也才10位,所以不会超出限制

        uint32_t b1, b2;
        generateIndexHash(data, fp, b1, b2);
        if (lookUpImpl(fp, b1) || lookUpImpl(fp, b2))
        {
            return true;
        }
        return false;
    }

删除

    bool DeleteImpl(uint32_t fp, uint32_t index) //实现删除的逻辑
    {
        vector<uint32_t> &bucket = table_[index];
        for (uint8_t i = 0; i < num_entry_per_bucket_; i++)
        {
            if (bucket[i] == fp)
            {
                //找到了
                max_entry_; //总个数减少
                bucket[i] = 0;
                return true;
            }
        }
        return false;
    }
    bool Delete(const string &data) //删除一个元素
    {
        uint32_t fp = finger_hash_(data) & ((1 << fingerprint_size_) - 1); //这个是对应的指纹位最大也才10位,所以不会超出限制

        //获得他的索引位置
        uint32_t b1, b2;
        generateIndexHash(data, fp, b1, b2);
        //因为一个元素只会出现一个bucket中,所以找到一个就算可以了
        if (DeleteImpl(fp, b1) || DeleteImpl(fp, b2))
        {
            return true;
        }

        return false;
    }

有什么用

  1. 可以帮助我们快速的检查一个元素是否在某个集合中
  2. 数据库查询优化,将数据插入到cuckoo中,可以通过查询过滤器,来测试某个数据是否存在,如果查询失败,就不需要访问数据库
  3. 边缘过滤,可以帮助我们快速的过滤掉一些无用的请求,提高网络传输效率。
    类似于边缘缓存,但原始数据不需要存储在过滤器中

    1.利用网络边缘的缓存节点CDN边缘节点缓存数据的技术,可以更快的向用户提供所需的内容,用户在请求特定的数据,即使在远程的服务器上,也能在较短的时间进行访问,常用在静态网页图像视频音乐等多媒体内容的分发
    2. 原始数据不需要存在过滤器中:可以在数据流传输过程中通过算法技术架构。进行实时的分析和过滤操作,提高数据处理和应用的效率可靠性

如何选择

  1. Cuckoo Filter如果不会影响时间敏感度2,优先选择Cuckoo Filter,Cuckoo相比拥有更好的查询速度更低的误判率,时间敏感度更好,可以快速的响应各种请求并且缩短响应时间
  2. Cuckoo的插入上随着数据的增多,效率会逐渐低下
  3. 对于相同的误报率,Cuckoo需要更少的空间
  4. Cuckoo还可以支持删除操作

参考

Cuckoo filter [Explained]
Cuckoo Filter: Practically Better Than Bloom
Bloom Filters by Example


  1. False Positive Probability,假阳性的概率,概率容器可以错误返回true ↩︎

  2. 时间敏感度指完成任务所需要的响应时间或处理时间的要求或限制,对任务的响应和处理时间要求高 ↩︎

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

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

相关文章

vue---父子、兄弟、跨层级关系组件通信

目录 1、props / $emit &#xff08;父子通信&#xff09; 2、$root、 $parent / $children(vue3废弃) 3、ref/$refs 4、EventBus &#xff08;$emit / $on&#xff09; 5、provideinject&#xff08;依赖注入&#xff09; 6、$attrs $listeners&#xff08;透传&#x…

电子政务网络智慧运维方案

随着电子政务建设的深入&#xff0c;我国政府的信息化建设已经具备了一定的规模&#xff0c;形成了部、省、市、县四级体系&#xff1b;大型政务服务事项、公文流转、行政审批、费税征缴、信息公开、网格化社会管理、三网融合、智慧城市建设等大量政府核心业务越来越依赖信息化…

Linux 静态库的制作与使用

目录 静态库1、 什么是库2、 静态库的制作2.1 命名规则与制作规则 3、 静态库的使用 静态库 1、 什么是库 库文件是计算机上的一类文件&#xff0c;可以简单的把库文件看成一种代码仓库&#xff0c;它提供使用者可以直接拿来用的变量、函数或类。库是一种特殊的程序&#xff…

atbetaflight——指定commit号编译固件

一、说明 在开发过程中&#xff0c;比如成员A上传了一次code,而成员B需要测试本次提交的code&#xff0c;但是由于没有搭建ci,成员B就需要自己拉code编译&#xff0c;本文将详细说明编译步骤&#xff1b; 二、步骤 1、使用vscode打开code 在使用git clone下载到code后的文件…

HDCTF2023复盘

文章目录 前言 CryptoNormal_rsaNormal_rsa(Revenge)(低指数e攻击)Math_RSA(二次剩余)爬过小山的看云(hill,云影) MischardMisc(base64)MasterMisc(crc,wav)ExtremeMisc(zip爆破,明文攻击) Reverseeasy_re(Upx,base64)easyasm(xor) WebWelcome To HDCTF 2023(JSFuck)SearchMast…

『C++』异常详解

「前言」文章是关于C异常方面&#xff0c;下面开始讲解 「归属专栏」C嘎嘎 「笔者」枫叶先生(fy) 「座右铭」前行路上修真我 「枫叶先生有点文青病」 「每篇一句」 少年的肩膀&#xff0c;就该这样才对嘛&#xff0c; 什么都不要急&#xff0c; 先挑起清风明月、杨柳依依和草长…

华为OD机试真题(Java),吃到最多的刚好合适的菜(100%通过+复盘思路)

一、题目描述 入职后&#xff0c;导师会请你吃饭&#xff0c;你选择了火锅。 火锅里会在不同时间下很多菜。 不同食材要煮不同的时间&#xff0c;才能变得刚好合适。你希望吃到最多的刚好合适的菜&#xff0c;但你的手速不够快&#xff0c;用m代表手速&#xff0c;每次下手捞…

作业3综合练习

综合练习: 要求&#xff1a;请给openlab搭建web网站 网站需求: 1.基于域名www.openlab.com可以访问网站内容为 welcome to openlab!!! 2.给该公司创建三个子界面分别显示学生信息,教学资料和缴费网站,基于www.openlab.com/student #更改配置文件 &#xff08;虚拟主机标签…

嵌入式51单片机04-矩阵按键系列

文章目录 矩阵按键一、矩阵按键基础知识二、矩阵按键系列代码1. 矩阵按键操作&#xff08;显示数字&#xff09;&#xff08;1&#xff09;仿真电路图&#xff08;2&#xff09;源代码&#xff08;3&#xff09;实验结果 2. 矩阵按键操作&#xff08;控制数码管&#xff09;&am…

STM32的GPIO重映射配置(解除下载端口的重映射)

在设计一个项目的时候&#xff0c;因为用的是STMF103C8T6&#xff0c;引脚较少&#xff0c;所以把可以用的GPIO都需要用上&#xff0c;但是由于下载的引脚在出生时&#xff0c;被厂家已经配置好了&#xff0c;所以我们得利用软件配置一下&#xff0c;使引脚变成正常的GPIO。 手…

安卓12源码编译错误-java.lang.OutOfMemoryError: Java heap space

报错如下&#xff1a; FAILED: out/soong/.intermediates/frameworks/base/module-lib-api-stubs-docs-non-updatable/android_common/metalava/api_lint.timestamp out/soong/.intermediates/frameworks/base/module-lib-api-stubs-docs-non-updatable/android_common/metala…

Flutter开发日常练习-小猫咪杂货店(新增动画和跳转抖音)

之前的练习加了个详情页面,然后跳转第三方页面抖音用户详情页面 跳转详情页添加了Hero的动画,共享元素过度 一个 标准 hero 动画 使 hero 从一页飞至新页面&#xff0c;通常以不同大小到达不同的目的地。 设定好每个图片的id,通过id作为 Hero 组件的标识,id不能重,否则会报错&…

DHCP笔记

目录 DHCP动态主机配置协议——UDP67/68端口 DHCP获取IP地址 客户端首次获取IP地址 客户端再次获取IP地址 租期/续租 DHCP的工作报文 DHCP的配置 案例 DHCP动态主机配置协议——UDP67/68端口 DHCP是应用层协议&#xff0c;采用C/S服务模式&#xff0c;只能在一个广播域…

TortoiseSVN使用-授权访问

文章目录 3.4.6 授权访问 3.4.6 授权访问 总结&#xff1a; 如果是匿名访问&#xff08;就是不用输入用户名密码的访问方式&#xff09;&#xff0c;请只开启anon-access write如果授权访问&#xff0c;请先设置anon-access none&#xff0c;然后打开3个&#xff1a;auth-a…

C++ “类与对象”

类与对象的概念 类相当于是结构体的声明&#xff0c;是结构体的设计图&#xff0c;而对象是利用设计图的创造的产物. &#xff08;1&#xff09;.类的大小计算 类的大小计算时与结构体类似&#xff0c;但函数是不计入大小的&#xff08;函数放在单独的公共空间&#xff09;. 在…

贝叶斯学习(Bayesian Learning)提高篇

Advanced Bayesian Learning 前言Review Bayes Optimal ClassifierNaive Bayes Classifier这里其实不太懂ExampleLaplace smoothing加完之后原数据的比例会发生变化分子1&#xff0c;如何确定分母的加数 Naive Bayes for Document Classi cationProblem statementDocument repr…

C语言猜数字小游戏

今天&#xff0c;我们来写一个猜数字小游戏&#xff0c;这个游戏的大致规则如下&#xff1a;&#x1f447; 1.电脑会随机生成一个数1~100 2.猜数字 a> 猜大了&#xff0c;提醒猜大了&#xff0c;继续猜 b> 猜小了&#xff0c;提醒猜小了&#xff0c;继续彩 c> 猜对了&…

Windows下版本控制器(SVN)-启动服务器端程序

文章目录 3.3 启动服务器端程序 3.3 启动服务器端程序 ①SVN 服务器必须处于运行状态才能响应客户端请求&#xff0c;帮助我们管理项目文件。 所以我们必须将 SVN 服务器启动起来。启动 SVN 服务器有两种方法&#xff0c;一个是命令 行方式&#xff0c;一个是注册 Windows 服务…

基于容器平台 ACK 快速搭建 Stable Diffusion

作者&#xff1a;子白 本文介绍如何在阿里云容器平台 ACK 上快速搭建一套可对外提供服务的 Stable Diffusion。 CPU 版本 前提条件 已创建 Kubernetes 托管版集群。具体操作&#xff0c;请参见创建 Kubernetes 托管版集群[1]。 &#x1f4cd;无需 GPU&#xff0c;节点需要…

数据库系统概论--第三章课后习题

1.试述SQL的特点。 答:SQL有以下特点: ①综合统一:SQL语言集数据定义语言DDL、数据操纵语言DML、数据控制语言DCL的功能于一体。在关系模型中实体和实体间的联系均用关系表示,这种数据结构的单一性带来了数据操作符的统一性,查找、插入、删除、更新等每一种操作都只需一种操作…