作業所屬課程 | https://edu.cnblogs.com/campus/gdgy/Networkengineering1834 |
---|---|
作業要求 | https://edu.cnblogs.com/campus/gdgy/Networkengineering1834/homework/11146 |
這個作業的目標 | 實現論文查重算法,熟練使用PSP表格,熟練使用單元測試,熟練使用代碼質量檢測工具,熟練使用性能分析工具 |
一、GitHub
https://github.com/birdaaron/Cosine-Similarity
二、PSP表格
PSP2.1 | Personal Software Process Stages | 預估耗時(分鍾) | 實際耗時(分鍾) |
---|---|---|---|
Planning | 計划 | 10 | 10 |
· Estimate | 估計這個任務需要多少時間 | 10 | 10 |
Development | 開發 | 290 | 470 |
· Analysis | 需求分析 (包括學習新技術) | 60 | 120 |
· Design Spec | 生成設計文檔 | 0 | 0 |
· Design Review | 設計復審 | 0 | 0 |
· Coding Standard | 代碼規范 (為目前的開發制定合適的規范) | 0 | 0 |
· Design | 具體設計 | 20 | 20 |
· Coding | 具體編碼 | 120 | 200 |
· Code Review | 代碼復審 | 60 | 60 |
· Test | 測試(自我測試,修改代碼,提交修改) | 30 | 70 |
Reporting | 報告 | 120 | 330 |
·Test Report | 測試報告 | 90 | 300 |
·Size Measurement | 計算工作量 | 0 | 0 |
·Postmortem & Process Improvement Plan | 事后總結, 並提出過程改進計划 | 30 | 30 |
Total | 合計 | 420 | 810 |
三、接口的設計與實現過程
1.算法原理
參考文章:https://www.cnblogs.com/airnew/p/9563703.html
簡單起見,先從兩個句子着手:
句子A:我喜歡分詞!你喜歡嗎?
句子B:我討厭分詞,你討厭嗎?
判斷這兩個句子的相似度的基本思路是:如果兩句話的用詞相似,它們的內容也就越相似。所以可以通過詞頻來計算兩個句子的相似度。
既然要計算詞頻,就應該讓計算機把所有用詞都識別出來。
所以第一步就是分詞。
分詞A:我/喜歡/分詞/!/你/喜歡/嗎/?/
分詞B:我/討厭/分詞/,/你/討厭/嗎/?/
第二部,將分詞都放在一個集合里,方便統計
集合:我/你/喜歡/討厭/嗎/!/?/,/
第三步,計算詞頻
詞頻A:我(1)/你(1)/喜歡(2)/討厭(0)/嗎(1)/!(1)/?(1)/,(0)/
詞頻B:我(1)/你(1)/喜歡(0)/討厭(2)/嗎(1)/!(0)/?(1)/,(1)/
第四步,得出向量(詞頻數組)
句子A [1,1,2,0,1,1,1,0]
句子B [1,1,0,2,1,0,1,1]
得到詞頻后就可以開始計算相似度:如果把兩個句子的向量看成是空間中的兩條從原點[0,0,0,0,0,0,0,0]出發,指向[1,1,2,0,1,1,1,0]和[1,1,0,2,1,0,1,1]的線段,就可以通過計算線段夾角大小來判斷兩條線段是否重合/相似。
也就是說,這個角的余弦值越大,就越相似。
2.接口設計
· 我將實現的功能大體分為兩個部分:
1.文件處理TextSimilarity.java:用於讀取txt文件中的字符串和創造輸出文件,是程序的入口
2.相似度計算Core.java:用於將讀入的文章分詞,記錄詞頻和計算相似度
· 關系圖
3.關鍵算法
· 由於有了分詞頻數計算余弦值是非常簡單的,那么關鍵就在於收集分詞和統計分詞頻數
· 收集分詞的集合是一個以分詞字符串(String word)為Key,分詞頻數數組(int[2] count)為Value的HashMap(HashMap<String,int[]> wordMap),其中count[0]代表articleA的分詞頻數,count[1]則代表articleB的分詞頻數。
· 代碼中用到的是分詞器是jieba-analysis
四、接口部分的性能改進
1.使用SonarLint改進代碼質量
· 已消除所有警告
2.使用JProfier分析性能
內存泄漏
· Overview
Memory的下降代表垃圾回收
· Live memory
手動GC前,各對象占用內存
手動GC后,各對象占用內存,可見大部分HashMap被留在了內存里
· Heap walker
可見這些HashMap都是由我使用的分詞器所帶來的,不方便優化
時間花費
· CallTree,可見大部分時間花費在分詞上,很小部分時間花費在文件的讀寫
· 花費時間最多的函數
五、單元測試展示
1.測試覆蓋率
2.單元測試
· TextSimilarityTest.java
該類主要是用於處理文件,所以主要測試是否成功從文件中讀取文章和是否成功創建輸出文件
· 參數化測試
JUnit4允許開發人員使用不同的值反復運行相同的測試,initData()函數中objects包含5組數據,它們會在構造函數中被接收,相當於進行5次不同數據的測試,每組數據的第一個元素是對比文章的絕對地址,第二個元素是對比文章的第一句話(由於每篇文章的第一句話都是“活着前言”的不同變句,由此用來測試對應文章是否成功被讀取到List中)
· void testArticleBFirstSentence() 測試對比文章是否被成功讀取到List中
· void testCreateOutputFile() 測試輸出文件是否成功創建
· 測試結果
· CoreTest.java
該類主要用於分詞、統計詞頻和計算相似度,其中計算相似度比較簡單,重點在於測試前兩個功能。
· 測試數據
· void testTextSegment()測試分詞結果和詞頻統計結果
· 測試結果
· 文章相似度測試
· orig.txt與orig_0.8_del.txt
· orig.txt與orig_0.8_dis_1.txt
· orig.txt與orig_0.8_dis_10.txt
· orig.txt與orig_0.8_dis_15.txt
六、異常處理
· FileNotFoundException
在從文件中讀取字符串和創造輸出文件時,如果給出的文件地址不正確,就會產生該異常
異常測試