软件工程作业2:论文查重
论文查重
这个作业属于哪个课程 | 软件工程课程 |
---|---|
这个作业要求在哪里 | https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/homework/13229 |
这个作业属于哪个课程 | https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/ |
这个作业的目标 | 按照要求写一个查重软件 |
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 20 | 30 |
· Estimate | · 估计这个任务需要多少时间 | 300 | 400 |
Development | 开发 | 500 | 600 |
· Analysis | · 需求分析 (包括学习新技术) | 10 | 20 |
· Design Spec | · 生成设计文档 | 10 | 20 |
· Design Review | · 设计复审 | 20 | 30 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 10 | 20 |
· Design | · 具体设计 | 30 | 20 |
· Coding | · 具体编码 | 10 | 30 |
· Code Review | · 代码复审 | 10 | 30 |
· Test | · 测试(自我测试,修改代码,提交修改) | 20 | 10 |
Reporting | 报告 | 30 | 20 |
· Test Repor | · 测试报告 | 10 | 40 |
· Size Measurement | · 计算工作量 | 40 | 50 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 10 | 10 |
· 合计 | 1040 | 1330 |
程序设计
类名 | 方法名 | 职责描述 |
---|---|---|
CosineSimilarity | getWordFrequency | 计算词频向量 |
cosineSimilarity | 计算两个文本的余弦相似度 | |
FileUtils | WriteToFile | 写数据到文件中 |
ReadFile | 从文件读取数据 | |
TextUtils | preprocessText | 对文本进行分词处理 |
关键算法:余弦相似度
余弦相似度算法:一个向量空间中两个向量夹角间的余弦值作为衡量两个个体之间差异的大小,余弦值接近1,夹角趋于0,表明两个向量越相似,余弦值接近于0,夹角趋于90度,表明两个向量越不相似。
例子
句子A:这只皮靴号码大了。那只号码合适
句子B:这只皮靴号码不小,那只更合适
怎样计算上面两句话的相似程度?
基本思路是:如果这两句话的用词越相似,它们的内容就应该越相似。因此,可以从词频入手,计算它们的相似程度。
第一步,分词。
句子A:这只/皮靴/号码/大了。那只/号码/合适。
句子B:这只/皮靴/号码/不/小,那只/更/合适。
第二步,列出所有的词。
这只,皮靴,号码,大了。那只,合适,不,小,很
第三步,计算词频。
句子A:这只1,皮靴1,号码2,大了1。那只1,合适1,不0,小0,更0
句子B:这只1,皮靴1,号码1,大了0。那只1,合适1,不1,小1,更1
第四步,写出词频向量。
句子A:(1,1,2,1,1,1,0,0,0)
句子B:(1,1,1,0,1,1,1,1,1)
到这里,问题就变成了如何计算这两个向量的相似程度。我们可以把它们想象成空间中的两条线段,都是从原点([0, 0, …])出发,指向不同的方向。
两条线段之间形成一个夹角,
如果夹角为0度,意味着方向相同、线段重合,这是表示两个向量代表的文本完全相等;
如果夹角为90度,意味着形成直角,方向完全不相似;
如果夹角为180度,意味着方向正好相反。
因此,我们可以通过夹角的大小,来判断向量的相似程度。夹角越小,就代表越相似。
性能分析
没有警告
基于JProfiler工具的分析
由图可知
char[]类型的实例数量为36,169,占用了36,169个单位的内存大小,占比最大。
最耗时的程序
如上图所示,一个测试案例耗时420ms
其主要性能瓶颈是计算余弦相似度时调用的基于jieba分词方法
单元测试
我从两个文件中读取数据,调用余弦相似度计算方法,计算出余弦相似度,将其写入result.txt,观察结果的准确性
测试覆盖率截图
异常处理
当文件路径输入不正确时,(即捕获到FileNotFoundException,会在控制台打印并终止程序)
public class FileUtils {
public static void WriteToFile(String data,String filename) {
try (FileWriter fileWriter = new FileWriter(filename,true )){
fileWriter.write("\n"+data);
System.out.println(filename+"写入成功!");
}catch (FileNotFoundException e){
throw handleException(e, "文件不存在: " + filename);
}
catch (IOException e) {
throw handleException(e, "文件写入出错: " + filename);
}
}
public static String ReadFile(String filename){
StringBuilder stringBuilder = new StringBuilder();
try (FileReader fileReader = new FileReader(filename)){
String line;
BufferedReader bufferedReader = new BufferedReader(fileReader);
while((line=bufferedReader.readLine())!=null){
stringBuilder.append(line);
}
} catch (FileNotFoundException e) {
throw handleException(e, "文件不存在: " + filename);
} catch (IOException e) {
throw handleException(e, "文件读取出错: " + filename);
}
return stringBuilder.toString();
}
private static RuntimeException handleException(Exception e, String message) {
System.err.println(message + " " + e.getMessage());
return new RuntimeException(message, e);
}