我有简单的文本文件,包含两列,都是整数
1 5
1 12
2 5
2 341
2 12
依旧......
我需要按第二个值对数据集进行分组, 这样输出就是。
5 1 2
12 1 2
341 2
现在问题是该文件在34 Gb附近非常大
在大小上,我尝试编写一个python脚本将它们组合成一个字典,其值为整数数组,但它仍然需要太长时间。 (我想要花费大量时间来分配array('i')
并在append
上进行扩展。
我现在打算编写一个猪脚本,我计划在伪分布式hadoop机器上运行(亚马逊EC3高内存大型实例)。
data = load 'Net.txt';
gdata = Group data by $1; // I know it will lead to 5 (1,5) (2,5) but thats okay for this snippet
store gdata into 'res.txt';
我想知道是否有更简单的方法。
更新 将这么大的文件保存在内存中是不可能的,在python解决方案的情况下,我计划在第一次运行中进行4次运行,只考虑下一次运行中的1到1千万的第二个col值,1000万到2000万被认为是等等。但事实证明这很慢。
pig / hadoop解决方案很有意思,因为它可以将所有内容保存在磁盘上[大部分都是如此]。
为了更好地理解,此数据集包含有关~45百万Twitter用户连接的信息,文件格式表示第二个号码给出的用户ID跟在第一个用户之后。
我曾使用的解决方案:
class AdjDict(dict):
"""
A special Dictionary Class to hold adjecancy list
"""
def __missing__(self, key):
"""
Missing is changed such that when a key is not found an integer array is initialized
"""
self.__setitem__(key,array.array('i'))
return self[key]
Adj= AdjDict()
for line in file("net.txt"):
entry = line.strip().split('\t')
node = int(entry[1])
follower = int(entry[0])
if node < 10 ** 6:
Adj[node].append(follower)
# Code for writting Adj matrix to the file:
答案 0 :(得分:2)
假设每行有大约17个字符(我随机选择的数字使数学运算更容易),此文件中有大约20亿个记录。除非你在64位系统上运行大量物理内存,否则你会将你的页面文件扯到试图将所有内容保存在单个字典中。而这只是将其作为数据结构阅读 - 假设在构建此结构之后,您计划用它实际做。
有了这么简单的数据格式,我认为你最好不要用C代替Python。破解这些数据应该不难,而且每个值的开销也会少得多。至少,只需要保存20亿个4字节整数就可以达到8 Gb(除非你可以对你当前列为1和2的值的可能范围进行一些简化假设 - 如果它们适合一个字节或一个短,那么你可以使用较小的int变量,这对于这个大小的数据集来说是值得的。)
答案 1 :(得分:1)
如果我必须在当前的硬件上解决这个问题,我可能会写一些小程序:
第一个可以处理500兆字节的文件块,交换列并将结果写入新文件。 (你会得到70或更多。)(这不会占用太多记忆。)
然后我会在每个小文件上调用操作系统提供的sort(1)
。 (这可能需要一些记忆。)
然后我会编写一个合并排序程序,它将所有70多个子文件中的行合并在一起。 (这不会占用太多记忆。)
然后我会编写一个程序来运行大型排序列表;你会有很多像以下几行:
5 1
5 2
12 1
12 2
你将需要返回:
5 1 2
12 1 2
(这不会占用太多记忆。)
通过将其分解为更小的块,希望您可以将RSS保持在适合合理机器的范围内 - 将占用更多磁盘I / O,但除了令人惊讶的硬件外,交换使用会杀死在一个大程序中处理此问题的尝试。
答案 2 :(得分:1)
也许你可以通过该文件进行多次传递。
每个键都会通过文件,例如,如果您选择范围大小为100
第一遍 - 计算出0-99之间的所有按键 第二遍 - 计算出100-199的所有钥匙 第3遍 - 计算出200-299的所有钥匙 第4遍 - 计算出300-399的所有钥匙 ..等等。
对于您的样本,第一遍将输出
5 1 2
12 1 2
并输出第4遍
341 2
选择范围大小,以便您创建的字典适合您的RAM
我不打算使用多处理来尝试通过使用多个内核来加速它,除非你有一个非常快的硬盘驱动器,这应该是IO绑定的,你最终会砸到磁盘
答案 3 :(得分:1)
如果您正在使用34 GB文件,我假设硬盘在存储和访问时间方面都不是问题。如何顺序读取对,当你找到pair(x,y),打开文件“x”,附加“y”并关闭文件“x”?最后,每个Twitter用户ID将有一个文件,每个文件包含此连接的所有用户。如果您希望以您指定的输出格式获得结果,则可以连接所有这些文件。
然而,我确实认为: (a)对于如此大的数据集,精确分辨率是不合适的 (b)可能有一些更好的方法来衡量连通性,所以也许你想告诉我们你的最终目标。
事实上,你有一个非常大的图形,并且已经设计了许多有效的技术来研究巨大图形的形状和属性 - 这些技术中的大多数都是作为流媒体在线算法而设计的。
例如,一种称为三角形计数的技术,与概率基数估算算法相结合,可以高效,快速地提供有关图表中包含的派系的信息。为了更好地了解三角形计数方面以及它与图形的关系,请参阅此示例(随机选择)article。
答案 4 :(得分:1)
我有类似的要求,您只需要再发一次猪声明就可以删除5(1,5)(2,5)中的冗余。
a = LOAD 'edgelist' USING PigStorage('\t') AS (user:int,following:int);
b = GROUP a BY user;
x = FOREACH b GENERATE group.user, a.following;
store x INTO 'following-list';