【大数据】亿级数据中判断一个数是否存在

本文涉及的产品
云原生大数据计算服务 MaxCompute,5000CU*H 100GB 3个月
云原生大数据计算服务MaxCompute,500CU*H 100GB 3个月
简介: 【大数据】亿级数据中判断一个数是否存在

问题描述

在开发过程中,经常要判断一个元素是否在一个集合中。假设你现在要给项目添加IP黑名单功能,此时你手上有大约 1亿个恶意IP的数据集,有一个IP发起请求,你如何判断这个IP在不在你的黑名单中?

类似这种问题用Java自己的Collection和Map很难处理,因为它们存储元素本身,会造成内存不足,而我们只关心元素存不存,对于元素的值我们并不关心,具体值是什么并不重要。

解决方案

BloomFilter(布隆过滤器)

布隆过滤器可以用来判断某个元素是否在集合内,具有运行快速,内存占用小的特点,它是一个保存了很长的二级制向量,同时结合 Hash 函数实现的。而高效插入和查询的代价就是,它是一个基于概率的数据结构,只能告诉我们一个元素绝对不在集合内,对于存在集合内有一定的误判率

fpp

因为布隆过滤器中总是会存在误判率,因为哈希碰撞是不可能百分百避免的。布隆过滤器对这种误判率称之为假阳性概率,即:False Positive Probability,简称为 fpp。

在实践中使用布隆过滤器时可以自己定义一个 fpp,然后就可以根据布隆过滤器的理论计算出需要多少个哈希函数和多大的位数组空间。需要注意的是这个 fpp 不能定义为 100%,因为无法百分保证不发生哈希碰撞。

下图表示向布隆过滤器中添加元素 https://blog.csdn.net/booksseahttps://www.abc.com 的过程,它使用了 func1 和 func2 两个简单的哈希函数。

对写入的数据做 H 次 hash 运算定位到数组中的位置,同时将数据改为 1 。当有数据查询时也是同样的方式定位到数组中。 一旦其中的有一位为 0 则认为数据肯定不存在于集合,否则数据可能存在于集合中。

通过其原理可以知道,可我们可以提高数组长度以及 hash 计算次数来降低误报率,但是相应的 CPU、内存的消耗也会相应的提高;这需要我们根据自己的业务需要去权衡选择。

布隆过滤器的特点

布隆过滤有以下2个特点:

  • 只要返回数据不存在,则肯定不存在。
  • 返回数据存在,但只能是大概率存在。

在有限的数组长度中存放大量的数据,即便是再完美的 Hash 算法也会有冲突,所以有可能两个完全不同的 A、B 两个数据最后定位到的位置是一模一样的。这时拿 B 进行查询时那自然就是误报了。

布隆过滤器中的数据可不可以删除

布隆过滤器判断一个元素存在就是判断对应位置是否为 1 来确定的,但是如果要删除掉一个元素是不能直接把 1 改成 0 的,因为这个位置可能存在其他元素,所以如果要支持删除,最简单的做法就是加一个计数器,就是说位数组的每个位如果不存在就是 0,存在几个元素就存具体的数字,而不仅仅只是存 1,那么这就有一个问题,本来存 1 就是一位就可以满足了,但是如果要存具体的数字比如说 2,那就需要 2 位了,所以带有计数器的布隆过滤器会占用更大的空间。

<dependency>
    <groupId>com.baqend</groupId>
    <artifactId>bloom-filter</artifactId>
    <version>1.0.7</version>
</dependency>

新建一个带有计数器的布隆过滤器 CountingBloomFilter:

package com.lonelyWolf.redis.bloom;
import orestes.bloomfilter.FilterBuilder;
public class CountingBloomFilter {
    public static void main(String[] args) {
        orestes.bloomfilter.CountingBloomFilter<String> cbf = new FilterBuilder(10000,
                0.01).countingBits(8).buildCountingBloomFilter();
        cbf.add("zhangsan");
        cbf.add("lisi");
        cbf.add("wangwu");
        System.out.println("是否存在王五:" + cbf.contains("wangwu")); //true
        cbf.remove("wangwu");
        System.out.println("是否存在王五:" + cbf.contains("wangwu")); //false
    }
}

