有效地搜索海量文件中的字符串

时间:2013-03-14 03:55:23

标签: python search optimization large-files

我发现了这个想法的变种,但没有一个可以让我(对python来说很新)到我需要的地方。

以下是该方案:

  1. 我有一个巨大的,27 gig hashfile.txt由独特的字符串组成,所有这些都在不同的行上。
  2. 我需要逐行解析这个文件,在另一个不大的(~800mb)addresses.txt文件中搜索匹配
  3. 找到匹配项后,需要将其写入outfile.txt
  4. 我目前的代码已尽可能优化,但只能达到150行/秒。考虑到我的hashfile.txt中有超过15亿行,任何优化都会有所帮助。

    fin = 'hashed.txt'
    nonzeros = open('addrOnly.txt', 'r')
    fout = open('hits.txt', 'w')
    lines = nonzeros.read()
    i = 0
    count = 0
    
    with open(fin, 'r') as f:
        for privkey in f:
                address = privkey.split(", ")[0]
                if address in lines:
                        fout.write(privkey)
                i = i+1
                if i%100 == 0:
                        count = count + 100
                        print "Passed: " + str(count)
    

2 个答案:

答案 0 :(得分:4)

您希望实施的内容可能是Rabin-Karp string search。当您在某些语料库中同时搜索多个字符串时,它非常高效。

有关此帖子中python实现的更多信息。 python efficient substring search

由于您一次搜索多个地址,您可能希望对addresses.txt中的条目进行哈希处理,并在每次迭代时将它们与Rabin-Karp哈希值进行比较。阅读有关Rabin-Karp中滚动哈希的更多信息,您将了解其工作原理。

因为Rabin-Karp要求所有图案长度相同;在实践中,所有地址都可能具有一些不可忽略的长度,您可以将它们全部截断为相同(不太短)的长度并使用前缀进行散列。此外,您可能希望将Rabin-Karp哈希修改为对空白不变,并且在地址格式方面存在细微差别,并且还要定义一个类似于自定义字符串比较器以确认匹配。

答案 1 :(得分:3)

对于这样的数据大小,我会使用适当的数据库。数据库经过优化,可以比人们编写的Python程序更快地处理大型数据集。

直接字符串比较很昂贵。让我们对字符串进行哈希处理,以便哈希的完整二叉树索引有很好的机会适应内存。 md5是128位,计算速度非常快。

首先,为任一文件中的每条记录计算md5,并将它们存储在另一个文本文件中:

from hashlib import md5
with open('hashfile.txt') as input:
  with open('hashfile-md5.txt', 'w') as output:
    for line in input:
      value = line.rstrip() # cut '\n'
      output.write(value)
      output.write('\t') # let our file be tab-separated
      output.write(int(value).hexdigest(), 16)) # md5 as long number
      output.write('\n')

address.txt重复相同的操作,生成address-md5.txt

使用Postgresql,mysql甚至SQLite(我将在这里使用它),并创建两个表和一个索引。

$ sqlite3 matching-db.sqlite

create table hashfile (
  txt varchar(64), -- adjust size to line lengths of hashfile.txt
  hash number(38) -- enough to contain 128-bit hash
);

create table address (
  txt varchar(64), -- adjust size to line lengths of address.txt
  hash number(38) -- enough to contain 128-bit hash
);

现在加载我们的数据。本机数据库导入通常比通过dbapi从Python插入快得多。

.separator \t
.import hashfile-md5.txt hashfile
.import address-md5.txt address

现在我们可以创建一个索引:

create index x_address_hash on address(hash);

这是一个select语句,可以有效地扫描大型hashfile表,并从小address表中查找匹配的哈希值。索引将在整个时间内(希望如此),就像大多数地址表一样。

select h.txt
from hashfile h, address a
where h.hash = a.hash and h.txt = a.txt;

我们的想法是使用索引x_address_hash来有效地匹配哈希值,如果哈希值匹配,也会比较实际的文本值。

我没有在29 MB的数据上尝试过它,但是在玩具2行的例子中它起作用了:)