高效的“滚动/移动哈希”计算(如移动平均)
Posted
技术标签:
【中文标题】高效的“滚动/移动哈希”计算(如移动平均)【英文标题】:Efficient 'rolling/moving hash' computation (like moving average) 【发布时间】:2013-01-11 14:25:15 【问题描述】:我正在尝试优化一个程序,该程序需要在流的每个位置(字节)处为数据流中的恒定大小窗口计算散列。在比可用 RAM 大得多的磁盘文件中查找重复项是必需的。目前我为每个窗口计算单独的 md5 散列,但它花费大量时间(窗口大小为几千字节,因此每个数据字节被处理几千次)。我想知道是否有一种方法可以在恒定(与窗口大小无关)时间内计算每个后续哈希(例如移动平均线中 1 个元素的加法和减法)?散列函数可以是任何东西,只要它不提供长散列(50-100 位是可以的)并且它的计算速度相当快。它还必须在多达数万亿个不那么随机的窗口(TB 数据)上几乎不产生碰撞——在我的情况下,每次碰撞都意味着磁盘访问(crc32 非常弱,md5 在这方面还可以)。
如果您指出 linux 上可用的现有库函数(如果有的话),我将不胜感激。
这是我在这里的第一个问题,如果我做错了什么,请多多包涵。
问候, 巴托斯
【问题讨论】:
良好散列函数的一个属性(导致统计上适当数量的冲突)是它们的最终值取决于混合输入数据的 /all/ 位,即在它们的在下一个数据块的每个处理步骤中进行计算,结果取决于到目前为止已处理的所有位。如果现在您想“仅”省略前 N 位,这意味着所有后续计算步骤所依赖的数据都不同,因此所有步骤都必须重做。所以你至少得放弃今天好的散列函数的这种力量。 【参考方案1】:rolling hashes 上的***文章有一个指向 ngramhashing 的链接,它在 C++ 中实现了一些不同的技术,包括:
随机化 Karp-Rabin(有时称为 Rabin-Karp) 循环多项式哈希(也称为 Buzhash) 通过不可约多项式进行散列(也可通过GitHub 获得)
【讨论】:
有用的链接,至少我可以尝试现有的实现。谢谢!【参考方案2】:您所描述的与重复数据删除存储中使用的基本方法非常接近。
重复数据删除系统,我们通常使用Rabin's fingerprinting方法作为快速、滚动的哈希函数。 然而,虽然 Rabin 指纹是良好且易于理解的碰撞属性,但它在密码学上并不安全,即将发生碰撞。检查例如怎么样Bentley et al. used such a method in their compression method。问题是您是否可以容忍以及可以容忍多少冲突。如果您可以容忍偶尔的碰撞,那么一个好的 Rabin 指纹实现可能是一个好主意。良好的实现每个内核每秒可以处理超过 200 MB。
我不知道有任何几乎没有冲突(又名加密安全)并且同时滚动的方法。作为 PlasmaHH,我非常怀疑这是否真的可行。
想想你是否可以放松你的限制。也许你可以允许错过一些重复。在这些情况下,更快的方法是可能的。
【讨论】:
谢谢。我会尝试 Rabin 指纹方法,希望它足够好。我真的不想错过比我更多的重复项(因为块大小)。但可能发生冲突时磁盘访问的成本会低于哈希性能增益。 Rabin-Karp 方法确实表现良好,并且在 64 位算术中实现时,对于该任务来说很少有冲突。非常感谢!以上是关于高效的“滚动/移动哈希”计算(如移动平均)的主要内容,如果未能解决你的问题,请参考以下文章