海量数据的处理

一 背景

所谓海量数据处理,无非就是基于海量数据上的存储、处理、操作。何谓海量,就是数据量太大,所以导致要么是无法在较短时间内迅速解决,要么是数据太大,导致无法一次性装入内存。

针对时间,我们可以采用巧妙的算法搭配合适的数据结构,如Bloom filter/Hash/bit-map/堆/trie树。

针对空间,无非就一个办法:大而化小,分而治之(hash映射)。

二 数据结构

BitMap
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(1)布隆过滤器、BItMap
如果一个数据不再布隆过滤器里面,则一定不存在。
如果一个数组判断在布隆过滤器里面,不一定不存在。
在这里插入图片描述
(2)堆
堆是一种特殊的二叉树,具备以下两种性质 1)每个节点的值都大于(或者都小于,称为最小堆)其子节点的值 2)树是完全平衡的,并且最后一层的树叶都在最左边这样就定义了一个最大堆。 如下图用一个数组来表示堆:

在这里插入图片描述
(3) trie树t
从上面的图中,我们或多或少的可以发现一些好玩的特性。
第一:根节点不包含字符,除根节点外的每一个子节点都包含一个字符。
第二:从根节点到某一节点,路径上经过的字符连接起来,就是该节点对应的字符串。
第三:每个单词的公共前缀作为一个字符节点保存。
适用范围:
前缀统计,词频统计。
外部排序
大数据的排序,去重

** 基本原理及要点:**

外部排序的两个独立阶段:
1)首先按内存大小,将外存上含n个记录的文件分成若干长度L的子文件或段。依次读入内存并利用有效的内部排序对他们进行排序,并将排序后得到的有序字文件重新写入外存,通常称这些子文件为归并段。
2)对这些归并段进行逐趟归并,使归并段逐渐由小到大,直至得到整个有序文件为之。
外排序的优化方法:置换选择 败者树原理,最优归并树。

三 具体面试题

海量日志数据,提取出某日访问百度次数最多的那个IPIP地址最多有2^32=4G种取值情况,所以不能完全加载到内存中处理;

1、可以考虑采用“分而治之”的思想,按照IP地址的Hash(IP)%1024值,把海量IP日志分别存储到1024个小文件中。这样,每个小文件最多包含4MB个IP地址;
2、对于每一个小文件,可以构建一个IP为key,出现次数为value的Hash map,同时记录当前出现次数最多的那个IP地址;
3、可以得到1024个小文件中的出现次数最多的IP,再依据常规的排序算法得到总体上出现次数最多的IP;

搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节。假设目前有一千万个记录(这些查询串的重复度比较高,虽然总数是1千万,但如果除去重复后,不超过3百万个。一个查询串的重复度越高,说明查询它的用户越多,也就是越热门。),请你统计最热门的10个查询串,要求使用的内存不能超过1G。

可以在内存中处理,典型的Top K算法

算法思想:hashmap+堆

先对这批海量数据预处理,在O(N)的时间内用Hash表完成统计;
借助堆这个数据结构,找出Top K,时间复杂度为O(N*logK)。
或者:采用trie树,关键字域存该查询串出现的次数,没有出现为0。最后用10个元素的最小堆来对出现频率进行排序。

有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M。返回频数最高的100个词。

算法思想:分而治之 + hash统计 + 堆排序

顺序读文件中,对于每个词x,取hash(x)%5000,然后按照该值存到5000个小文件(记为x0,x1,…x4999)中。这样每个文件大概是200k左右。如果其中的有的文件超过了1M大小,还可以按照类似的方法继续往下分,直到分解得到的小文件的大小都不超过1M。

对每个小文件,采用trie树/hash_map等统计每个文件中出现的词以及相应的频率。

取出出现频率最大的100个词(可以用含100个结点的最小堆)后,再把100个词及相应的频率存入文件,这样又得到了5000个文件。最后就是把这5000个文件进行归并(类似于归并排序)的过程了。