构建布隆过滤器前面 2 个参数一个就是期望的元素数,一个就是 fpp 值,后面的 countingBits 参数就是计数器占用的大小,这里传了一个 8 位,即最多允许 255 次重复,如果不传的话这里默认是 16 位大小,即允许 65535次重复。

建议使用Guava自带的布隆过滤器,直接传入预期的数据量以及fpp,它会自动帮我们计算数组长度和哈希次数

布隆过滤器应该设计为多大?

假设在布隆过滤器里面有 k 个哈希函数,m 个比特位(也就是位数组长度),以及 n 个已插入元素,错误率会近似于 (1-ekn/m)k,所以你只需要先确定可能插入的数据集的容量大小 n,然后再调整 k 和 m 来为你的应用配置过滤器。

布隆过滤器应该使用多少个哈希函数?

对于给定的 m(比特位个数)和 n(集合元素个数),最优的 k(哈希函数个数)值为: (m/n)ln(2)

布隆过滤器的时间复杂度和空间复杂度?

对于一个 m(比特位个数)和 k(哈希函数个数)值确定的布隆过滤器,添加和判断操作的时间复杂度都是 O(k),这意味着每次你想要插入一个元素或者查询一个元素是否在集合中,只需要使用 k 个哈希函数对该元素求值,然后将对应的比特位标记或者检查对应的比特位即可。

Guava的布隆过滤器的实现

Guava有自带的布隆过滤器的实现

public class BloomFilterTest {
    public static void main(String[] args) {
        long star = System.currentTimeMillis();
        BloomFilter<Integer> filter = BloomFilter.create(
                Funnels.integerFunnel(),
                //预计存放多少数据
                10000000,
                //可以接受的误报率
                0.01);
        for (int i = 0; i < 10000000; i++) {
            filter.put(i);
        }
        Assert.isTrue(filter.mightContain(1),"不存在");
        Assert.isTrue(filter.mightContain(2),"不存在");
        Assert.isTrue(filter.mightContain(3),"不存在");
        Assert.isTrue(filter.mightContain(10000000),"不存在");
        long end = System.currentTimeMillis();
        System.out.println("执行时间:" + (end - star));
    }
}

BitMap

BitMap不会存在误判的情况,位图也是布隆过滤器的实现,但是占用内存空间随集合内最大元素的增大而增大。而布隆过滤器,因为其可能一个bit为多个元素作标识,这就保证了它的空间利用率。这2种方式根据业务进行选择。

以32位整型为例,它可以表示数字的个数为2^32. 可以申请一个位图,让每个整数对应的位图中的一个bit,这样2^32个数需要的位图的大小为512MB。具体实现的思路为:申请一个512MB的位图,并把所有的位都初始化为0;接着遍历所有的整数,对遍历到的数字,把相应的位置上的bit设置为1.最后判断待查找的数对应的位图上的值是多少,如果是0,那么表示这个数字不存在,如果是1,那么表示这个数字存在。


Java中有BitMap的实现类,BitSet

