软工作业2:个人项目
作业概述
| 这个作业属于哪个课程 | 软件工程 | 
|---|---|
| 这个作业要求在哪里 | 个人项目 | 
| 这个作业的目标 | 设计一个论文查重的项目 | 
github链接
PSP表格
| PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) | 
|---|---|---|---|
| Planning | 计划 | 20 | 20 | 
| · Estimate | · 估计这个任务需要多少时间 | 340 | 360 | 
| Development | 开发 | 300 | 320 | 
| · Analysis | · 需求分析 (包括学习新技术) | 100 | 100 | 
| · Design Spec | · 生成设计文档 | 30 | 25 | 
| · Design Review | · 设计复审 | 20 | 15 | 
| · Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 30 | 40 | 
| · Design | · 具体设计 | 30 | 40 | 
| · Coding | · 具体编码 | 30 | 30 | 
| · Code Review | · 代码复审 | 20 | 15 | 
| · Test | · 测试(自我测试,修改代码,提交修改) | 40 | 55 | 
| Reporting | 报告 | 40 | 40 | 
| · Test Repor | · 测试报告 | 15 | 15 | 
| · Size Measurement | · 计算工作量 | 10 | 10 | 
| · Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 15 | 15 | 
| · 合计 | 1235 | 1100 | 
项目设计
项目架构

- FileUtil类:流的形式输入或者输出文件,将输入的文件转换为字符串的形式,并且输出查重结果到result.txt文件下
 - SimHashUtils类:传入String,计算出它的hash值,并以字符串形式输出
 - HammingUtils类:输入两个simHash值,计算它们的海明距离,并计算输出相似度
 - MainText类:程序主入口,通过传递命令行参数的方式提供文件的位置,调用Util包下的类输出结果
 - MainTest类:单元测试类
 
外部依赖
hanlp:portable-1.5.4(汉语言分词处理)
junit:4.13.2(单元测试)
simhash算法
原理
simhash是一种能计算文档相似度的hash算法。通过simhash能将一篇文章映射成64bit,再比较两篇文章的64bit的海明距离,就能知道文章的相似程序。若两篇文章的海明距离<=3,可认为这两篇文章很相近,可认为它们是重复的文章。
simhash作为locality sensitive hash(局部敏感哈希)的一种,其主要思想是降维,将高维的特征向量映射成低维的特征向量(把文档降维到hash数字),通过两个向量的海明距离来确定文章是否重复或者高度近似。在信息论中,两个等长字符串之间的汉明距离是两个字符串对应位置的不同字符的个数。也就是说,它就是将一个字符串变换成另外一个字符串所需要替换的字符个数。例如:1011101 与 1001001 之间的汉明距离是 2。至于我们常说的字符串编辑距离则是一般形式的海明距离。如此,通过比较多个文档的simHash值的海明距离,可以获取它们的相似度。
simhash算法分为5个步骤:分词、hash、加权、合并、降维。
性能分析


(很拉跨,但是没得改)
git提交记录

单元测试
FileUtils
//文件类型不是txt类型
@Test
public void readNotTxtTest(){
    String str = FileUtils.readTxt("D:\\3121005063\\src\\main\\java\\com\\zjz\\util\\FileUtils.java");
    System.out.println(str);
}
//路径存在,正常读取
@Test
public void readTxtTest() {
    String str = FileUtils.readTxt("D:\\3121005063\\src\\main\\resources\\file\\orig.txt");
    String[] strings = str.split(" ");
    for (String string : strings) {
        System.out.println(string);
    }
}
//路径存在,正常写入
@Test
public void writeTxtTest() {
    FileUtils.writeTxt("原神,启动!",
            "D:\\3121005063\\src\\main\\resources\\file\\orig.txt");
}
//路径不存在,读取失败
@Test
public void readTxtFailTest() {
    FileUtils.readTxt("D:\\3121005063\\src\\main\\resources\\file\\fake.txt");
}
//路径错误,写入失败
@Test
public void writeTxtFailTest() {
    FileUtils.writeTxt("原神,启动!",
            "D:\\3121005063\\src\\main\\resources\\file\\fake.txt");
}
测试结果

- 文件类型不是txt类型:抛出异常
 - 路径存在,正常读取
 - 路径存在,正常写入
 - 路径不存在,读取失败

 - 路径错误,写入失败

 
HammingUtils
//获取海明距离
@Test
public void getHammingDistanceTest() {
    String str0 = FileUtils.readTxt("D:\\3121005063\\src\\main\\resources\\file\\orig.txt");
    String str1 = FileUtils.readTxt("D:\\3121005063\\src\\main\\resources\\file\\orig_0.8_add.txt");
    int distance = HammingUtils.getHammingDistance(SimHashUtils.generateSimHash(str0), SimHashUtils.generateSimHash(str1));
    System.out.println("海明距离:" + distance);
    System.out.println("相似度: " + (100 - distance * 100 / 128) + "%");
}
//获取海明距离失败测试
@Test
public void getHammingDistanceFailTest() {
    // 测试str0.length()!=str1.length()的情况
    String str0 = "10101010";
    String str1 = "1010101";
    System.out.println(HammingUtils.getHammingDistance(str0, str1));
}
//获取相似度测试
@Test
public void getSimilarityTest() {
    String str0 = FileUtils.readTxt("D:\\3121005063\\src\\main\\resources\\file\\orig.txt");
    String str1 = FileUtils.readTxt("D:\\3121005063\\src\\main\\resources\\file\\orig_0.8_add.txt");
    int distance = HammingUtils.getHammingDistance(SimHashUtils.generateSimHash(str0), SimHashUtils.generateSimHash(str1));
    double similarity = HammingUtils.getSimilarity(SimHashUtils.generateSimHash(str0), SimHashUtils.generateSimHash(str1));
    System.out.println("str0和str1的汉明距离: " + distance);
    System.out.println("str0和str1的相似度:" + similarity);
}
- 获取海明距离
 - 获取海明距离失败测试
 - 获取相似度测试
 

SimHashUtils
//获取字符串Hash测试
@Test
public void getHashTest() {
    String[] strings = {"我们", "说", "如来", "他", "真的", "来","了吗"};
    for (String string : strings) {
        String stringHash = SimHashUtils.getHash(string);
        System.out.println(stringHash.length());
        System.out.println(stringHash);
        System.out.println("=====================");
    }
}
//获取字符串SimHash测试
@Test
public void getSimHashTest() {
    String orig = FileUtils.readTxt("D:\\3121005063\\src\\main\\resources\\file\\orig.txt");
    String orig_add = FileUtils.readTxt("D:\\3121005063\\src\\main\\resources\\file\\orig_0.8_add.txt");
    System.out.println(orig + ": \n" + SimHashUtils.generateSimHash(orig));
    System.out.println("=====================");
    System.out.println(orig_add + ": \n" + SimHashUtils.generateSimHash(orig_add));
    System.out.println("=====================");
}


                
            
浙公网安备 33010602011771号