搜索1GB+;Python中模式第一次出现的数据字符串
有一个1G字节的任意数据字符串,您可以假设它相当于:搜索1GB+;Python中模式第一次出现的数据字符串,python,algorithm,search,large-data-volumes,Python,Algorithm,Search,Large Data Volumes,有一个1G字节的任意数据字符串,您可以假设它相当于: 1_gb_string=os.urandom(1*gigabyte) 我们将搜索这个字符串,1\u gb\u string,查找无限多的固定宽度、1 kb的模式,1\u kb\u模式。每次我们搜索时,模式都会不同。因此缓存机会并不明显。同样的1GB字符串将被反复搜索。下面是一个简单的生成器来描述正在发生的事情: def findit(1_gb_string): 1_kb_pattern=get_next_pattern()
1_gb_string=os.urandom(1*gigabyte)
我们将搜索这个字符串,1\u gb\u string
,查找无限多的固定宽度、1 kb的模式,1\u kb\u模式
。每次我们搜索时,模式都会不同。因此缓存机会并不明显。同样的1GB字符串将被反复搜索。下面是一个简单的生成器来描述正在发生的事情:
def findit(1_gb_string):
1_kb_pattern=get_next_pattern()
yield 1_gb_string.find(1_kb_pattern)
请注意,只需找到模式的第一个匹配项。之后,不应进行其他主要处理
我可以使用什么比python的bultin find更快的方法来匹配1KB模式和1GB或更大的数据字符串
(我已经知道如何拆分字符串并并行搜索它,因此您可以忽略基本优化。)
更新:请将内存要求绑定到16GB。使用无限内存,您可以对每个1k字符串及其在1GB文件中的位置进行哈希运算
如果没有无限大的内存,你将被搜索时触摸的内存页数所限制。在遗传学领域,有许多字符串匹配算法用于查找子字符串。您可以尝试或是否愿意花费大量时间预处理字符串 如果你是,你能做的就是建立一个带有偏移量的n-gram列表 假设您的字母表是十六进制字节,您使用的是1-grams 然后,对于00ff,您可以创建一个如下所示的字典(perlese,抱歉) 沿着字符串向下走,从字节发生的所有点构建@array\u of_偏移量。您可以对任意n-gram执行此操作 这提供了一个“搜索起点”,您可以使用它进行行走 当然,缺点是您必须对字符串进行预处理,这是您的折衷 编辑:
这里的基本思想是匹配前缀。如果信息非常相似,这可能会造成严重后果,但是如果n-gram之间存在相当大的差异,那么您应该能够很好地匹配前缀 让我们量化分歧,因为您尚未讨论正在分析的信息类型。在这个算法中,我们可以将散度描述为一个距离函数:你需要一个相当高的散度。如果n克之间的汉明距离是,比如说,1,那么上述想法就行不通了。但是如果是n-1,上面的算法会容易得多 为了改进我的算法,让我们构建一个算法,该算法可以连续消除一些可能性: 我们可以调用来定义给定n-gram的信息。获取搜索字符串并根据前m个字符连续构建前缀。当m前缀的熵“足够高”时,请稍后使用
从某种意义上说,这就像反转哈夫曼编码。我不确定字符串的
find()
方法是否比Python的re
(正则表达式)模块提供的search()
方法快,但只有一种方法可以找到答案
如果您只是在搜索字符串,您需要的是:
import re
def findit(1_gb_string):
yield re.search(1_kb_pattern, 1_gb_string)
但是,如果您真的只需要第一个匹配,那么最好使用返回迭代器的finditer()
,并且使用如此大的操作可能会更好。
对你来说是最有价值的。这是麻省理工学院关于动态规划的讲座据我所知,标准查找算法是一种简单的算法,其复杂性大约为n*m比较,因为 它根据每个可能的偏移量检查模式。有一些更有效的算法,需要大约n+m比较。 如果字符串不是自然语言字符串,可以尝试
. Boyer–Moore搜索算法也足够快速和简单。如果模式相当随机,您可以预先计算字符串的n个前缀的位置 不必检查所有的n前缀选项,只需使用1GB字符串中的实际前缀,这些前缀将少于1GG。在内存中使用尽可能大的前缀,我没有16GB的RAM要检查,但前缀4可以工作(至少在内存效率高的数据结构中),如果不尝试3甚至2的话 对于随机1GB字符串和随机1KB模式,如果使用3字节前缀,每个前缀应该有10个位置,但4字节前缀的平均值应该是0或1,因此查找应该很快 预计算位置
def find_all(pattern, string):
cur_loc = 0
while True:
next_loc = string.find(pattern, cur_loc)
if next_loc < 0: return
yield next_loc
cur_loc = next_loc+1
big_string = ...
CHUNK_SIZE = 1024
PREFIX_SIZE = 4
precomputed_indices = {}
for i in xrange(len(big_string)-CHUNK_SIZE):
prefix = big_string[i:i+PREFIX_SIZE]
if prefix not in precomputed_indices:
precomputed_indices[prefix] = tuple(find_all(prefix, big_string))
当你澄清长时间的预处理是可以接受的时,我建议使用一种变体:“一种多模式搜索的选择算法”,正如维基百科所说 定义一个“滚动散列”函数,即当您知道
haystack[x:x+N]
的散列时,计算haystack[x+1:x+N+1]
的散列为O(1)。(Python内置的hash
等普通散列函数没有此属性,这就是为什么您必须自己编写的原因,否则预处理会变得非常长,而不仅仅是很长;-)。多项式方法是富有成效的,您可以使用(比如)30位散列结果(如果需要,通过掩蔽,也就是说,您可以进行更高精度的计算,只存储掩蔽的30位选择)。为了清楚起见,我们将这个滚动散列函数称为RH
所以,当你沿着干草堆1GB的绳子滚动时,计算1G的相对湿度结果;如果您只存储这些,它将为您提供一个1G 30位值(4GB)的数组H映射
def find_all(pattern, string):
cur_loc = 0
while True:
next_loc = string.find(pattern, cur_loc)
if next_loc < 0: return
yield next_loc
cur_loc = next_loc+1
big_string = ...
CHUNK_SIZE = 1024
PREFIX_SIZE = 4
precomputed_indices = {}
for i in xrange(len(big_string)-CHUNK_SIZE):
prefix = big_string[i:i+PREFIX_SIZE]
if prefix not in precomputed_indices:
precomputed_indices[prefix] = tuple(find_all(prefix, big_string))
def find_pattern(pattern):
prefix = pattern[:PREFIX_SIZE]
# optimization - big prefixes will result in many misses
if prefix not in precomputed_indices:
return -1
for loc in precomputed_indices[prefix]:
if big_string[loc:loc+CHUNK_SIZE] == pattern:
return loc
return -1
ib = A[k]
b = B[ib]
while b < len(haystack) - 1024:
if H[b] != k: return "not found"
if needle == haystack[b:b+1024]: return "found at", b
ib += 1
b = B[ib]