排序大文本数据
我有一个很大的文件(有1亿行,用制表符分隔的值,大小大约是1.5GB)。请问有什么最快的方法可以根据其中一个字段来排序这个文件吗?
我试过使用Hive。我想看看用Python能不能更快地做到这一点。
4 个回答
4
把数据分成几个小文件,这样可以在内存中进行排序。先在内存里对每个小文件进行排序,然后再把这些排好序的小文件合并在一起。
合并的时候,从每个要合并的小文件中读取一部分数据。每个文件读取的量要一样,这样才能留出足够的内存空间来存放合并后的结果。合并完成后,把结果保存下来,然后重复这个过程,把合并的数据块继续添加到文件中。
这样做可以减少对文件的读写操作,也能减少在硬盘上移动文件的次数。
6
你想为一个文件建立一个内存索引,步骤如下:
- 先创建一个空列表。
- 用
open
打开这个文件。 - 逐行读取文件内容(可以用
f.readline()
),并把每一行的内容存到列表里。存储的内容是一个元组,包含你想要排序的值(可以用line.split('\t').strip()
来提取)和这一行在文件中的位置(可以通过在调用f.readline()
之前使用f.tell()
来获取)。 - 读取完毕后,记得用
close
关闭文件。 - 对这个列表进行
sort
排序。
然后,如果你想打印排序后的文件,可以重新打开文件。对于列表中的每个元素,使用 f.seek(offset)
将文件指针移动到这一行的开头,再用 f.readline()
读取这一行,最后用 print
打印出来。
优化建议:你可以在列表中存储每一行的长度,这样在打印时可以使用 f.read(length)
来提高效率。
示例代码(为了可读性优化,而不是速度):
def build_index(filename, sort_col):
index = []
f = open(filename)
while True:
offset = f.tell()
line = f.readline()
if not line:
break
length = len(line)
col = line.split('\t')[sort_col].strip()
index.append((col, offset, length))
f.close()
index.sort()
return index
def print_sorted(filename, col_sort):
index = build_index(filename, col_sort)
f = open(filename)
for col, offset, length in index:
f.seek(offset)
print f.read(length).rstrip('\n')
if __name__ == '__main__':
filename = 'somefile.txt'
sort_col = 2
print_sorted(filename, sort_col)
19
你有没有考虑过使用*nix系统中的sort
程序?简单来说,它的速度可能比大多数Python脚本要快。
你可以用 -t $'\t'
来指定数据是用制表符分隔的,-k n
来指定你想要排序的字段,其中 n
是字段的编号,如果你想把结果输出到一个新文件,可以用 -o outputfile
。
举个例子:
sort -t $'\t' -k 4 -o sorted.txt input.txt
这个命令会对 input.txt
文件的第4个字段进行排序,并把结果输出到 sorted.txt
文件中。