有10个文件,每个文件1G,每个文件的每一行存放的都是用户的query,每个文件的query都可能重复。要求你按照query的频度排序。

方案1:

算法思想:分而治之 + hash统计 + 堆排序

顺序读取10个文件,按照hash(query)%10的结果将query写入到另外10个文件中。这样新生成的文件每个的大小大约也1G,大于1G继续按照上述思路分。

找一台内存在2G左右的机器,依次对用hash_map(query, query_count)来统计每个query出现的次数。利用快速/堆/归并排序按照出现次数进行排序。将排序好的query和对应的query_cout输出到文件中。这样得到了10个排好序的文件(记为)。

对这10个文件进行归并排序(内排序与外排序相结合)。
方案2:
算法思想:hashmap+堆

一般query的总量是有限的,只是重复的次数比较多而已,可能对于所有的query,一次性就可以加入到内存了。这样,我们就可以采用trie树/hash_map等直接来统计每个query出现的次数,然后按出现次数做快速/堆/归并排序就可以了。

在2.5亿个整数中找出不重复的整数,注,内存不足以容纳这2.5亿个整数。

采用2-Bitmap(每个数分配2bit,00表示不存在,01表示出现一次,10表示多次,11无意义)进行,共需内存2^32 * 2 bit=1 GB内存,还可以接受。然后扫描这2.5亿个整数,查看Bitmap中相对应位,如果是00变01,01变10,10保持不变。所描完事后,查看bitmap,把对应位是01的整数输出即可。

给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何快速判断这个数是否在那40亿个数当中?

方案1:申请512M的内存,一个bit位代表一个unsigned int值。读入40亿个数,设置相应的bit位,读入要查询的数,查看相应bit位是否为1,为1表示存在,为0表示不存在。

方案2:因为2^32为40亿多,所以给定一个数可能在,也可能不在其中;这里我们把40亿个数中的每一个用32位的二进制来表示假设这40亿个数开始放在一个文件中。

然后将这40亿个数分成两类: 1.最高位为0 2.最高位为1 并将这两类分别写入到两个文件中,其中一个文件中数的个数<=20亿,而另一个>=20亿(这相当于折半了); 与要查找的数的最高位比较并接着进入相应的文件再查找

再然后把这个文件为又分成两类: 1.次最高位为0 2.次最高位为1

并将这两类分别写入到两个文件中,其中一个文件中数的个数<=10亿,而另一个>=10亿(这相当于折半了); 与要查找的数的次最高位比较并接着进入相应的文件再查找。 ……. 以此类推,就可以找到了。

解决问题的一般步骤

3.1 计算容量

  • 1 byte = 8 bit
  • 1 KB = 1024 byte
    1 个整数占 4 byte,1 亿个整数占 4*108 byte ≈ 400 MB。

3.2 拆分

可以将海量数据拆分到多台机器上和拆分到多个文件上:

  • 如果数据量很大,无法放在一台机器上,就将数据拆分到多台机器上。这种方式可以让多台机器一起合作,从而使得问题的求解更加快速。但是也会导致系统更加复杂,而且需要考虑系统故障等问题;
  • 如果在程序运行时无法直接加载一个大文件到内存中,就将大文件拆分成小文件,分别对每个小文件进行求解。

有以下策略进行拆分:

  • 按出现的顺序拆分:当有新数据到达时,先放进当前机器,填满之后再将数据放到新增的机器上。这种方法的优点是充分利用系统的资源,因为每台机器都会尽可能被填满。缺点是需要一个查找表来保存数据到机器的映射,查找表可能会非常复杂并且非常大。
    在这里插入图片描述

  • 按散列值拆分:选取数据的主键 key,然后通过哈希取模 hash(key)%N 得到该数据应该拆分到的机器编号,其中 N 是机器的数量。优点是不需要使用查找表,缺点是可能会导致一台机器存储的数据过多,甚至超出它的最大容量。
    在这里插入图片描述

  • 按数据的实际含义拆分:例如一个社交网站系统,来自同一个地区的用户更有可能成为朋友,如果让同一个地区的用户尽可能存储在同一个机器上,那么在查找一个用户的好友信息时,就可以避免到多台机器上查找,从而降低延迟。缺点同样是需要使用查找表。
    在这里插入图片描述

