[目录]
- 第一章:概述
- 第二章:整体数据分层
- 第三章:整体实现框架
- 第四章:元数据
- 第五章:ETL
- 第六章:数据校验
- 第七章:数据标准化
- 第八章:去重
- 第九章:增量/全量
- 第十章:拉链处理
- 第十一章:分布式处理增量
- 第十二章:列式存储
- 第十三章:逻辑数据模型(数仓模型)
- 第十四章:数据模型参考
- 第十五章:维模型
- 第十六章:渐变维
- 第十七章:数据回滚
- 第十八章:关于报表
- 第十九章:数据挖掘
数据仓库实践杂谈(八)——去重
数据重复是一个比较麻烦的事情。从正常逻辑上来看,如果应用系统和数据卸出的程序没问题,不应该存在这个问题。但实际情况来看,确又时有发生。一旦确定数据源的数据会有重复的可能,就需要专门进行去重处理。
在数据量很大的情况下,去重很耗时。所以如果可以,尽量先行优化数据源系统。
最直观的去重可能就是先把数据加载到数据库中,然后通过select distinct *,直接把重复的数据去掉。但一般来说这是个悲剧。这种操作如果无法在分布式体系下执行,将会非常慢。
从算法角度,去重的处理流程包括如下两个步骤:
- 先排序,需要对所有数据进行整体排序;一般整行数据会比较大,可以先计算没一行数据的MD5(此MD5值可以保留,以后也有用的),然后针对MD5值进行排序;
- 然后逐行检查是否跟下一行相同,如果不同,下移一行;如果相同,标记出来,再看下一行是否相同,直到不同为止。
先说排序。排序算法很简单,这里处理基本都是文本,按字典值排序即可。但不管哪个排序算法,都需要把数据全部装到内存里面遍历、比较;而我们需要处理的数据可能远大于内存容量。所以,需要参考一下“外排序”的概念。
所谓“外排序”,是大文件的排序,即待排序的记录存储在外存储器上,待排序的文件无法一次装入内存,需要在内存和外部存储器之间进行多次数据交换,以达到排序整个文件的目的。处理的流程也分为两个部分:
- 分割排序:把文件分割成多个小文件,每个小文件应该可以被整体读进内存进行排序处理,然后把每个排序后的结果回写成单独的文件。
- 归并,一般进行二路归并。把两个文件按顺序读出来对比,小的拿出来放到缓冲区(假设按正序),然后小的文件读下一行,合并的结果输出到新的文件;两两归并之后,最后得到完全排序的文件。
对排序后的文件进行去重就非常方便了。回头看看,为啥要排序呢?如果不排序,拿到某行数据,要找跟它相同的,需要把所有数据都看一遍;如果是排序的文件,只需要看下一行就行,如果相同就再看下一行。毕竟一份数据中出现重复的是很少的,一条数据重复多次的可能性更小,绝大多数都是往下看一行即可。
在这里,用MD5来排序和比较有比较大的好处。毕竟一般业务数据都很长,几十个字段很正常,而MD5只有128位。当然,使用MD5需要注意一点,MD5存在碰撞概率,也就是不同的输入可能得到同一个MD5值。因此,如果MD5值不相同的,可以直接认定数据不相同;但MD5值相同的话,则需要进一步比较实际数据内容。由于重复的数据比例很小,需要进一步比较的数据很少。而且计算MD5,也是很方便的通过切割文件分布并行的进行计算。
上述过程可以方便的移植到分布式体系上:
- 拆分成多个小文件每个文件在不同的节点上独立排序;
- 两两文件在不同的节点上进行归并;
- 按某个字段特诊,或者MD5值的前几位进行分片,每片数据在独立的节点上进行查重。
在Hadoop体系下,利用MapReduce来实现就相当方便了。文本排序也是MapReduce的经典案例了。只需要定义好自己的分割器,比如每1万条数据一个分片。很容易就实现分布式的排序。
然后再来一次MapReduce,进行分片去重操作即可。
当然,利用MapReduce去重,还有一个取巧的做法。根据Reduce的过程特性,会自动根据key来计算输入的value集合,把数据作为key输出给Reduce,无论这个数据出现多少次,reduce最终结果中key只能输出一次。按次思路,做一个Map把整行数据作为key,value设为空。Reduce输出key即可。这是得益于MapReduce处理过程内部做了对key的排序。如果每行数据很大,不管哪种方式实现,都建议用MD5来进行排序和比较,能进一步提高效率。
未完待续。
来源:CSDN
作者:老程序员一叶知秋
链接:https://blog.csdn.net/cfy_fantasyxx/article/details/103682968