面试官:如何在海量数据中判断某个数据是否存在?

吃苹果的上帝 2020-01-16 17:15:44 ⋅ 978 阅读

https://www.toutiao.com/a6756788128960217604

这是一道面试题:如何在海量数据(如亿级数据)中判断某个数据是否存在?

回想一下,在java中我们可以使用列表、集合等数据结构来存放数据,如hashmap,然后判断某个数据是否存在,但在此问题中显然不适用,因为上亿的数据在内存较小的计算机中无法存放。

通常我们有以下解决思路:

  1. 将海量数据分散存储到多个文件中去,依次将每个文件载入内存进行判定;

  2. 使用多台机器进行分布式计算,每台机器完成各自任务;

  3. 使用布隆过滤器(Bloom Filter)。

本篇主要介绍第三种方法:布隆过滤器 。

我们先熟悉一下 位图 的概念。

位图也叫 位数组 , 可以看成 是一个数组,每个 数组 单元只 存储“0 ”或者“1”,每个 单元 大小为 1bit 。


正是因为位图所需内存较小,所以这里可派上用场。

上文说了,位图存放的是0和1,那么怎么和实际数据对应起来呢?很自然能想到使用 哈希函数 。


如图,将人名存进位图时,可使用hash函数,将人名映射到对应的位图单元中,并将该单元数值置为1,0则代表没有数据映射到该单元,即该单元没有存放数据。

然而 hash冲突 是不可避免的,图中可看到“潘金莲”和“武松”散列到了同一个数组单元。这就出现了一个问题:假如我们要存储的数据中有“潘金莲”,没有“武松”,当我们对“武松”进行哈希后发现其对应位置为1,于是认为“武松”存在于该数据集中,显然这个结果是错误的,因为1是潘金莲的映射结果。

那么怎么解决这个问题呢?因为hash冲突不可避免,所以我们只能尽量减少冲突的发生。

一般有两种思路:

  1. 对位图扩容,使用容量更大的位图;

  2. rehash。

事实上,大名鼎鼎的 布隆过滤器(Bloom Filter) 使用的便是这两种思路。看下百度百科给出的定义。

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

简单而言,布隆过滤器就是 位图+一系列随机映射函数 。


如上图,使用了三个互相独立的hash函数,对每条数据都进行三次哈希,并将对应单元置为1.

这样能减少hash冲突的发生,当然hash函数的个数以及位图的容量是视情况而定的。

布隆过滤器的优点:

1.每个单元只占1bit , 所用空间小;

2.使用哈希直接查找 , 查询时间短 。

布隆过滤器的 缺点:

1.由于hash冲突的存在 ,有一定的 误判率 ;

2.由于hash冲突的存在 , 删除数据较为困难 。

先看误判率。


其实与刚才“武松和潘金莲”的问题类似:假设“吴用”并不在数据集中,但它的位置已被其它数据置为1,那么判定结果会错误。

但如果“吴用”对应的某个位置为0,那么“吴用”必定不存在,因为如果存在,与其对应的所有位置都为1.

由此可得下面两条结论:

布隆过滤器判断数据存在,那么它可能存在也可能不存在 。

布隆过滤器判断数据不存在,那么它必定不存在。

再看删除数据。

这个也好理解,举个栗子。


“吴用”和“宋江”都映射到④号位置,现在想要删除“吴用”,那么④号位置到底要不要置为0呢?如果置为0,那么“宋江”就不高兴了,如果不变,显然又会增加对“吴用”的误判率(已经被删除,但该位置还是1)。

在后来的改进中,对位图的每个单元增加了 计数器 ,计数器初始值为0,每映射一个数据,计数器加1,每删除一个数据,计数器减1。这样在删除数据时,只要计数器 当前值 大于1,该单元就不置为0.

布隆过滤器的应用场景有很多,典型的有Redis的缓存穿透、爬虫时URL去重、垃圾邮件的判别等。





