第一次个人编程作业

第一次个人编程作业

这个作业属于哪个课程 <班级链接>
这个作业要求在哪里 <作业要求的链接>
这个作业的目标 论文查重算法+PSP表格+使用JProfiler性能分析+Git管理+单元测试

1 代码链接

2 计算模块接口的设计

本次作业需要实现一个 论文查重 软件

传统的 hash 算法只负责将原始内容尽量均匀随机地映射为一个签名值,原理上相当于伪随机数产生算法。产生的两个签名,如果相等,说明原始内容在一定概 率 下是相等的;如果不相等,除了说明原始内容不相等外,不再提供任何信息,因为即使原始内容只相差一个字节,所产生的签名也很可能差别极大。

我们可以使用 SimHash 来实现我们想要的功能,它除了能够提供原始内容是否相等的信息外,还能额外提供不相等的,原始内容的差异程度的信息,我们可以配合海明距离判断两篇论文的重复率

Simhash 主要步骤为:分词、hash、加权、合并、降维

得到 Simhash 之后,我们可以使用海明距离来判断相似度,一般来说,海明距离小于等于3就是相似

海明距离:在信息编码中,两个合法代码对应位上编码不同的位数称为码距,又称海明距离。举例如下:10101和00110从第一位开始依次有第一位、第二、第五位不同,则海明距离为3。

计算 Jaccard 相似度,可以把它理解为我们最后的相似度

Jaccard index [1] , 又称为Jaccard相似系数(Jaccard similarity coefficient)用于比较有限样本集之间的相似性与差异性。Jaccard系数值越大,样本相似度越高。

所以我们大概需要三个类

  • 一个类用来存放 SimHash 的一些属性,并提供 SimHash 的计算方法
  • 一个类用来实现海明距离的计算
  • 一个类调用其他方法,实现文件读取、相似度的计算以及结果的写入操作

3 计算模块接口的实现

最终实现的项目使用 maven 创建项目,由于类不多,就没有按照属性分成不同的包,具体结构如下:

主要类如下:

  1. SimHash 类:用来存放 SimHash 的一些属性,并提供 SimHash 的计算方法

    1. getFrequency 方法调用分词器进行分词,遍历所有的单词,并计算它的词频放到一个 Map 中
    2. hash 方法是一个普通的hash算法,但是其扩充他的 hash 到 64 位
    3. simHash 方法用来计算 simHash 值,首先调用了 getFrequency 方法得到词频,调用 hash 方法得到长度为 64 的字符,对这 64 为字符进行加权计算,最后进行降维,把权重值大于零的位置设置为 1,小于 0 的位置设置为 0,得到文本的局部哈希值

  2. HammingDistanceUtils 类:这是一个工具类,用来计算海明距离

    1. hammingDistance 方法用来计算海明距离,传入的值为 SimHash
    2. getDistance 方法用来计算海明距离,和1使用不同的方法,传入的值为 String
    3. getSimilarity 方法用来计算相似度,也就是论文最后的相似度

  3. Main 类:用来实现程序的逻辑,试上面两个类的方法关联起来,计算论文的相似度

    1. main 程序的主要入口,根据传入的参数进行相似度的检查,接受的值为要求的 论文原文的文件的绝对路径、抄袭版论文的文件的绝对路径和输出的答案文件的绝对路径,调用 check 进行相似度的计算,是打包 jar 包时的主函数
    2. check 程序,实现相似度的主要逻辑,调用其他函数进行计算,把结果打印在屏幕上、并保存在指定的文件中

  4. FilenameUtils 类:主要用于测试单元获取位于resources的文件路径

    1. getResourcesPath 方法,主要用于测试单元获取位于resources的文件路径

4 计算模块接口部分的性能改进

类的占用情况

方法测试

最多的还是文件读取

5 计算模块部分单元测试展示

主要是通过测试不同的文件原文件改进,空文件、添加、删除、错别字,打乱等测试,看是否能够正确读取、进行计算来判断

@Test   // 正常情况
public void testMain() {
    String firstFilename = FilenameUtils.getResourcesPath("orig.txt");
    String secondFilename = FilenameUtils.getResourcesPath("orig_0.8_add.txt");
    String outputFilename = FilenameUtils.getResourcesPath("out.txt");
    Main.check(firstFilename, secondFilename, outputFilename);
}

@Test   // 测试待测文件为空情况
public void testNullText() {
    String firstFilename = FilenameUtils.getResourcesPath("orig.txt");
    String secondFilename = FilenameUtils.getResourcesPath("empty.txt");
    String outputFilename = FilenameUtils.getResourcesPath("out.txt");
    Main.check(firstFilename, secondFilename, outputFilename);
}

