个人项目:论文查重
github地址
| 这个作业属于哪个课程 | https://edu.cnblogs.com/campus/gdgy/Networkengineering1834 |
|---|---|
| 这个作业要求在哪里 | https://edu.cnblogs.com/campus/gdgy/Networkengineering1834/homework/11146 |
| 这个作业的目标 | 学习使用PSP表格,学习commit规范 |
一、模块接口的设计与实现过程
1.1文件读写类

文件读写类为了增加开发效率,我引入了糊涂工具包,引用了里面的FileReader,然后对异常进行了封装
1.2分词与计算类

分词部分也是引入了糊涂工具包的TokenizerEngine,并通过hankcs当作引擎来进行分词处理。
1.3 自定义异常类

1.4 程序流程
- 流程图

-
实现逻辑
通过查找网上的资料,主要找到的是阮一峰的文章,介绍的是 TF-IDF与余弦相似性的应用
主要说的是离用余弦相似性来比较两个句子的相似性,这样的思路同然可以运用到一整篇文章。所以我们需要做的第一步是进行分词,并统计词频。但是这里用的是位置向量分析。主要思路是,每一个词在全文的分布大概是如何的,从宏观上来分析两篇文章的相似度。
这里我用到的是hanlp分词。然后遍历存放着词与词频信息的map,计算cos值。最后比对得出答案。
-
这里有一个点需要注意的是分词之后统计的时候还需要对字符char进行判断,值判断汉字。[\u4e00-\u9fa5]
最后的结果
orig_0.8_add.txt 0.8695990639733713
orig_0.8_del.txt 0.7498838191640381
orig_0.8_dis_1.txt 0.9206491294709916
orig_0.8_dis_10.txt 0.804067893296461
orig_0.8_dis_15.txt 0.6575365154781483
二、测试
- 测试分别从两个完全相同的文件和完全不同的文件,到5个测试用例去测试。
同时也测试了假如文件路径有问题和文件为空,也考虑到了各种异常的情况。
package com.free;
import com.free.util.FileUtil;
import com.free.util.TokenizerUtil;
import org.junit.Test;
import java.util.List;
import java.util.Map;
/**
* @ClassNamemain
* @Description
* @Author Free
* @Date2020/9/22 11:39
* @Version V1.0
**/
public class MainStart {
@Test
public void sameTest(){
String path = "D:\\Free\\课程\\软件工程\\数据源\\test\\orig_0.8_add.txt";
String path2 = "D:\\Free\\课程\\软件工程\\数据源\\test\\orig_0.8_add.txt";
Map<String, List<Integer>> stringListMap = TokenizerUtil.CountWord(path);
Map<String, List<Integer>> stringListMap2 = TokenizerUtil.CountWord(path2);
Double aDouble = TokenizerUtil.CountCos(stringListMap, stringListMap2);
FileUtil.writeFile("D:\\Free\\课程\\软件工程\\数据源\\test\\test\\res.txt",String.valueOf(aDouble));
System.out.println(aDouble);
}
@Test
public void addTest(){
String path = "D:\\Free\\课程\\软件工程\\数据源\\test\\orig.txt";
String path2 = "D:\\Free\\课程\\软件工程\\数据源\\test\\orig_0.8_add.txt";
Map<String, List<Integer>> stringListMap = TokenizerUtil.CountWord(path);
Map<String, List<Integer>> stringListMap2 = TokenizerUtil.CountWord(path2);
Double aDouble = TokenizerUtil.CountCos(stringListMap, stringListMap2);
FileUtil.writeFile("D:\\Free\\课程\\软件工程\\数据源\\test\\test\\res.txt",String.valueOf(aDouble));
System.out.println(aDouble);
}
@Test
public void delTest(){
String path = "D:\\Free\\课程\\软件工程\\数据源\\test\\orig.txt";
String path2 = "D:\\Free\\课程\\软件工程\\数据源\\test\\orig_0.8_del.txt";
Map<String, List<Integer>> stringListMap = TokenizerUtil.CountWord(path);
Map<String, List<Integer>> stringListMap2 = TokenizerUtil.CountWord(path2);
Double aDouble = TokenizerUtil.CountCos(stringListMap, stringListMap2);
FileUtil.writeFile("D:\\Free\\课程\\软件工程\\数据源\\test\\test\\res.txt",String.valueOf(aDouble));
System.out.println(aDouble);
}
@Test
public void disTest(){
String path = "D:\\Free\\课程\\软件工程\\数据源\\test\\orig.txt";
String path2 = "D:\\Free\\课程\\软件工程\\数据源\\test\\orig_0.8_dis_1.txt";
Map<String, List<Integer>> stringListMap = TokenizerUtil.CountWord(path);
Map<String, List<Integer>> stringListMap2 = TokenizerUtil.CountWord(path2);
Double aDouble = TokenizerUtil.CountCos(stringListMap, stringListMap2);
FileUtil.writeFile("D:\\Free\\课程\\软件工程\\数据源\\test\\test\\res.txt",String.valueOf(aDouble));
System.out.println(aDouble);
}
@Test
public void dis10Test(){
String path = "D:\\Free\\课程\\软件工程\\数据源\\test\\orig.txt";
String path2 = "D:\\Free\\课程\\软件工程\\数据源\\test\\orig_0.8_dis_10.txt";
Map<String, List<Integer>> stringListMap = TokenizerUtil.CountWord(path);
Map<String, List<Integer>> stringListMap2 = TokenizerUtil.CountWord(path2);
Double aDouble = TokenizerUtil.CountCos(stringListMap, stringListMap2);
FileUtil.writeFile("D:\\Free\\课程\\软件工程\\数据源\\test\\test\\res.txt",String.valueOf(aDouble));
System.out.println(aDouble);
}
@Test
public void dis15Test(){
String path = "D:\\Free\\课程\\软件工程\\数据源\\test\\orig.txt";
String path2 = "D:\\Free\\课程\\软件工程\\数据源\\test\\orig_0.8_dis_15.txt";
Map<String, List<Integer>> stringListMap = TokenizerUtil.CountWord(path);
Map<String, List<Integer>> stringListMap2 = TokenizerUtil.CountWord(path2);
Double aDouble = TokenizerUtil.CountCos(stringListMap, stringListMap2);
FileUtil.writeFile("D:\\Free\\课程\\软件工程\\数据源\\test\\test\\res.txt",String.valueOf(aDouble));
System.out.println(aDouble);
}
@Test
public void Test(){
String path = "D:\\Free\\课程\\软件工程\\数据源\\test\\orig.txt";
String path2 = "D:\\Free\\课程\\软件工程\\数据源\\test\\orig_0.8_dis_15.txt";
Map<String, List<Integer>> stringListMap = TokenizerUtil.CountWord(path);
Map<String, List<Integer>> stringListMap2 = TokenizerUtil.CountWord(path2);
Double aDouble = TokenizerUtil.CountCos(stringListMap, stringListMap2);
FileUtil.writeFile("D:\\Free\\课程\\软件工程\\数据源\\test\\test\\res.txt",String.valueOf(aDouble));
System.out.println(aDouble);
}
@Test
public void NullpointTest(){
String path = "";
String path2 = "";
Map<String, List<Integer>> stringListMap = TokenizerUtil.CountWord(path);
Map<String, List<Integer>> stringListMap2 = TokenizerUtil.CountWord(path2);
Double aDouble = TokenizerUtil.CountCos(stringListMap, stringListMap2);
FileUtil.writeFile("D:\\Free\\课程\\软件工程\\数据源\\test\\test\\res.txt",String.valueOf(aDouble));
System.out.println(aDouble);
}
@Test
public void DIYpointTest(){
String path = "D:\\Free\\test\\1000.txt";
String path2 = "D:\\Free\\test\\4.txt";
Map<String, List<Integer>> stringListMap = TokenizerUtil.CountWord(path);
Map<String, List<Integer>> stringListMap2 = TokenizerUtil.CountWord(path2);
Double aDouble = TokenizerUtil.CountCos(stringListMap, stringListMap2);
FileUtil.writeFile("D:\\Free\\课程\\软件工程\\数据源\\test\\test\\res.txt",String.valueOf(aDouble));
System.out.println(aDouble);
}
}
JProfiler> Protocol version 63
JProfiler> Java 11 detected.
JProfiler> 64-bit library
JProfiler> Listening on port: 34227.
JProfiler> Enabling native methods instrumentation.
JProfiler> Can retransform classes.
JProfiler> Can retransform any class.
JProfiler> Native library initialized
JProfiler> VM initialized
JProfiler> Retransforming 122 base class files.
JProfiler> Base classes instrumented.
JProfiler> Waiting for a connection from the JProfiler GUI ...
JProfiler> Using sampling (5 ms)
JProfiler> Time measurement: elapsed time
JProfiler> CPU profiling enabled
0.804067893296461
0.6575365154781483
0.8695990639733713
文件为空
null
0.6575365154781483
0.7498838191640381
0.9206491294709916
文件路径为空
文件路径为空
null
1.0
Process finished with exit code 0
-
覆盖率
总方法覆盖率为77%,主要原因是自定义异常中只用到一个方法,但是line覆盖率达到了93%

