Java如何实现海量数据判重

 更新时间:2023年09月19日 09:16:00   作者:Java中文社群  
在海量数据如何确定一个值是否存在?这是一道非常经典的面试场景题,那怎么回答这个问题呢?下面小编就来和大家详细的聊一聊,感兴趣的可以一起学习一下

在海量数据如何确定一个值是否存在?这是一道非常经典的面试场景题。

那怎么回答这个问题呢?接下来咱们就详细的聊一聊。

参考答案

判断一个值是否存在?通常有以下两种解决方案:

  • 使用哈希表:可以将数据进行哈希操作,将数据存储在相应的桶中。查询时,根据哈希值定位到对应的桶,然后在桶内进行查找。这种方法的时间复杂度为 O(1),但需要额外的存储空间来存储哈希表。如果桶中存在数据,则说明此值已存在,否则说明未存在。
  • 使用布隆过滤器:布隆过滤器是一种概率型数据结构,用于判断一个元素是否在集合中。它利用多个哈希函数映射数据到一个位数组,并将对应位置置为 1。查询时,只需要对待查询的数据进行哈希,并判断对应的位是否都为 1。如果都为 1,则该数据可能存在;如果有一个位不为 1,则该数据一定不存在。布隆过滤器的查询时间复杂度为 O(k),其中 k 为哈希函数的个数。

相同点和不同点

它们两的相同点是:它们都存在误判的情况。例如,使用哈希表时,不同元素的哈希值可能相同,所以这样就产生误判了;而布隆过滤器的特征是,当布隆过滤器说,某个数据存在时,这个数据可能不存在;当布隆过滤器说,某个数据不存在时,那么这个数据一定不存在。

它们两的区别主要有以下几点:

  • 存储机制:哈希表使用一个数组来存储键值对,通过哈希函数将键映射到数组的索引位置,然后将值存储在对应的位置上。而布隆过滤器则使用一个位数组(或位向量),通过多个哈希函数将元素映射到位数组的多个位上。
  • 查询操作:哈希表在进行查询时,通过计算哈希值来定位键值对的存储位置,然后直接获取对应的值。查询时间复杂度通常为 O(1)。布隆过滤器在进行查询时,也通过多个哈希函数计算多个位,然后判断对应的位是否都为 1 来确定元素是否存在。查询时间复杂度为 O(k),其中 k 为哈希函数的个数。
  • 内存占用:哈希表需要根据数据规模来动态调整数组的大小,以保证存储效率。而布隆过滤器在预先设置位数组的大小后,不会随数据规模的增加而增长。因此布隆过滤器更适用于海量数据。

结论

哈希表和布隆过滤器都能实现判重,但它们都会存在误判的情况,但布隆过滤器存储占用的空间更小,更适合海量数据的判重。

布隆过滤器实现原理

布隆过滤器的实现,主要依靠的是它数据结构中的一个位数组,每次存储键值的时候,不是直接把数据存储在数据结构中,因为这样太占空间了,它是利用几个不同的无偏哈希函数,把此元素的 hash 值均匀的存储在位数组中,也就是说,每次添加时会通过几个无偏哈希函数算出它的位置,把这些位置设置成 1 就完成了添加操作。

当进行元素判断时,查询此元素的几个哈希位置上的值是否为 1,如果全部为 1,则表示此值存在,如果有一个值为 0,则表示不存在。因为此位置是通过 hash 计算得来的,所以即使这个位置是 1,并不能确定是那个元素把它标识为 1 的,因此布隆过滤器查询此值存在时,此值不一定存在,但查询此值不存在时,此值一定不存在。

并且当位数组存储值比较稀疏的时候,查询的准确率越高,而当位数组存储的值越来越多时,误差也会增大。

位数组和 key 之间的关系,如下图所示:

如何实现布隆过滤器

布隆过滤器的实现通常有以下两种方案:

  • 通过程序实现(内存级别方案):使用 Google Guava 库和 Apache Commons 库实现布隆过滤器。
  • 通过中间件实现(支持数据持久化):使用 Redis 4.0 之后提供的布隆过滤插件来实现,它的好处是支持持久化,数据不会丢失。

Guava 实现布隆过滤器

使用 Google Guava 库实现布隆过滤器总共分为以下两步:

  • 引入 Guava 依赖
  • 使用 Guava API 操作布隆过滤器

