个人觉得这个是一个求职者的弱项,因为学生确实很少能接触到这类问题,但同时,面试官又爱考这类题
针对海量数据,常见的方法有:哈希法,位图法,布隆过滤器法,数据库优化法,倒排索引法,外部排序法,Trie树,堆,双层桶排序法,以及使用mapreduce
哈希法
哈希表主要的优势时O(1)的查找,由于其存储顺序基本无须,所以其存储的消耗时间不会随数据规模变大而变长,但hash存取会出现冲突的情况,因此也未必适合海量数据
位图法
顾名思义,位图法就是用一位表示一个数据。这样就需要我们提前知道数据的范围,比如数据范围是1~10,我们就申请10位的空间,数据的范围是1~,,我们就申请一千位的空间。
位图法主要使用范围是排序O(N)和查重O(N),相对于其他的排序,位图法速度很快,但本质上还是属于空间换取时间,因此在数据分布上不宜稀疏,这样无疑性价比时很低的
布鲁过滤法
属于上面两个方法的合一,定义m位数组,以及n种不同的hash函数。添加一个数据时,先用n种不同的hash函数求得n个1(这n个未必互不相同),将数组的n个位置都置为1,当查找数组是否有数据p时,若hash的n个结果位置不都为1,则一定不存在该数据p。
综上,该方法虽然在节省一定空间的同时,也牺牲了准确率,这里的准确率是指查找时只有不存在这个结果是一定准确的。
另:哈希函数个数时错误率最少,约等于,CBF与SBF是基于此的拓展,CBF将位数组的每一个位扩展为一个counter,支持删除操作,SBF则采用counter的最小值近似表示元素的出现频率。
数据库优化法
常见优化思路
- 数据分区
- 索引
- 缓存机制
- 虚拟存储
- 分批处理
- 使用临时表和中间表
- 优化查询语句
- 使用视图
- 使用存储过程
- 用排序代替非排序存取
- 使用采样数据进行数据挖掘
倒排索引
在搜索引擎实际的引用中,有时需要按照关键字的某些值查找记录,所以是按照关键字建立索引,这就是倒排索引
倒排索引具有两种形式
- 一条记录的水平反向索引包含每个引用单词的文档的列表
- 一个单词的水平反向索引又包含每个单词在一个文档中的位置 第二种提供了更多的兼容性,但也需要更多的时间与空间
相对于正向索引这种更适合用于全文查询的索引形式,由于反向索引是单词指向了包含该单词的文档,因此可以在多关键词时,在表中先完成查询的并、交等逻辑运算,在对记录进行存取,提高查找速度
外排序
外排序是相对内排序而言,将待排序的记录存储在外存储器上,待排序的文件无法一次装入内存,需要内存和外部存储器多次进行数据交换。一般采用归并排序等方式实现外部排序。
归并排序:
- 将数据分为n个数据段,并对每个数据段进行段内排序
- 将数据段两两多次归并,最后使文件有序
Trie树
又叫字典树,通过利用字符串的公共前缀,大幅度节省空间和时间,主要用于统计,保存大量的字符串。 我最近会出一期字典树的算法学习
- 根节点不包含字符串,除了根节点外每个节点都只包含一个字符
- 从根节点到某一个节点(要是尾节点才可以),路径上经过的字符连接起来,为该节点对应的字符串
- 节点维护一个整数,若为0或者初始化,则说明这不是尾节点,否则表示有几个字符串将其设为尾节点
堆
堆是树形结构,因此内部是无序的,但是父节点一定大于子节点(大根堆),或者子节点一定大于父节点(小根堆)。从这种结构,我们能猜出堆擅长找最值。而使用双堆,我们可以找到中位数。
桶排序
桶排序其实就是经典的分而治之的思想,根据数据范围和数据个数,将数据分为几个桶,然后桶内进行排序,再在桶间排序
另,一般在关键字分布范围比较小的情况下排序,否则桶的个数 会太多,浪费资源
MapReduce方法
MapReduce是一种简化并行计算的分布式编程模型,主要目的为了大型集群的系统能在大数据集上进行并行工作,并用于大规模数据的并行运算。在架构中,MapReduce API 提供 Map 和 Reduce 处理,GFS 分布式文件系统和 BigTable 分布式数据库提供数据存取。
MapReduce分为map和reduce,map是数据一对一的进行转换,reduce是将多个数据规约成为一个数据,比如求和,求积等。
接下来是一些常见问题类型
TopK类问题
取最大的k个数、频率最高的k个数,热搜榜单,最热门查询词等...
通常比较好的方案是【分治 + trie树/hash + 小顶堆】: 先将数据集按照hash方法分为多个小数据集,然后使用trie树或者hash统计每个小数据集中的搜索词频,之后用小顶堆求出每个数据集中频率最高的k个数,最后合并。
- 局部淘汰法,始终维持一个大小为k的数组
- 分治法
- hash法去重
- 采用小顶堆
当然了具体问题具体分析,我们对该问题进一步进行细分
单机单核大内存
那就说明数据不够海量
单机多核大内存
使用hash方法将数据划分为n份,每份交给一个线程处理,最后使用一个线程将结果归并。
该方法存在一个瓶颈会明显影响效率,即数据倾斜,每个线程的处理速度可能不同,快的线程的效率被慢的线程所掩盖,解决方法是进一步划分区域,每个线程完成当前小分区的操作后,领取下一个小分区。
单机单核小内存
将数据切割成小文件
欸你这个和上一个没差啊,其实上一个划分是为了并行,这一个属于无奈。
多机小内存
将数据分发到多台机器上[hash + socket],每个机器采用单机单核小内存解决。
TOPK问题很适合用MapReduce解决,用户只需编写一个map函数和两个reduce函数,然后提交到Hadoop(采用mapchain和reducechain)上即可解决问题,map负责将hash值相同的数据交给同一个reduce task,第一个reduce统计每个词出现的频率,第二个词统计所有reduce task输出数据中的top k。
重复问题
采用位图法 那么问题来了,一位只有两种可能:0或1,对应到状态也是只有没出现过和出现过两种可能
所以我们选择用两位表示一个数据
排序问题
-
数据库排序法
-
分治法
-
位图法