@Test   // 测试待测文本不存在情况
public void testNullPath(){
    String firstFilename = FilenameUtils.getResourcesPath("orig.txt");
    String secondFilename = FilenameUtils.getResourcesPath("fake.txt");
    String outputFilename = FilenameUtils.getResourcesPath("out.txt");
    Main.check(firstFilename, secondFilename, outputFilename);
}

@Test   // 测试待测文件为相同文件或相同内容
public void testSameText(){
    String firstFilename = FilenameUtils.getResourcesPath("orig.txt");
    String secondFilename = FilenameUtils.getResourcesPath("orig.txt");
    String outputFilename = FilenameUtils.getResourcesPath("out.txt");
    Main.check(firstFilename, secondFilename, outputFilename);
}

@Test   // 测试不同的文件格式(不报错,但因为读取的不是字,意义不大)
public void testOtherExt(){
    String firstFilename = FilenameUtils.getResourcesPath("avatar.png");
    String secondFilename = FilenameUtils.getResourcesPath("avatar.png");
    String outputFilename = FilenameUtils.getResourcesPath("out.txt");
    Main.check(firstFilename, secondFilename, outputFilename);
}

@Test   // 测试添加了一些内容的文档
public void testAdd(){
    String firstFilename = FilenameUtils.getResourcesPath("orig.txt");
    String secondFilename = FilenameUtils.getResourcesPath("orig_0.8_add.txt");
    String outputFilename = FilenameUtils.getResourcesPath("out.txt");
    Main.check(firstFilename, secondFilename, outputFilename);
}

@Test   // 测试删除了一些内容的文档
public void testDel(){
    String firstFilename = FilenameUtils.getResourcesPath("orig.txt");
    String secondFilename = FilenameUtils.getResourcesPath("orig_0.8_del.txt");
    String outputFilename = FilenameUtils.getResourcesPath("out.txt");
    Main.check(firstFilename, secondFilename, outputFilename);
}

@Test   // dis10
public void testDis(){
    String firstFilename = FilenameUtils.getResourcesPath("orig.txt");
    String secondFilename = FilenameUtils.getResourcesPath("orig_0.8_dis_10.txt");
    String outputFilename = FilenameUtils.getResourcesPath("out.txt");
    Main.check(firstFilename, secondFilename, outputFilename);
}

@Test   // dis15
public void testDis15(){
    String firstFilename = FilenameUtils.getResourcesPath("orig.txt");
    String secondFilename = FilenameUtils.getResourcesPath("orig_0.8_dis_15.txt");
    String outputFilename = FilenameUtils.getResourcesPath("out.txt");
    Main.check(firstFilename, secondFilename, outputFilename);
}

@Test   // dis1
public void testDis1(){
    String firstFilename = FilenameUtils.getResourcesPath("orig.txt");
    String secondFilename = FilenameUtils.getResourcesPath("orig_0.8_dis_1.txt");
    String outputFilename = FilenameUtils.getResourcesPath("out.txt");
    Main.check(firstFilename, secondFilename, outputFilename);
}

@Test   // mix
public void testMix(){
    String firstFilename = FilenameUtils.getResourcesPath("orig.txt");
    String secondFilename = FilenameUtils.getResourcesPath("orig_0.8_mix.txt");
    String outputFilename = FilenameUtils.getResourcesPath("out.txt");
    Main.check(firstFilename, secondFilename, outputFilename);
}

代码覆盖率

测试结果

6 计算模块部分异常处理说明

  1. 输入的文件为空文件,则提示 ”文件为空,请重新输入“

  2. 输入的文件为不存在,则提示 ”文件不存在,请检查路径“

  3. 输入参数个数不符合要求,直接提示正确用法

7 PSP表格

PSP2.1 ersonal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 20 30
Estimate 估计这个任务需要多少时间 30 20
Development 开发 400 360
Analysis 需求分析 (包括学习新技术) 60 120
Design Spec 生成设计文档 60 60
Design Review 设计复审 30 30
Coding Standard 代码规范 (为目前的开发制定合适的规范) 50 20
Design 具体设计 30 30
Coding 具体编码 160 150
Code Review 代码复审 40 60
Test 测试(自我测试,修改代码,提交修改) 60 90
Reporting 报告 150 160
Test Repor 测试报告 60 60
Size Measurement 计算工作量 40 40
Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 60 50
合计 1190 1280

8 总结

在本次作业中,学到了很多,除了 Simhash 和 海明距离外,还学会了 github 的使用

在作业过程中,也遇到了一些比较坑的地方,如我在打包 jar 包时,发现生成的jar包运行结果和 idea 中直接运行结果不同,结果测试,是因为文件读取时编码问题,设置编码即可

posted @ 2021-09-19 18:29  lz**  阅读(84)  评论(0编辑  收藏  举报
#