具体实现如下。

① 引入 Guava 依赖

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
</dependency>

② 使用 Guava API

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
public class BloomFilterExample {
    public static void main(String[] args) {
        // 创建一个布隆过滤器,设置期望插入的数据量为10000,期望的误判率为0.01
        BloomFilter<String> bloomFilter = BloomFilter.create(Funnels.unencodedCharsFunnel(), 10000, 0.01);
        // 向布隆过滤器中插入数据
        bloomFilter.put("data1");
        bloomFilter.put("data2");
        bloomFilter.put("data3");
        // 查询元素是否存在于布隆过滤器中
        System.out.println(bloomFilter.mightContain("data1")); // true
        System.out.println(bloomFilter.mightContain("data4")); // false
    }
}

在上述示例中,我们通过 BloomFilter.create() 方法创建一个布隆过滤器,指定了元素序列化方式、期望插入的数据量和期望的误判率。然后,我们可以使用 put() 方法向布隆过滤器中插入数据,使用 mightContain() 方法来判断元素是否存在于布隆过滤器中。

小结

在海量数据如何确定一个值是否存在?通常有两种解决方案:哈希表和布隆过滤器,而它们两都存在误判的情况,但布隆过滤器更适合海量数据的判断,因为它占用的数据空间更小。布隆过滤器的特征是:当布隆过滤器说,某个数据存在时,这个数据可能不存在;当布隆过滤器说,某个数据不存在时,那么这个数据一定不存在。

到此这篇关于Java如何实现海量数据判重的文章就介绍到这了,更多相关Java数据判重内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java并发包JUC同步器框架AQS框架原文翻译

    java并发包JUC同步器框架AQS框架原文翻译

    发现了一篇JDK作者的论文《The java.util.concurrent Synchronizer Framework》主要描述了作者对AbstractQueuedSynchronizer同步器框架的设计和实现。权威性毋庸置疑!自然需要拜读一下,配上中文翻译,希望大家能有所收获
    2022-02-02
  • Flink作业Task运行源码解析

    Flink作业Task运行源码解析

    这篇文章主要为大家介绍了Flink作业Task运行源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • Java中内部类的概念与分类详解

    Java中内部类的概念与分类详解

    一个类的定义放在另一个类的内部,这个类就叫做内部类,下面这篇文章主要给大家介绍了关于Java中内部类的概念与分类的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2021-09-09
  • SpringBoot实现微信及QQ绑定登录的示例代码

    SpringBoot实现微信及QQ绑定登录的示例代码

    本文主要介绍了SpringBoot实现微信及QQ绑定登录的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • Java 超详细讲解ThreadLocal类的使用

    Java 超详细讲解ThreadLocal类的使用

    写SpringBoot项目的时候,经常用到的一个保存用户信息的类就是Threadlocal,我们今天就来详细介绍一下这个类,感兴趣的朋友来看看吧
    2022-04-04
  • Java中使用JWT生成Token进行接口鉴权实现方法

    Java中使用JWT生成Token进行接口鉴权实现方法

    这篇文章主要介绍了Java中使用JWT生成Token进行接口鉴权实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08
  • 详解Spring Boot 集成Shiro和CAS

    详解Spring Boot 集成Shiro和CAS

    这篇文章主要介绍了详解Spring Boot 集成Shiro和CAS,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • IDEA中的Run/Debug Configurations各项解读

    IDEA中的Run/Debug Configurations各项解读

    这篇文章主要介绍了IDEA中的Run/Debug Configurations各项解读,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • Windows环境使用bat脚本启动Java服务的过程

    Windows环境使用bat脚本启动Java服务的过程

    Java项目一般会被打包成jar后启动,在windows系统中可以通过终端窗口cmd启动jar包,即在jar包所在的目录中打开cmd,或在cmd中进入到jar包目录,这篇文章主要介绍了Windows环境使用bat脚本启动Java服务,需要的朋友可以参考下
    2023-08-08
  • Java Lambda表达式与引用类浅析

    Java Lambda表达式与引用类浅析

    Lambda表达式是Java SE8中一个重要的新特性,允许通过表达式来代替功能接口。本文将通过一些简单的示例和大家讲讲Lamda表达式的使用,感兴趣的可以了解一下
    2023-01-01

最新评论