0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

数据集中如何判断元素是否存在

科技绿洲 来源:Java技术指北 作者:Java技术指北 2023-10-07 16:43 次阅读

Guava BloomFilter

布隆过滤器是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率和删除困难。

基本概念

当需要判断某个元素是否在某个数据集中时,一般会怎么做?

  1. 将数据集封装成集合,比如List、Set等
  2. 通过集合提供的API判断该元素是否存在于集合

这样的实现比较简单,同时通过现有的JDK都能很快达到目的,但是设想一下,如果上面说到的集合数据量非常的大,这样不仅会耗费较大的存储空间,同时 在集合中检索元素的时间复杂度也会随之增加。那么有没比较好的方法去实现判断元素是否存在这样的情形呢?

也就是 布隆过滤器

通过一系列的Hash函数将元素映射到一个位阵列(Bit Array)中的多个点位上,判断元素是否存在,则是判断所有点位是不是都为1。然而,位阵列上都为1并不一定能够保证该元素一定存在,也有可能是其他元素Hash后落在了该点位上,这就是布隆过滤器的误判。

因此通过布隆过滤器我们可以确定:

  1. 元素可能在集合中
  2. 元素一定不在集合中

应用场景

  • 网页爬虫时忽略已经判定的URL路径
  • 邮箱通过设置过滤垃圾邮件
  • 集合重复元素的判别,有效判断元素不在集合中
  • 防止数据缓存时的缓存穿透问题

优缺点

  • 优点
    • 相比于其它的数据结构,布隆过滤器在空间和时间方面都有巨大的优势。
    • 布隆过滤器存储空间和插入/查询时间都是常数。
    • Hash函数相互之间没有关系,方便由硬件并行实现。
    • 布隆过滤器不需要存储元素本身,对保密要求非常严格的场合有优势。
    • 布隆过滤器可以表示全集,其它任何数据结构都不能。
  • 缺点
    • 元素存在的误判
    • 一般情况下不支持元素(位阵列)的删除

实现原理

图片

核心其实是元素如何存储?如何判断元素是否存在?核心方法就两个,一个“存”一个检查,里面涉及到了算法相关知识,感兴趣可以深入研究下其实现原理与思想。

  • put 将元素放入过滤器中,但不是存储
public < T > boolean put(@ParametricNullness T object, Funnel< ? super T > funnel, int numHashFunctions, LockFreeBitArray bits) {
            long bitSize = bits.bitSize(); // 位数组,可以通过redis来实现分布式的布隆过滤器
            long hash64 = Hashing.murmur3_128().hashObject(object, funnel).asLong(); //通过funnel将对象转换成基本类型并计算64位hash
            int hash1 = (int)hash64; // 取低32位
            int hash2 = (int)(hash64 > >> 32); // 取高32位
            boolean bitsChanged = false;
            // 
            for(int i = 1; i <= numHashFunctions; ++i) {
                int combinedHash = hash1 + i * hash2;
                if (combinedHash < 0) {
                    combinedHash = ~combinedHash;
                }

                bitsChanged |= bits.set((long)combinedHash % bitSize);
            }

            return bitsChanged;
        }
  • mightContain 与put相似,计算的过程相同,不同的是值的判断
public < T > boolean mightContain(@ParametricNullness T object, Funnel< ? super T > funnel, int numHashFunctions, LockFreeBitArray bits) {
            long bitSize = bits.bitSize();
            long hash64 = Hashing.murmur3_128().hashObject(object, funnel).asLong();
            int hash1 = (int)hash64;
            int hash2 = (int)(hash64 > >> 32);

            for(int i = 1; i <= numHashFunctions; ++i) {
                int combinedHash = hash1 + i * hash2;
                if (combinedHash < 0) {
                    combinedHash = ~combinedHash;
                }

                if (!bits.get((long)combinedHash % bitSize)) {
                    return false;
                }
            }

            return true;
        }

我们可以简单第理解其实现原理?比如现在有一个容器,我们定义为String[] bitArray = new String[26]作为 位阵列 , 现在有一堆由小写英文组成的元素,我们假定Hash算法为a-z到1~26的映射。

  1. 现在有一个元素abc,hash后为1110000000...,保存到bitArray :1110000000...
  2. 现在有一个元素cde, hash后为0011100000...,保存到bitArray :1111100000...
  3. 现在又有一个新的元素ade,hash后同样为100110000...,很明显会认为该元素存在,这就是FFP

为什么判断元素一定不在集合中呢?很显然,如果一个元素存在,则该元素hash后的bit数组必须全部都是1,反之则不存在

示例

@Test
    public void match(){
        BloomFilter filter = BloomFilter.create(Funnels.stringFunnel(Charset.defaultCharset()),10000,0.2);
        List< String > ids = new ArrayList<  >();

        IntStream.rangeClosed(1,10000).forEach(index- >{
            String id = UUID.randomUUID().toString();
            ids.add(id);
            filter.put( id );
        });

        ids.forEach(id- >{
            // 正常情况下全部失败,但是会有 20%的返回true
            System.out.println( id + ":" + filter.mightContain( id+1 ));
        });
    }

