第一次个人编程作业
| 这个作业属于哪个课程 | 软件工程 |
|---|---|
| 这个作业要求在哪里 | 作业要求 |
| 这个作业的目标 | 练习代码测试 |
GitHub地址: https://github.com/alanthegoat
1.题目:论文查重
描述如下:
设计一个论文查重算法,给出一个原文文件和一个在这份原文上经过了增删改的抄袭版论文的文件,在答案文件中输出其重复率。
原文示例:今天是星期天,天气晴,今天晚上我要去看电影。
抄袭版示例:今天是周天,天气晴朗,我晚上要去看电影。
要求输入输出采用文件输入输出,规范如下:
从命令行参数给出:论文原文的文件的绝对路径。
从命令行参数给出:抄袭版论文的文件的绝对路径。
从命令行参数给出:输出的答案文件的绝对路径。
我们提供一份样例,课堂上下发,上传到班级群,使用方法是:orig.txt是原文,其他orig_add.txt等均为抄袭版论文。
注意:答案文件中输出的答案为浮点型,精确到小数点后两位。
2.算法的选择
上网查看论文查重的算法,主要有一下选择:
1.SimHash算法。
2.余弦定理计算文本相似度:**cosA=<a,b>/|a||b|**。
详细的内容点这里:[算法介绍](https://blog.csdn.net/liuxiangke0210/article/details/85258467)
3.Jaccard index:Jaccard系数的计算方式为:交集个数和并集个数的比值。
最终我采用了SimHash算法计算文本相似度,大概思路如下:
传统哈希的弊端:
举个例子,我们假设有以下三段文本:
the cat sat on the mat
the cat sat on a mat
we all scream for ice cream
使用传统hash可能会得到如下的结果:
irb(main):006:0> p1 = 'the cat sat on the mat'
irb(main):007:0> p1.hash => 415542861
irb(main):005:0> p2 = 'the cat sat on a mat'
irb(main):007:0> p2.hash => 668720516
irb(main):007:0> p3 = 'we all scream for ice cream'
irb(main):007:0> p3.hash => 767429688 "
可理想当中的hash函数,需要对几乎相同的输入内容,产生相同或者相近的hash值,换言之,hash值的相似程度要能直接反映输入内容的相似程度,故md5等传统hash方法也无法满足我们的需求。
SimHash问世:
流程
simhash算法分为5个步骤:分词、hash、加权、合并、降维,具体过程如下所述:
1.分词
给定一段语句,进行分词,得到有效的特征向量,然后为每一个特征向量设置1-5等5个级别的权重(如果是给定一个文本,那么特征向量可以是文本中的词,其权重可以是这个词出现的次数)。例如给定一段语句:“CSDN博客结构之法算法之道的作者July”,分词后为:“CSDN 博客 结构 之 法 算法 之 道 的 作者 July”,然后为每个特征向量赋予权值:CSDN(4) 博客(5) 结构(3) 之(1) 法(2) 算法(3) 之(1) 道(2) 的(1) 作者(5) July(5),其中括号里的数字代表这个单词在整条语句中的重要程度,数字越大代表越重要。
2.hash
通过hash函数计算各个特征向量的hash值,hash值为二进制数01组成的n-bit签名。比如“CSDN”的hash值Hash(CSDN)为100101,“博客”的hash值Hash(博客)为“101011”。就这样,字符串就变成了一系列数字。
3.加权
在hash值的基础上,给所有特征向量进行加权,即W = Hash * weight,且遇到1则hash值和权值正相乘,遇到0则hash值和权值负相乘。例如给“CSDN”的hash值“100101”加权得到:W(CSDN) = 100101 4 = 4 -4 -4 4 -4 4,给“博客”的hash值“101011”加权得到:W(博客)=101011 5 = 5 -5 5 -5 5 5,其余特征向量类似此般操作。
4.合并
将上述各个特征向量的加权结果累加,变成只有一个序列串。拿前两个特征向量举例,例如“CSDN”的“4 -4 -4 4 -4 4”和“博客”的“5 -5 5 -5 5 5”进行累加,得到“4+5 -4+-5 -4+5 4+-5 -4+5 4+5”,得到“9 -9 1 -1 1”。
5.降维
对于n-bit签名的累加结果,如果大于0则置1,否则置0,从而得到该语句的simhash值,最后我们便可以根据不同语句simhash的海明距离来判断它们的相似度。例如把上面计算出来的“9 -9 1 -1 1 9”降维(某位大于0记为1,小于0记为0),得到的01串为:“1 0 1 0 1 1”,从而形成它们的simhash签名。
3.计算模块接口的设计与实现过程
工程总览:

用到的类
1.文件读取工具类

2.SimHash算法核心类

主要函数及功能:
1.分词
导入分词器的依赖

使用分词器StandardTokenizer

2.hash
这里分词后,通过hash函数计算各个分词的hash值。

3.加权
这里规定分词的权重。

4.合并
在这里对单个hash后的分词进行特征向量化,转成特定位数的特征向量,通过加权后合并。

5.降维
通过此处降维,返回文档的SimHash。

独到之处

这里可以对html代码进行过滤。
程序运行截图

4.计算模块接口部分的性能改进
消耗最大的函数

类的使用情况

改进
在读取文件时,使用缓冲流和StringBuilder提升性能。

5.计算模块部分单元测试展示
使用junit进行单元测试。



6.计算模块部分异常处理说明
异常处理主要是两个,一是比较文件中有空文件,此时无需比较;二是文件路径不正确,不能找到文件。
1.发现空文件

测试

2.路径错误
用File类里面自带的异常。
测试

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

浙公网安备 33010602011771号