这个作业属于哪个课程 | 软工23级 (广东工业大学 - 计算机学院) |
---|---|
这个作业要求在哪里 | 个人项目 |
这个作业的目标 | 设计一个论文查重算法,给出一个原文文件和一个在这份原文上经过了增删改的抄袭版论文的文件,在答案文件中输出其重复率 |
GitHub链接:https://github.com/Eaenerys/Eaenerys/tree/main/3123004291
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 30 |
Estimate | 估计这个任务需要多少时间 | 845 | 935 |
Development | 开发 | 240 | 260 |
Analysis | 需求分析 (包括学习新技术) | 120 | 130 |
Design Spec | 生成设计文档 | 30 | 45 |
Design Review | 设计复审 | 15 | 15 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 15 | 15 |
Design | 具体设计 | 60 | 80 |
Coding | 具体编码 | 120 | 120 |
Code Review | 代码复审 | 30 | 30 |
Test | 测试(自我测试,修改代码,提交修改) | 35 | 30 |
Reporting | 报告 | 60 | 75 |
Test Repor | 测试报告 | 30 | 35 |
Size Measurement | 计算工作量 | 30 | 35 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 30 | 45 |
合计 | 845 | 935 |
一.代码设计
代码的核心功能是计算两篇文章的相似度,为了清晰地组织代码,可以将功能划分为以下几个类和函数:
-
函数一共有1个主类(main)和5个方法
-
方法:
-
1.readFile(String filePath): String:读取文件内容。
-
2.getWordFrequency(String text): Map<String, Integer>:分词并统计词频。
-
3.calculateCosineSimilarity(Map<String, Integer> map1, Map<String, Integer> map2): double:计算余弦相似度。
-
4.calculateNorm(List
vector) : double:计算向量模长。 -
5.writeResult(String outputPath, double similarity): void:将结果写入文件。
-
-
流程图
-
计算模块接口的设计与实现过程:计算模块采用了模块化设计,主要包含 Main 入口类、PlagiarismChecker 查重核心类 和 FileHandler 文件处理类。Main 负责程序的启动和流程控制,PlagiarismChecker 提供分词、词频统计和余弦相似度计算功能,FileHandler 负责文件的读写操作。
-
核心算法包括:分词与词频统计,通过正则表达式对文本进行分词,并统计每个词语的频率;余弦相似度计算,基于词频向量计算点积和模长,衡量文本相似性;文本预处理,过滤停用词和空字符串,确保词频统计的准确性。最终相似度得分通过余弦相似度计算得出,结果精确到小数点后两位。
算法关键
-
分词:使用简单的正则表达式按空格和标点符号分割文本。
-
词频统计:使用 HashMap 统计每个词语的频率。
-
余弦相似度:基于词频向量计算相似度
公式为:
\(cosinesimilarity=dotproduct/norm1×norm2\)
其中:dot_product 是两个向量的点积,norm1 和 norm2 是两个向量的模长。
独到之处
-
使用简单的分词方法,适合处理短文本。
-
通过余弦相似度衡量文本相似性,能够有效处理词频差异。
二.计算模块接口的性能改进
性能分析
性能分析图如下:
分析:可能是文件 I/O 操作,文件写入操作(BufferedWriter)涉及磁盘 I/O,导致比内存操作(如分词和词频统计)慢得多。或者是因为频繁写入,或者每次写入的数据量较大,会导致性能开销显著增加。
性能改进思路
-
优化分词方法:使用更高效的分词工具(如 Jieba 分词库)替代简单的正则表达式分词。
-
减少内存占用:使用 StringBuilder 替代 String 拼接文件内容。
-
并行计算:将词频统计和向量计算并行化,利用多核 CPU 提高性能。
-
算法变化:可以采用Jaccard算法计算重复率
三.计算模块部分单元测试
单元测试代码
部分代码展示如下:
其中重要的有
-
testCalculateCosineSimilarity:测试 PlagiarismChecker 类的 calculateCosineSimilarity 方法。构造两个词频映射,验证计算结果是否正确。
-
testCalculateNorm:测试 PlagiarismChecker 类的 calculateNorm 方法。输入一个向量 [3, 4],验证计算结果是否为 5。
-
testCalculateCosineSimilarityEmptyMaps:测试空词频映射的余弦相似度计算。输入两个空映射,验证结果是否为 0。
通过这些测试代码,可以保证代码的正确性和健壮性。
代码异常处理
-
1. 文件不存在异常
设计目标:当输入文件路径无效或文件不存在时,抛出异常并提示用户。
场景:用户提供的文件路径错误,或者文件被删除、移动。
-
2. 文件内容为空异常
设计目标:当文件内容为空时,抛出异常并提示用户。
场景:用户提供的文件是空文件,或者文件内容被清空。
-
3. 文件写入异常
设计目标:当结果文件无法写入时,抛出异常并提示用户。
场景:输出文件路径无效,或者文件被占用。