個人第一次編程作業


這個作業屬於哪個課程 班級鏈接
這個作業要求在哪里 作業鏈接
這個作業的目標 論文查重算法設計+學習PSP表格+單元測試+JProfiler性能分析+Git管理

1 代碼鏈接(Java)

1.1 Github鏈接

1.2 可運行的jar包已經發布至倉庫的release包內


2 計算模塊接口的設計與實現過程

2.1 主要的類

  • IoProcess類:進行文本輸入輸出的操作,文本和字符串的相互轉換

  • MyApplication類:主程序

  • MyApplicationTest類:對程序進行單元測試

  • MySimHash類(關鍵類):對字符串進行分詞、獲取哈希值、加權、合並、降維操作,並計算兩字符串的海明距離,計算相似度



2.2 關鍵類的關鍵函數

2.2.1 getSimHash()

  • 分詞:調用HanLp包,對全部字符串進行分詞

  • 獲取哈希值:調用hash(),獲取每個詞的哈希值,256bits

  • 加權和合並:根據詞語的索引進行加權,例如 0~9 的權重為10/-10, 10~19的權重為9/-9,依次遞減,並將相同索引的hash值通過相加進行合並

  • 降維:對每個索引的哈希值大於0的置為1,小於0的置為0

2.2.2 例子

  • 分詞,我們假設權重分為5個級別(1~5)。比如:“今天是星期天,天氣晴,今天晚上我要去看電影 ” ==> 分詞后為 “ 今天/ 是/星期/天/天氣/晴/晚上/我/要去/看電影“,分詞。

  • hash,通過hash算法把每個詞變成hash值,比如“今天”通過hash算法計算為 110101(算法中是設置了196bit的值),“是”通過gethash算法計算為 101011。這樣我們的字符串就變成了一串串數字。

  • 加權,通過 2步驟的hash生成結果,需要按照單詞的權重(單詞權重按照先后順序划分,上面有說過)形成加權數字串,比如“今天”的hash值為“110101”,通過加權計算為“10 10 -10 10 -10 10”;“是”的hash值為“101011”,通過加權計算為 “ 9 -9 9 -9 9 9”。

  • 合並,把上面各個單詞算出來的序列值累加,變成只有一個序列串。“10+9 10-9 -10+9 10-9 -10+9 10+9”,這里為了方便,沒有將所有的都寫出來,實際上是將所有的進行相加。

  • 降維,把4步算出來的 “19 1 -1 1 -1 19” 變成 0 1 串,形成我們最終的simhash簽名。 如果每一位大於0 記為 1,小於0 記為 0。最后算出結果為:“1 1 0 1 0 1”。

2.2.3 getSembalance()

​ 對比兩個哈希值相同索引,如果不同,海明距離加1,最后計算相似度,保留兩位小數

2.3 算法的關鍵以及獨到之處

2.3.1 介紹

​ 運用simHash,而不是直接運用Hash,simhash一種局部敏感的hash值,本文主要目的是為比較兩文本的相似度,如果使用傳統的hash,無法實現目的。

2.3.2 例子

​ “你媽媽喊你回家吃飯哦,回家羅回家羅” 和 “你媽媽叫你回家吃飯啦,回家羅回家羅”。
​ 通過simhash計算結果為:

  • 1000010010101101111111100000101011010001001111100001001011001011

  • 1000010010101101011111100000101011010001001111100001101010001011

    通過傳統hash計算為:

  • 0001000001100110100111011011110

  • 1010010001111111110010110011101

    可見,simhash變化的只有很小一部分,而hash值發生了很大改變,因此不能用傳統的hash

2.4 分包截圖


2.5 實際命令行運行效果



3 計算模塊接口部分的性能改進

執行單元測試,對各種情況使用JProfiler對性能進行監控

3.1 類的占用情況



3.2 CPU Load



3.3堆內存情況



3.4 耗時操作




可見,耗時最多的是hanlp分詞操作,因此性能瓶頸在於Hanlp分詞操作函數,所以我並沒有對其他地方進行改動來提升程序的性能

4 計算模塊部分單元測試展示

4.1 采用白盒測試,對原文件改進,空文件、添加、刪除、錯別字,打亂等測試

單元測試代碼如下

/**
 *Test 1:test the empty txtFile
 */
@Test
public void testForEmpty(){
try {
    MyApplication.process("test/orig.txt", "test/empty.txt", "test/ansAll.txt");
	} 
    catch (Exception e) {
    e.printStackTrace();
    Assert.fail();
}
}
/**
 * Test 3:Test 20% text addition: orig_0.8_add.txt
 */
  @Test
  public void testForAdd(){
  try {         			     	                                            			   MyApplication.process("test/orig.txt","test/orig_0.8_add.txt","test/ansAll.txt"); 
     }
     catch (Exception e) {
       e.printStackTrace();
       Assert.fail();
     }
  }
