我在一台Linux机器上(Redhat),我有一个11GB的文本文件。 文本文件中的每行包含单个logging的数据,行的前n个字符包含logging的唯一标识符。 该文件包含超过2700万条logging。
我需要validation文件中没有多个具有相同唯一标识符的logging。 我还需要在一个80GB的文本文件上执行这个过程,所以任何需要将整个文件加载到内存中的解决scheme都是不实际的。
逐行读取文件,所以不必将其全部加载到内存中。
对于每一行(记录)创建一个sha256散列(32字节),除非你的标识符更短。
将散列/标识符存储在numpy.array
。 这可能是最紧凑的方式来存储它们。 27百万记录次32字节/散列是864 MB。 这些日子应该适合体面的机器的记忆。
为了加速访问,你可以使用第一个例如2个字节的hash作为collections.defaultdict
的关键字,并将其余的哈希值放在值的列表中。 这实际上会创建一个包含65536个桶的哈希表。 对于27e6的记录,每个桶将平均包含大约400个条目的列表。 这将意味着比numpy数组更快的搜索速度,但它会使用更多的内存。
d = collections.defaultdict(list) with open('bigdata.txt', 'r') as datafile: for line in datafile: id = hashlib.sha256(line).digest() # Or id = line[:n] k = id[0:2] v = id[2:] if v in d[k]: print "double found:", id else: d[k].append(v)
Rigth工具的工作:把你的记录到数据库中。 除非你已经安装了Postgres或者MySQL,否则我会采用sqlite。
$ sqlite3 uniqueness.sqlite create table chk ( ident char(n), -- n as in first n characters lineno integer -- for convenience ); ^D
然后我会插入唯一的标识符和行号,可能使用这样的Python脚本:
import sqlite3 # install pysqlite3 before this n = ... # how many chars are in the key part lineno = 0 conn = sqlite3.connect("uniqueness.sqlite") cur = conn.cursor() with open("giant-file") as input: for line in input: lineno +=1 ident = line[:n] cur.execute("insert into chk(ident, lineno) values(?, ?)", [ident, lineno]) cur.close() conn.close()
在此之后,您可以索引表并使用SQL:
$ sqlite3 uniqueness.sqlite create index x_ident on chk(ident); -- may take a bit of time -- quickly find duplicates, if any select ident, count(ident) as how_many from chk group by ident having count(ident) > 1; -- find lines of specific violations, if needed select lineno from chk where ident = ...; -- insert a duplicate ident
是的,我尝试了大部分代码,它应该工作:)
假设我不能使用数据库,我会尝试类似的
# read the file one line at a time http://stackoverflow.com/a/6475407/322909, #be sure to read the comments keys = set() with open("bigfile.txt") as f: for line in f: key = get_key(line) if key in keys: print "dup" else: keys.add(key)
尝试这个:
n=unique identifier size cat 11gb_file | cut -c-$n | sort | uniq -cd
这将输出任何重复的标识符,并出现多少次。
我还没有尝试过这样的文件,但是…假设n个字符的固定位置是7,并且行数不超过999 + 7个字符,这可能会完成这个工作:
awk 'BEGIN{FIELDWIDTHS="7 999"} ! a[$1]++' file > newfile
我永远不会建议你尝试在Python中过滤如此庞大的文本文件。 不管你如何处理它,你都需要经过一些复杂的步骤来确保你不会耗尽内存。
首先想到的是创建一个散列的行,然后使用哈希来查找重复。 既然你保存了行号,那么你可以直接比较文本,以确保没有散列冲突。
但是,最简单的解决方案是将文本文件转换为数据库,使您能够快速地对重复项目进行排序,搜索和过滤。 然后,您可以重新创建文本文件,如果这真的是一个要求。
用Python读取大文本文件,逐行读取,不加载到内存中
这个问题的答案是这样的,
with open("log.txt") as infile: for line in infile: do_something_with(line)
也许这会帮助你,祝你好运。