流程很简单:

  1. 根据配置构建BloomFilter对象
  2. 通过put方法,初始化数据到filter
  3. 通过方法mightContain判断元素是否存在

结束语

BloomFilter虽然看起来简单,但是其内部的实现包含了很多的数学与算法知识,我们只是通过其简单的API就能各种复杂的功能。关于如何将目前说到的这些在具体的项目中进行实践与集成 后面会来介绍,首先我们能够先了解一些技术一起能解决上面问题,理解了原理与目的,使用也就不是难事。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • API
    API
    +关注

    关注

    2

    文章

    1470

    浏览量

    61731
  • 缓存
    +关注

    关注

    1

    文章

    229

    浏览量

    26627
  • 函数
    +关注

    关注

    3

    文章

    4274

    浏览量

    62302
  • 过滤器
    +关注

    关注

    1

    文章

    425

    浏览量

    19506
  • 数据集
    +关注

    关注

    4

    文章

    1200

    浏览量

    24613
收藏 人收藏

    评论

    相关推荐

    如何准确判断集中电路IC是否正常工作?

    如何准确判断电路中集成电路IC是否“偷懒”没处在工作状态,是好是坏是修理电视、音响、录像设备的一个重要内容,判断不准,往往花大力气换上新集成电路而故障依然存在,所以要对集成电路作出正确
    的头像 发表于 12-29 09:27 2w次阅读

    如何判断链表是否有环

    如何判断链表是否有环?
    发表于 08-10 17:07 635次阅读
    如何<b class='flag-5'>判断</b>链表<b class='flag-5'>是否</b>有环

    LabVIEW如何识别接线端是否数据输入,不能通过判断默认值的方式

    ”接线端的默认值为0。该接线端不连接时,实际操作为删去最后一个元素;写默认值0时实际操作为删去索引0的元素。由此可见,这个函数可以识别接线端是否数据输入,并且不是通过
    发表于 09-24 10:53

    C语言中怎么判断数组元素的个数

    C语言中怎么判断数组元素的个数,如数组:int array[]={45,56,76,234,1,34,23,2,3};
    发表于 05-26 11:49

    float类型数据是否合理判断

    float类型数据是否合理判断_chkfloat_单片机内嵌函数是怎么实现的?也就是怎么判断一个float数据
    发表于 07-22 16:17

    快速判断一维数组元素是否有重复

    今天在编写一个程序时要判断一维数组元素是否有重复,想了想做了个简单判断的程序,和大家分享一下思路,欢迎各位高手前辈提供更佳的思路方案。
    发表于 01-10 09:59

    请问如何判断一个任务是否存在或者已经删除?

    ) == osThreadDeleted来判断是否被删除,可是在第一次运行时,也就是XXXTask并不存在时,程序会卡死在configASSERT( pxTCB );因为pxTCB = ( TCB_t * ) xTask
    发表于 06-09 09:11

    如何判断输出图像数据是否正常?

    如何判断输出图像数据是否正常?
    发表于 02-15 06:59

    Arm AMBA协议集中是否存在无效数据填充导致效率降低的问题

    Arm AMBA协议集中,当总线位宽很宽时(如2048bit),是否存在无效数据填充导致效率降低的问题?AXI协议是否支持segment(
    发表于 09-14 11:42

    怎样判断放大器是否存在自激振荡?如何进行消除呢?

    怎样判断放大器是否存在自激振荡?如何进行消除呢?
    发表于 04-26 14:43

    C语言教程之判断一个数是否存在数组中

    C语言教程之判断一个数是否存在数组中,很好的C语言资料,快来学习吧。
    发表于 04-25 15:13 0次下载

    Linux中如何判断文件夹是否存在并新建文件夹

    本文档的主要内容详细介绍的是Linux中如何判断文件夹是否存在并新建文件夹vi文件免费下载。
    发表于 01-17 08:00 8次下载
    Linux中如何<b class='flag-5'>判断</b>文件夹<b class='flag-5'>是否</b><b class='flag-5'>存在</b>并新建文件夹

    如何判断网络是否存在二层环路

    方法只能看到网络的当前流量结果,此时需要和网络的正常业务量进行比较,流量远大于正常业务流量时,才能判断可能存在二层环路。如果流量只是稍大时,或者设备部署了广播抑制,就不能判断出环路了,需要使用其他方法
    发表于 12-16 15:44 3220次阅读

    怎样判断放大器是否存在自激振荡?如何进行消除?

    怎样判断放大器是否存在自激振荡?如何进行消除?  放大器是电子器件中应用最广泛的一种电路,其作用是在保持电信号形状不失真的前提下将信号幅度放大,从而扩大信号的传输范围和距离。然而,由于各种因素
    的头像 发表于 09-18 09:16 5526次阅读

    js判断是否在数组中存在

    JavaScript 是一种用于客户端和服务器端编程的脚本语言。它提供了许多内置函数和方法,以便进行数组操作。 在本文中,我们将学习如何使用 JavaScript 来判断一个元素是否存在
    的头像 发表于 11-30 16:23 1059次阅读