全部评论: 0

    我有话说:

    数据结构

    结构,简单的理解就是关系。严格点说,结构是指各个组成部分相互搭配和排列的方式。现实世界,不同数据元素之间不是独立的,而是存在特定的关系,我们将这些关系成为结构。 数据结构:是相互之间存在一种

    SQL判断是否"存在",还用 count 操作?

    来源:http://toutiao.com/i6826511837840802315 根据某一条件从数据库查询 『有』与『没有』,只有两种状态,那为什么写SQL的时候,还要SELECT

    面试如何设计数据库秒级平滑扩容架构?

    该方案能够实现n库扩2n库的秒级、平滑扩容,增加数据库服务能力,降低单库一半的数据量,其核心原理是:成倍扩容,避免数据迁移。

    推荐一款前端数据源管理工具 algeb

    ALGEB 简介 这是一个比较抽象的库,一开始可能比较难理解。我写它的初衷,是创建可响应的数据请求管理。传统数据请求,我们只是把携带ajax代码的一堆函数放一起,这样就可以调用接口。但是这种

    反向面试

      你可以反问面试的问题 内容来源:https://github.com/yifeikong/reverse-interview-zh 大部分翻译自:https://github

    您应该避免的五个简单的数据库设计错误

    Anith 他非常成功的文章 Facts and Fallacies about First Normal Form 之后,对五个常见的数据库设计错误进行了引人入胜的讨论,尽管使用它们的不幸后果

    线性表 - 栈与队列

    1.栈 1.栈(stack)是限定仅表尾进行插入和删除操作的线性表,(先进后出) 2.我们把允许插入和删除的一端成为栈顶(top) 另一端称为栈底(bottom),不含任何数据元素的栈称为空栈

    Dgraph 1.2.8 发布,事务性分布式图形数据库

    Dgraph 1.2.8 发布了。Dgraph 是一个可扩展的,分布式的,低延迟的图数据库,目标是提供 Google 生产水平的规模和吞吐量,超过 TB 的结构数据里,为用户提供足够低延迟的实时

    Redis面试整理:Redis几种数据类型的用法和应用场景重新梳理了一下

    1、字符串 1.1 介绍 string 字符串类型是Redis最为常用和基础的存储类型,是一个由字节组成的序列,他Redis是二进制安全的,也可以认为string字符串数据类型能够接收任何格式

    搞对数据库连接池,这次从100优化到3ms!阿里架构师都说好

    研究HikariCP(一个数据库连接池)时无意间HikariCP的Github wiki上看到了一篇文章(即前面给出的链接),这篇文章有力地消除了我一直以来的疑虑,看完之后感觉神清气爽。故

    【实战解析】基于HBase的大数据存储京东的应用场景

    作者就职于京东商城京麦平台组,从事京东商家开放平台的相关开发工作。热爱技术,熟悉各种常用开源框架,有丰富的大型分布式系统、高并发系统的开发经验。热衷于对大数据的研究,对Hadoop、HBase以及

    为什么说作为程序员分库分表的必要性一定要掌握?

      互联网大厂程序员必须掌握海量数据和高并发问题处理技能,期望进入大厂的程序员一定要仔细看这篇! MySQL 分库分表是做什么的? 相信很多程序员对 MySQL 都比较熟悉了,目前国内

    服务化改造实践 | 如何 Dubbo 支持 REST

    随着微服务的流行以及多语言互操作诉求的日益增多, Dubbo 暴露 REST 服务变成了一个不容忽视的诉求。

    「轻阅读」亿级用户的分布式数据存储解决方案

    分布式数据库和分布式存储是分布式系统难度最大、挑战最大,也是最容易出问题的地方。互联网公司只有解决分布式数据存储的问题,才能支撑更多次亿级用户的涌入。

    Redis系列九 推荐系统-布隆过滤器

      布隆过滤器 概念 布隆过滤器是一种空间利用率较高的概率型数据结构,用来测试一个元素是否集合。但是存在一定可能,导致结果误判。当布隆过滤器说某个存在时,这个值可能不存在;当它说不

    Logstash 7.9.2 发布,开源服务端数据处理流程

    Logstash 是开源的服务器端数据处理管道,能够同时从多个来源采集数据,转换数据,然后将数据发送到你最喜欢的“存储库”。目前,Logstash 7.9.2 已正式发布,该版本更新内容如下

    Fluid 0.3 正式发布:实现云原生场景通用化数据加速

    简介 为了解决大数据、AI 等数据密集型应用云原生计算存储分离场景下,存在数据访问延时高、联合分析难、多维管理杂等痛点问题,南京大学 PASALab、阿里巴巴、Alluxio 2020 年

    DDDplus 1.0.2 发布,轻量级业务台开发框架

    DDDplus 简介 一套轻量级业务台开发框架,以DDD思想为本,致力于业务资产的可沉淀可传承,全方位解决复杂业务场景的扩展问题,实现台核心要素,赋能台建设。 融合了前台复杂生态协作方法论