文件相似度比對工具的設計與實現

一、背景與目標

我們業務維護了兩個代碼倉庫,兩端的代碼很多都是一個平臺先開發好,幾乎直接copy到另一個倉庫。於是產生了一個技術需求,實現這兩個倉庫代碼複用。在技術預研階段,需要統計早先copy的代碼文件有多少,提前預估雙端代碼的大概可複用文件比例。早先我是利用Beyond Compare 手動遍歷文件,依據“肉眼”去對比的,花了大概一天的時間,而且估計的數據比較粗略。考慮到這個工作以後還會碰到,而且這個過程就是純粹機械的文件“相似度”對比,所以期望這個過程可以採取自動化腳本完成。大家都經歷過論文查重,主流的有PaperPass、中國知網等;不同的是,我要做的是一個批量文件的對比,當然它的每一步其實是兩個文件之間的相似度比較。之前有人推薦我用simian等工具,很短時間就能完成對比,可以設定相似代碼行數的閾值,並且可以輸出相似代碼。我覺得這款工具的確是好,但是畢竟是第三方工具,算法不可控,還收費。而且我們重複的不僅有代碼,還有重複圖片。

二、算法的設計

大家在學校論文查重時,應該用過至少聽說夠PaperPass。PaperPass文件比對是以句子爲單位檢測的,它的對比過程大致是文本預處理、語義挖掘、深度識別、全局掃描等,如下:


當然,具體還會涉及文字顏色、大小的比對,比較複雜。我們來看一下PaperPass的處理大致過程:t是要對比的文章,T是PP的論文庫,S是重複計數器,M是分割後的t的string數據大小:



然後開始遍歷查找,具體操作狀態如下:



查找到則S=S+1,否則,t數組繼續遍歷,


直到t數據遍歷完,循環結束。


那麼t文章的相似比例爲2/3。

但是這樣的算法對於代碼比對來說,有下面兩個問題:

1、PP是以句子爲單位檢測的,但是代碼不是簡單的句子分隔,如下:

2、既然代碼文件不能按語句分隔,該如下結合代碼copy場景找到最佳的分隔單位呢?是按空格、還是按行呢?


實際copy常常會因人習慣不同,增加些個人習慣的換行,尤其“左大括號換行派”與不換行派的互相copy代碼的時候有一定的誤差;我們來看看按空格分隔,分隔後的數組示意圖如下:



根據這個分隔原理,我用ruby腳本憝了這個算法,並驗證了下算法的情況,如下:



三、工具的原理

上面內容已經基本驗證了按空格分隔的效果,根據PaperPass的過程,寫了一個完整的工具,進行掃描:


我可以根據工具進行靈活性調整,篩選出相似比超過90%的文件或者其他。

四、算法的不足與改進

這個小工具的目的本身就是爲了方便自己使用,出發點也沒打算做的很牛逼,沒有花過多時間去改進它,但是還是有很多方案可以改進這個算法提升比對效率的:

1、由於算法的比對以及遍歷工程目錄下的文件時,使用的都是“暴力”循環遍歷,時間複雜度較高,我最高比對庫代碼達到7000個.m文件,腳本執行了一天沒跑完;後來執行時,去除了不必要的底層pod代碼庫,只對比了業務層的代碼,發現不到2小時,就跑完了。

2、中間也提過,如果你不想那麼精確地比對,可以按單行進行分隔,或者按多行爲分隔單位。

3、原子算法的複雜度是O(n2)的,如果再想着優化,就要優化原子算法本身了。對於T1文件與T2文件的比對過程中,如果發現T1中的某一行在T2中找不到重複的(這種情況應該是較大概率的),可以對T1針對這一行進行一次去重處理O(n);如果這一行在T2中找到了,去重處理並且計數器S累加。如果想把複雜度降到O(nlogn),那麼恐怕要採取二叉樹這樣的數據結構去處理T2了。

4、針對代碼文件,我們發現前面幾行文本往往都是很相似的,這些文本的對比會影響代碼內容的相似度的精確性,例如:


我們也可以直接過濾掉這些代碼段。

發佈了87 篇原創文章 · 獲贊 20 · 訪問量 22萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章