细看覆盖率是

FileUtil中没有覆盖到的地方是还没能测试到输出结果文件异常的部分。但是这个异常我已经做了处理,初步想的是在linux中会有文件读写权限,这时可以覆盖到。

三、性能检测

速度还是很快的,3秒左右完成了9个测试。

内存方面list用了最多 ,因为一个词就开了一个list来存储。
四、算法评价
这个算法实际有一些比较缺陷的地方,就是假如测试用例为
句子1:这是软件工程作业
句子2:这是软件工程作业,但是有点难。
在整体句子混杂的情况下算法效果比较好,但在上述情况,这两个句子最后得出的结果是1,效果明显不是很好。原因在于遍历只遍历到了第一个句子有的词。第二个句子有的词但第一个句子没有的词,并不会加入到计算中。
所以这是算法缺陷的点。这样是采用位置向量的缺陷。希望以后有机会再去修改,使得效果更加好。
五、PSP表格
| PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | 90 | 120 |
| · Estimate | · 估计这个任务需要多少时间 | 60 | 28 |
| Development | 开发 | 480 | 640 |
| · Analysis | · 需求分析 (包括学习新技术) | 60 | 120 |
| · Design Spec | · 生成设计文档 | 60 | 60 |
| · Design Review | · 设计复审 | 60 | 60 |
| · Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 30 | 30 |
| · Design | · 具体设计 | 30 | 30 |
| · Coding | · 具体编码 | 180 | 300 |
| · Code Review | · 代码复审 | 60 | 80 |
| · Test | · 测试(自我测试,修改代码,提交修改) | 60 | 120 |
| Reporting | 报告 | 60 | 60 |
| · Test Repor | · 测试报告 | 20 | 30 |
| · Size Measurement | · 计算工作量 | 10 | 10 |
| · Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | 30 |
| · 合计 | 1290 | 1750 |

被折叠的 条评论
为什么被折叠?



