排序大文本数据

13 投票
4 回答
14599 浏览
提问于 2025-04-16 23:41

我有一个很大的文件(有1亿行,用制表符分隔的值,大小大约是1.5GB)。请问有什么最快的方法可以根据其中一个字段来排序这个文件吗?

我试过使用Hive。我想看看用Python能不能更快地做到这一点。

4 个回答

4

把数据分成几个小文件,这样可以在内存中进行排序。先在内存里对每个小文件进行排序,然后再把这些排好序的小文件合并在一起。

合并的时候,从每个要合并的小文件中读取一部分数据。每个文件读取的量要一样,这样才能留出足够的内存空间来存放合并后的结果。合并完成后,把结果保存下来,然后重复这个过程,把合并的数据块继续添加到文件中。

这样做可以减少对文件的读写操作,也能减少在硬盘上移动文件的次数。

6

你想为一个文件建立一个内存索引,步骤如下:

  1. 先创建一个空列表。
  2. open 打开这个文件。
  3. 逐行读取文件内容(可以用 f.readline()),并把每一行的内容存到列表里。存储的内容是一个元组,包含你想要排序的值(可以用 line.split('\t').strip() 来提取)和这一行在文件中的位置(可以通过在调用 f.readline() 之前使用 f.tell() 来获取)。
  4. 读取完毕后,记得用 close 关闭文件。
  5. 对这个列表进行 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 文件中。

撰写回答