3.3 整合

拆分之后的结果还只是局部结果,需要将局部结果汇总为整体的结果。

4、海量数据去重问题

4.1 问题描述

对于海量数据,要求判断一个数据是否已经存在。这个数据很有可能是字符串,例如 URL。

4.2 基本的数据结构

(1) HashSet

考虑到数据是海量的,那么就需要使用拆分的方式将数据拆分到多台机器上,分别在每台机器上使用 HashSet 存储。我们需要使得相同的数据拆分到相同的机器上,可以使用哈希取模的拆分方式进行实现。
(2) BitSet
如果海量数据是整数,并且范围不大时,就可以使用 BitSet 存储。通过构建一定大小的比特数组,并且让每个整数都映射到这个比特数组上,就可以很容易地知道某个整数是否已经存在。因为比特数组比整型数组小的多,所以通常情况下单机就能处理海量数据。

class BitSet {
    int[] bitset;
    
    public BitSet(int size) {
        bitset = new int[(size >> 5) + 1]; // divide by 32
    }
    
    boolean get(int pos) {
        int wordNumber = (pos >> 5); // divide by 32
        int bitNumber = (pos & 0x1F); // mod 32
        return (bitset[wordNumber] & (1 << bitNumber)) != 0;
    }
    
    void set(int pos) {
        int wordNumber = (pos >> 5); // divide by 32
        int bitNumber = (pos & 0x1F); // mod 32
        bitset[wordNumber] |= 1 << bitNumber;
    }

(3) 布隆过滤器

布隆过滤器也是使用 BitSet 存储数据,但是它进行了一定的改进,从而解除了 BitSet 要求数据的范围不大的限制。在存储时,它要求数据先经过 k 个哈希函得到 k 个位置,并将 BitSet 中对应位置设置为 1。在查找时,也需要先经过 k 个哈希函数得到 k 个位置,如果所有位置上都为 1,那么表示这个数据存在。

布隆过滤器会误判,也就是将一个不存在的数判断为已经存在,这会造成一定的问题。例如在垃圾邮件过滤系统中,会将一个邮件误判为垃圾邮件,那么就收不到这个邮件。可以使用白名单的方式进行补救。

(4) 前缀树(Trie)

4.3 求文件A中没有但B中有的单词(字典树)

  • 遍历文件A,将文件hash到n个小文件中
  • 对B文件同样操作
  • 然后对于每一对文件,进行hash操作

4.4 海量数据排序问题

  • hash到小文件中,然后在小文件排序。然后合并的时候,用堆,每个小文件取一个,然后最小的拿走再加入对应文件的数字,直到结束。

  • 如果要求文件IO次数尽量少,比如:一个文件中20亿个int,有重复但不超过10000个,排序后输出到另一个文件(要求减少文件IO)

4.5 40亿整数,再给一个新数字,判断是否在40亿当中

