Winnowing:一种文档指纹的通用算法

       本文为论文《Winnowing: Local Algorithms for Document Fingerprinting》的读书笔记。

       在当今时代,电子内容会通过很多途径出现相同的情况,比如说:引用,版本修订,剽窃等。而文档指纹是用来准确指定拷贝的有效途径,哪怕是在大量的文档集合种有小部分的拷贝。

       在该论文中,作者介绍了通用的文档指纹算法,这些算法似乎可以捕捉到任何指纹的通用属性来保证拷贝的检测。另外,作者还提出了一种新的效果卓越的算法,名称是“Winnowing”。该算法对于文档指纹的侦测非常高效。

       作者首先从背景入手,讲述了文档抄袭检测的实际意义。关于文档的抄袭,不仅仅是大篇幅的引用或剽窃,同时还包括小部分的拷贝,而后者更加隐蔽,且不会轻易被发现,但是现在后者这种现象已经受到广泛的关注,有很多的研究在尝试解决后者这个难题。

       之前很多的检测算法都利用了一个观点,那就是k-gram,长度为k的连续子串。这些算法,首先将文档分成很多个k-grams,而这个k值是用户指定的。然后再哈希每一个k-gram,最后选出这些哈希值的一些子集,作为这个文档的指纹。在所有的实用的算法中,指纹还带有位置信息,这些信息代表着这些指纹来自的文档位置。这里需要注意的是,如果在实际过程中,一旦hash函数被选定的话,那么两个不同文档冲突的概率会非常小,这样也就大大降低了偶然性,反过来讲,一旦两个文档的文档指纹是一样的,那么非常可能这两个文档使用的是同一个k-gram。

       可见,为了效率而言,并没有将所有的hash值作为文档的指纹,而是选取了其中的一部分来作为文档指纹。那么这里就会存在一个如何选择hash值的问题,这个问题也是本文的一个关键点,好的选择策略可以使得算法的效率高,可用性高,并且干扰噪声小。在选择策略中,有一种方法是之前被广泛使用的,那就是0 mod p,而这个p值是被用户指定的。这样的方法是很容易实现,因为这使得所有的hash值中的1/p被保留下来作为文档指纹。而作为检测文档间是否存在雷同的方法,就是检测文档指纹相同指纹的个数。

       但是以上的方法会有一个弊端,那就是不能保证文档间的所有匹配会被检测出来,因为它把所有的选择都依赖于0 mod p。而本文提出的方法winnowing,可以从hash序列种选取合适的集合作为文档指纹,并且可以保证任意总够长的匹配都会被检测出来。这个winnowing算法之所以会这样的高效,是因为在选取hash值集合的时候,采用了滑动窗(window)的概念来选取hash值,使用滑动窗口来选择指纹的好处是:指纹的选择更多的依赖于窗口内的hash值序列,但是0 mod p选择时,更多取决于0 mod p函数。也就是在最原始的hash值中,作者首先以窗口大小w来选择这个窗口中最小的hash值,然后将这个窗口向右移动,每移动一个,都选择出窗口中最小的hash值。这样的过程结束后,会选择出很多的hash值,但是可以预见的是,在这些hash值中,肯定会存在很多相邻的hash值是相同的,这是因为窗口滑动的缘故。然后再将这些相同的hash值进行处理,最后得到比原来数量少很多的hash值集合,这就是使用winnowing后的文档指纹。

       当然这样的算法也有一些文档那个是不适用的,比如说整个文档中都是同一个字符的文档。因为这样的话,几乎产生的hash值只有一个,而这将大大降低文档指纹的代表性。

       随后作者还介绍了在文档相似检测领域的一些背景和相关性工作。

       首先,如果要对一个文档进行指纹提取的话,那么这个指纹提取算法必须满足3个特性。第一,该算法对空格具有不敏感性。也就是说,对文档的初步处理会采取措施,使得文档中空格,标点等的个数对初步处理结果是不具有影响的。第二,算法本身具有噪声抑制的特性。首先需要注意的是,比如“the”这样的单词在文档间出现,然后被检测出来,是没有意义的。所以在匹配方面,匹配必须足够长,使得这样的匹配可以预示着文档间的确存在抄袭或者雷同现象。同样的,比如说在不同文档间出现了相同的谚语,虽然谚语的长度可能足够长,但是不应该就凭此就认为文档间存在雷同。第三,算法与文档内容的位置不存在依赖关系。比如说,两个文档已经存在相似现象,那么在其中一篇文章中插入某些成段内容将不会影响到原先的相似度结果;或者删除了某些无关内容也不会影响到最终的相似度结果。

       关于第一个特性,对文档进行简单的预处理即可以做到,该文也没有大篇幅讲述。

       但是第二个特性的讲述,作者提出了一个阈值概念,也就是说需要选择足够长的的值k,使得这个k值比普通的谚语长度要长。所以这里用的一个假设,这个假设是长度不小于k的子串匹配是有意义的,而长度小于k的子串匹配是不具有意义的。

       其实第三个特性的讲述,是非常有趣也是有意义的,为达到这个特性的时候,作者介绍了一种之前也被广泛使用的策略Karp-Rabin String Match。

       Karp-Rabin算法是为了实现快速子串匹配的。在计算hash值的时候,主要是呈现出一个多项式计算。但是由于hash值计算的特殊性,前一个hash计算值其实和后一个hash计算值有很大的相似性,因为前一个计算和后一个计算在本质上只是相差一个字符。所以可以采用后者利用前者已有的计算值进行计算,在计算上只是在前者的计算结果上多两个加法计算和两次乘法计算,大大降低了原始计算的计算复杂性。

       随后的论文中,作者描述和分析了winnowing算法,其实也可以发现,该算法的主要关键点是如何从k-grams的众多hash值种选出最终的指纹。在检测过程中,作者希望子串在匹配过程中满足两个特性:1,如果一个子串匹配的长度至少和受保证的阈值t的话,这样的匹配会被检测出来;2,算法不会检测出长度小于k的匹配,这个k值被称为噪声阈值。

       可以看到,如果k越大的话,那么我就越有信心证明检测出来的匹配不是偶然性的。在winnowing中选择文档指纹的时候,如果出现了很多相邻的相同最小值,那么选择最右端出现的那个值,最后保存所有被选择出来的hash值作为文档的指纹。

       关于在本算法在运用的时候,虽然指纹可以按照算法获取,但是在具体算法流程中,可能会存在一个效率问题,也就是如何使得hash值被一次选出。首先这些值都是被存放在数据库中的,然后这些指纹会被索引。如果我们采取另一个窗口Fw来实现对指纹选择的话,那么这样在实现流程中使用的内存和磁盘访问会变得更少,更有利于指纹的查找。

       在该论文的后面部分,作者使用了一系列的实验数据来检验winnowing算法。以及以C语言展现了winnowing算法的具体代码实现。

发布了47 篇原创文章 · 获赞 10 · 访问量 22万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章