搜索1GB+;Python中模式第一次出现的数据字符串

搜索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()

有一个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()
    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前缀的熵“足够高”时,请稍后使用

  • 将p定义为搜索字符串的m前缀
  • 搜索1GB字符串并创建与p匹配的偏移量数组
  • 将m-prefix扩展为某个k-prefix,k>m,k-prefix的熵大于m-prefix
  • 保留上面定义的元素偏移数组,以便它们与k前缀字符串匹配。丢弃不匹配的元素
  • 转到4,直到满足整个搜索字符串
    从某种意义上说,这就像反转哈夫曼编码。

    我不确定字符串的
    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]