public class BitMapTest {
        public static void main(String[] args) {
                int[] array = {3, 8, 5, 7, 1};
                BitSet bitSet = new BitSet(5);
                for (int i = 0; i < array.length; i++) {
                        bitSet.set(array, true);
                }
                bitSet.stream().forEach(e -> System.out.println(e));
        }
}
相关实践学习
基于MaxCompute的热门话题分析
本实验围绕社交用户发布的文章做了详尽的分析,通过分析能得到用户群体年龄分布,性别分布,地理位置分布,以及热门话题的热度。
SaaS 模式云数据仓库必修课
本课程由阿里云开发者社区和阿里云大数据团队共同出品,是SaaS模式云原生数据仓库领导者MaxCompute核心课程。本课程由阿里云资深产品和技术专家们从概念到方法,从场景到实践,体系化的将阿里巴巴飞天大数据平台10多年的经过验证的方法与实践深入浅出的讲给开发者们。帮助大数据开发者快速了解并掌握SaaS模式的云原生的数据仓库,助力开发者学习了解先进的技术栈,并能在实际业务中敏捷的进行大数据分析,赋能企业业务。 通过本课程可以了解SaaS模式云原生数据仓库领导者MaxCompute核心功能及典型适用场景,可应用MaxCompute实现数仓搭建,快速进行大数据分析。适合大数据工程师、大数据分析师 大量数据需要处理、存储和管理,需要搭建数据仓库?学它! 没有足够人员和经验来运维大数据平台,不想自建IDC买机器,需要免运维的大数据平台?会SQL就等于会大数据?学它! 想知道大数据用得对不对,想用更少的钱得到持续演进的数仓能力?获得极致弹性的计算资源和更好的性能,以及持续保护数据安全的生产环境?学它! 想要获得灵活的分析能力,快速洞察数据规律特征?想要兼得数据湖的灵活性与数据仓库的成长性?学它! 出品人:阿里云大数据产品及研发团队专家 产品 MaxCompute 官网 https://www.aliyun.com/product/odps&nbsp;
目录
相关文章
|
1月前
|
存储 机器学习/深度学习 分布式计算
大数据技术——解锁数据的力量,引领未来趋势
【10月更文挑战第5天】大数据技术——解锁数据的力量,引领未来趋势
|
12天前
|
存储 分布式计算 数据挖掘
数据架构 ODPS 是什么?
数据架构 ODPS 是什么?
102 7
|
12天前
|
存储 分布式计算 大数据
大数据 优化数据读取
【11月更文挑战第4天】
27 2
|
25天前
|
数据采集 监控 数据管理
数据治理之道:大数据平台的搭建与数据质量管理
【10月更文挑战第26天】随着信息技术的发展,数据成为企业核心资源。本文探讨大数据平台的搭建与数据质量管理,包括选择合适架构、数据处理与分析能力、数据质量标准与监控机制、数据清洗与校验及元数据管理,为企业数据治理提供参考。
68 1
|
1月前
|
分布式计算 关系型数据库 MySQL
大数据-88 Spark 集群 案例学习 Spark Scala 案例 SuperWordCount 计算结果数据写入MySQL
大数据-88 Spark 集群 案例学习 Spark Scala 案例 SuperWordCount 计算结果数据写入MySQL
50 3
|
9天前
|
存储 大数据 数据管理
大数据分区简化数据维护
大数据分区简化数据维护
17 4
|
19天前
|
存储 大数据 定位技术
大数据 数据索引技术
【10月更文挑战第26天】
41 3
|
19天前
|
存储 大数据 OLAP
大数据数据分区技术
【10月更文挑战第26天】
52 2
|
22天前
|
消息中间件 分布式计算 大数据
数据为王:大数据处理与分析技术在企业决策中的力量
【10月更文挑战第29天】在信息爆炸的时代,大数据处理与分析技术为企业提供了前所未有的洞察力和决策支持。本文探讨了大数据技术在企业决策中的重要性和实际应用,包括数据的力量、实时分析、数据驱动的决策以及数据安全与隐私保护。通过这些技术,企业能够从海量数据中提取有价值的信息,预测市场趋势,优化业务流程,从而在竞争中占据优势。
67 2
|
24天前
|
数据采集 分布式计算 大数据
数据治理之道:大数据平台的搭建与数据质量管理
【10月更文挑战第27天】在数字化时代,数据治理对于确保数据资产的保值增值至关重要。本文探讨了大数据平台的搭建和数据质量管理的重要性及实践方法。大数据平台应包括数据存储、处理、分析和展示等功能,常用工具如Hadoop、Apache Spark和Flink。数据质量管理则涉及数据的准确性、一致性和完整性,通过建立数据质量评估和监控体系,确保数据分析结果的可靠性。企业应设立数据治理委员会,投资相关工具和技术,提升数据治理的效率和效果。
55 2
下一篇
无影云桌面