我在Linux机器(Redhat)上,我有一个11GB的文本文件。文本文件中的每一行都包含单个记录的数据,该行的前n个字符包含记录的唯一标识符。该文件包含超过2700万条记录。
我需要验证文件中没有多个具有相同唯一标识符的记录。我还需要在80GB的文本文件上执行此过程,因此任何需要将整个文件加载到内存中的解决方案都不实用。
答案 0 :(得分:4)
逐行读取文件,因此您无需将其全部加载到内存中。
对于每一行(记录),创建一个sha256哈希值(32字节),除非您的标识符更短。
将散列/标识符存储在numpy.array
中。这可能是存储它们最紧凑的方式。 2700万条记录时间32字节/散列是864 MB。这应该适合现在体面的机器。
为了加快访问速度,您可以使用第一个例如将2个字节的散列作为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)
答案 1 :(得分:2)
作业的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
是的,我尝试了大部分代码,它应该可以工作:)
答案 2 :(得分:0)
我绝不会建议您尝试在Python中过滤如此庞大的文本文件。无论你如何解决它,你都需要经历一些复杂的步骤,以确保你不会耗尽内存。
首先想到的是创建行的哈希,然后使用哈希来查找重复项。由于您也保存了行号,因此您可以直接比较文本以确保没有哈希冲突。
但是,最简单的解决方案是将文本文件转换为允许您快速排序,搜索和过滤掉重复项目的数据库。然后,如果确实需要,您可以使用它重新创建文本文件。
答案 3 :(得分:0)
Read large text files in Python, line by line without loading it in to memory
这个问题的答案就是这个,
with open("log.txt") as infile:
for line in infile:
do_something_with(line)
也许这会以某种方式帮助你,祝你好运。
答案 4 :(得分:0)
假设我无法使用数据库,我会尝试类似
的内容# 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)
答案 5 :(得分:0)
试试这个:
n=unique identifier size
cat 11gb_file | cut -c-$n | sort | uniq -cd
这将输出任何重复的标识符以及它们出现的次数。
答案 6 :(得分:0)
我没有在一个相当大的文件上尝试过这个,但是......假设n个字符的固定位置是7,并且这些行不超过999 + 7个字符,这可能会起作用:
awk 'BEGIN{FIELDWIDTHS="7 999"} ! a[$1]++' file > newfile