/**
 * Test 4:Test 20% text deletion: orig_0.8_del.txt
 */
     @Test
     public void testForDel(){
       try {
        MyApplication.process("test/orig.txt","test/orig_0.8_del.txt","test/ansAll.txt");
       }
       catch (Exception e) {
           e.printStackTrace();
       }
         }
/**
 * Test 5:Test 20% out-of-order text: orig_0.8_dis_1.txt
 */
   @Test
   public void testForDis1(){
   	try {
     MyApplication.process("test/orig.txt","test/orig_0.8_dis_1.txt","test/ansAll.txt");
     }
     catch (Exception e) {
         e.printStackTrace();
     }
    }
 /**
  * Test 6:Test 20% out-of-order text: orig_0.8_dis_10.txt
  */
 @Test
 public void testForDis10(){
   try {         MyApplication.process("test/orig.txt","test/orig_0.8_dis_10.txt","test/ansAll.txt");
   }
   catch (Exception e) {
     e.printStackTrace();
    }
 }
/**
 * Test 7:Test 20% out-of-order text: orig_0.8_dis_15.txt
 */

    @Test
    public void testForDis15(){
        try {
            MyApplication.process("test/orig.txt","test/orig_0.8_dis_15.txt","test/ansAll.txt");
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
/**
 * Test 8:Test the same text: orig.txt
 */
     @Test
     public void testForSame(){
     try {
         MyApplication.process("test/orig.txt","test/orig.txt","test/ansAll.txt");
       }
       catch (Exception e) {
           e.printStackTrace();
       }
         }

4.2 測試結果



4.3 代碼覆蓋率



5 計算模塊部分異常處理說明

5.1 測試文件輸入參數出錯的情況

代碼如下(只展示部分代碼):

/**
*Test 2:The case where the entered comparison text path parameter is an incorrect parameter
*/
public void testForWrongOriginArgument(){
    try {
    MyApplication.process("test/123.txt","test/orig_0.8_add.txt","test/ansAll.txt");
    }
    catch (Exception e) {
        e.printStackTrace();
    }
}

測試結果:


5.2 測試文件輸出參數出錯的情況

代碼如下(只展示部分代碼):

/**
 *Test14: Test if the output file path parameter is an error parameter
 */
@Test
public void testForWrongOutputArgument(){
    try {
        MyApplication.process("test/orig.txt","test/orig.txt","test/testAWrongArgumentResult.txt");
    }
    catch (Exception e) {
        e.printStackTrace();
    }
}

測試結果:



5.3 測試文件為空的情況

代碼如下(只展示部分代碼):

/**
 * Test 1:test the empty txtFile
 */
@Test
public void testForEmpty(){
    try {
        MyApplication.process("test/orig.txt", "test/empty.txt", "test/ansAll.txt");

    } catch (Exception e) {
        e.printStackTrace();
        Assert.fail();
    }
}

測試結果:



6 PSP表格

PSP2.1 Personal Software Process Stage 預估耗時(分鍾 實際耗時(分鍾)
Planning 計划 20 30
Estimate 估計這個任務需要多少時間 60 60
Development 開發 600 600
Analysis 需求分析 (包括學習新技術) 240 300
Design Spec 生成設計文檔 70 60
Design Review 設計復審 30 30
Coding Standard 代碼規范 (為目前的開發制定合適的規范) 30 20
Design 具體設計 60 70
Coding 具體編碼 200 240
Code Review 代碼復審 40 60
Test 測試(自我測試,修改代碼,提交修改) 240 300
Reporting 報告 160 180
Test Repor 測試報告 60 60
Size Measurement 計算工作量 40 40
Postmortem & Process Improvement Plan 事后總結, 並提出過程改進計划 60 60
合計 1910 2110

7 代碼質量檢查Code Quantity Analysis

代碼質量檢查,用的是codacy,主要問題出現在類名和方法名的命名上,復習了正確的命名方式

對於類名,大駝峰式,符合正則表達式:[A-Z]a-zA-Z0-9

對於方法名,小駝峰式,符合正則表達式:[a-z]a-zA-Z0-9


8 總結

  • 因為本人沒有完全寫過一個類似於這種的開發程序,所以耗時比較久,主要耗時在於Git和Github的學習上,如何將本地文件上傳到倉庫上;
  • 耗時比較多的地方還有對於jar包的打包上,因為沒有將Maven等依賴包一起打包進去,所以導致出現錯誤,最后詢問了朋友才解決了問題;
  • 以及之前沒有接觸過的codacy、Jprofiler和單元測試,所以學習新的工具也需要一定的時間


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM