《海量数据处理》

来源:互联网 发布:手机淘宝网购流程图 编辑:程序博客网 时间:2024/05/21 09:30

依照冯·诺依曼体系结构,计算机在运行程序的时,必须把程序先加载进内存中,然后CPU才能按照程序的逻辑依次执行。一般情况下,我们PC机的内存是4GB/8GB大小,当我们要处理一些较大的文件并在内存中需要开辟较大的空间(超过我们PC机的物理内存大小4GB/8GB)时,我们并不能随便改变物理内存的大小,此时,我们该如何解决此类问题呢?于是,便引出了今天我们要讨论的——海量数据处理。

典例:

//1)给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址//2)与上题条件相同,如何找到top K的IP?如何直接用Linux系统命令实现? //3)给两个文件,分别有100亿个query,我们只有1G内存,如何找到两个文件交集?分别给出精确算法和近似算法!//4)给上千个文件,每个文件大小为1K—100M。给n个词,设计算法对每个词找到所有包含它的文件,你只有100K内存!//5)有一个词典,包含N个英文单词,现在任意给一个字符串,设计算法找出包含这个字符串的所有英文单词!

在讨论具体的解题思路之前,我们先做点铺垫工作,了解下什么是哈希函数?它又有什么用呢?
所谓哈希函数——就是具有将一种类型的数据(常为字符串类型)依据一些特定的算法映射为无符号整数值(映射关系为:多对一)的函数。

//哈希函数——用于哈希切分size_t BKDRHash(const char* str, size_t module ){    assert(module);    const size_t seed = 31; // 种子   也可以为 131    1313    13131   ....等    size_t hash = 0;    while (*str){        hash = hash * seed + *str++;    }    return hash % module;   //将函数返回值控制在区间[0,module)}

1)给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址

面对此类问题,既然我们不能将一个较大的文件一次性的加载进内存中,那么我们可以采用分而治之的思想来解决此类问题。如下图:
海量1
我们可以将大于100GB的日志文件利用哈希函数切分为1000份的小文件,因为哈希函数的映射关系是“多对一”这样便可以保证相同IP被划分进同一个小文件中,切分后的每个小文件的大小大概也就是100MB大小左右,这样我们就可以分别将每个小文件加载进内存中,进而求出每个小文件中出现次数最多的IP地址,通过相互比较便可得出总文件中出现次数最多的IP地址。


2)与上题条件相同,如何找到top K的IP?

经由(1)题的解答之后,此题便是典型的 ” top K “问题,利用pair<string,count>键值对建造一个含有K个元素的“小堆”,首先,先依次将前K个小文件中的出现次数最多的IP地址入堆,然后,依次用剩下的小文件中的出现次数最多的IP地址相对应次数count与堆顶元素IP相对应的次数couunt比较,若大于堆顶元素的次数就替换堆顶元素并采用“向下调整算法”调整,直至比较完所有小文件,则堆中保留的便是出现次数最多的K个IP地址。注:若K大于1000,则应将第(1)题的大文件至少切分成K个小文件。


3)给两个文件,分别有100亿个query,我们只有1G内存,如何找到两个文件交集?分别给出精确算法和近似算法!

精确算法:哈希切分
假设每个query的大小为10个字节,那么100亿个query大约为100GB左右,切分成为1000份小文件,每份小文件的大小大概也就100MB左右,便可以在1G的内存中进行处理了,先利用哈希函数(BKDRHash等)将每一个query映射成一个整数,再用这个整数%1000得到index,index便为当前query应存入的小文件的下标,于是便将两个大文件分别切分成的1000个小文件,分别对比下标相同的小文件内容,找出其中的交集,最后将所有交集汇总便可得到最终结果。时间复杂度O(N)。

近似算法:布隆过滤器
哈希函数返回的数是无符号整数,无符号整形能表示的最大数大概为42亿左右,又因为布隆过滤器用每一位代表一个无符号整数,所以需要大概5亿个字节(大概500MB)就能够表示无符号整数的范围了,将第一个文件中的每一个query经哈希函数映射后得到的无符号整数映射到布隆过滤器中的一个位上,并标记此位,然后取出第二个文件中的每一个query经相同的哈希函数映射后 ,查看产生的无符号整数对应的布隆过滤器的位是否被标记,若标记,则是交集元素,若没有标记,则不为交集元素。时间复杂度O(N)。


4)给上千个文件,每个文件大小为1K—100M。给n个词,设计算法对每个词找到所有包含它的文件,你只有100K内存!
一般情况下,我们是将一个文件的内容利用map等数据结构组织起来,再用关键字来搜索此map查看关键字是否在此文件中,但是,此题我们所拥有的内存空间远远没有文件的容量大,所以我们并不能采用上述思路解答,借鉴搜索引擎的搜索原理,此题我们可以采用倒排索引的方法来解决,如下图:
倒排索引
首先,将N个单词组织成map的结构,然后依次遍历每个文件,取出文件中的每一个单词并在map中查找,若找到,边将此文件的文件名添加到后面的链表中,遍历完所有文件,map中每个单词后面的链表中存储的便是包含该单词的文件名。补充:在实际应用中还常在链表结点中存储每个文件中此单词的权重(多为出现次数),这样有利于按权重将搜索到的结果进行筛选哈。


5)有一个词典,包含N个英文单词,现在任意给一个字符串,设计算法找出包含这个字符串的所有英文单词!

解决此类问题我们需要用到一种特殊的数据结构“Trie树”又叫“字典树”.

Trie树定义如下:
Trie树:是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。
性质:
根节点不包含字符,除根节点外每一个节点都只包含一个字符; 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串; 每个节点的所有子节点包含的字符都不相同。
实现方法:
(1) 从根结点开始一次搜索;
(2) 取得要查找关键词的第一个字母,并根据该字母选择对应的子树并转到该子树继续进行检索;
(3) 在相应的子树上,取得要查找关键词的第二个字母,并进一步选择对应的子树进行检索。
(4) 迭代过程……
(5) 在某个结点处,关键词的所有字母已被取出,则读取附在该结点上的信息,即完成查找。
其他操作类似处理

字典树


原创粉丝点击