  • 分布式机器,多台机器一起查找并合并
  • bitmap,注意不是40亿个数字就要40亿个位,而是都是整数,所以覆盖所有整数范围就是232大概42亿,所以需要申请232个位,一个int8个位,所以需要2^29个int,占用500M内存

10亿个数值,找最大的一万个?

应该计算一下这个数组整体大小,然后询问数据是否重复,如果重复,先对文件hash,然后保存不同文件。维持一个1万的小顶堆,遍历效率是o(nlogn)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Spring Batch 是一个用于批处理海量数据的开源框架。它提供了一种简单且灵活的方式来处理大量的数据,帮助开发人员根据自定义的规则和逻辑进行批量处理任务。 在处理海量数据时,Spring Batch 提供了以下特性: 1. 分批处理:Spring Batch 可以将大数据集分成多个小批次进行处理,避免一次性加载全部数据,降低了内存的压力。 2. 事务管理:Spring Batch 支持事务管理,可以保证数据的一致性和完整性,确保批处理任务的可靠性。 3. 异常处理:Spring Batch 提供了灵活的异常处理机制,可以捕捉并处理异常,保证任务的顺利执行。 4. 监控和报告:Spring Batch 提供了可视化的监控和报告功能,可以实时查看任务的执行进度和状态,方便开发人员进行调试和排错。 5. 多线程处理:Spring Batch 支持多线程处理数据,可以并发执行多个任务,提高数据处理的效率。 6. 可扩展性:Spring Batch 提供了丰富的扩展点和接口,可以根据业务需求进行定制和扩展,实现个性化的数据处理逻辑。 总之,Spring Batch 是一个强大的批处理框架,它能够帮助开发人员高效地处理海量数据,具有良好的可靠性、可扩展性和灵活性,是处理大规模数据任务的不错选择。 ### 回答2: Spring Batch是一个用于大规模数据处理的开源框架。它提供了一种有效的方式来处理海量数据,以实现批处理任务的分解和并发执行。 首先,Spring Batch提供了丰富的组件来管理和控制批处理任务。这些组件包括job、step、tasklet和chunk等,它们可以帮助我们定义和配置批处理任务的各个环节,从而使得海量数据处理变得更加可控和可管理。 其次,Spring Batch提供了高效的数据处理机制。它采用了读-处理-写的模式来处理数据,可以将输入数据进行分块读取,并通过多线程、多进程或分布式集群的方式进行并发处理,再将处理结果进行批量写入。这样可以大大提高数据处理的效率和吞吐量,适应海量数据处理需求。 此外,Spring Batch还提供了一系列的错误处理和容错机制。对于处理过程中可能出现的错误或异常,Spring Batch可以捕获并记录,然后根据配置的策略进行重试或跳过等处理。这样可以保证批处理任务的数据完整性和可靠性,防止数据丢失或处理中断导致的问题。 总之,Spring Batch是一个非常适合处理海量数据的框架。它可以帮助我们高效地处理大量数据,并提供了灵活的批处理任务管理和容错机制,从而满足海量数据处理的需求。 ### 回答3: Spring Batch 是一个Java框架,用于处理海量数据的批处理任务。它提供了一套强大的工具和功能,可以有效地处理大量的数据,并且具有良好的可扩展性和可维护性。 在处理海量数据时,Spring Batch 提供了以下功能和优势: 1. 分批处理:Spring Batch 可以将海量数据分为多个小批次进行处理,每次处理一批数据,以降低内存和CPU的使用量。这种方式可以提高整体的性能和效率,并且可以更好地管理资源。 2. 事务管理:Spring Batch 提供了事务管理机制,确保数据处理的原子性和一致性。即使在处理过程中出现错误或异常,Spring Batch 也可以回滚事务,保证数据的完整性。 3. 多线程处理:Spring Batch 支持多线程处理,可以同时处理多个批次的数据。通过合理的线程配置,可以更好地利用多核处理器的性能,并且可以并行处理不同的数据批次,提高整体的处理速度。 4. 容错和错误处理:Spring Batch 提供了强大的容错和错误处理机制。它可以记录和重试失败的任务,并且可以自定义错误处理策略。这样可以有效地处理异常情况,并且可以保证数据的准确性和完整性。 5. 可扩展性和可维护性:Spring Batch 使用了模块化的架构,提供了丰富的可重用组件和扩展点。这样可以更好地实现代码的可维护性和可扩展性,方便开发人员进行定制化开发和集成其他系统。 总之,Spring Batch 是一个功能强大的框架,适用于处理海量数据的批处理任务。它可以提高处理效率和性能,并且具有良好的可扩展性和可维护性,非常适合处理大量的数据

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值