个人项目作业

这个作业属于哪个课程 软件工程
这个作业要求在哪里 个人项目作业
这个作业的目标 设计一个论文查重算法,通过练习进行学习

1.本次作业github链接:点击此处跳转至Github

2.PSP表格

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

3.写在前面

  • 编程语言:JAVA
  • IDEA版本:IntelliJ IDEA Community Edition 2020.2.4
  • 项目构建工具:maven
  • 单元测试工具:JUnitGenerator V2.0
  • 性能分析工具:JProfiler

4.计算模块接口部分的设计与实现过程

1.设计

  • 1.1 整体设计

  • 1.2 类
    Main:main 方法所在的类
    TxtIO:读写 txt 文件的工具类
    SimHash:计算 SimHash 值的类
    Hamming:计算海明距离的类
    ShortStringException:处理文本内容过短的异常类

  • 1.3 各类使用的方法

  • 1.3.1 TxtIO
    包含了两个静态方法:
    1、readTxt:读取txt文件
    2、writeTxt:写入txt文件

  • 1.3.2 SimHash
    包含了两个静态方法:
    1、getHash:传入String,计算出它的hash值,并以字符串形式输出,(使用了MD5获得hash值)
    2、getSimHash:传入String,计算出它的simHash值,并以字符串形式输出,(需要调用 getHash 方法)

  • 1.3.3 Hamming
    包含了两个静态方法:
    1、getHammingDistance:输入两个 simHash 值,计算出其海明距离 distance
    2、getSimilarity:输入两个 simHash 值,调用 getHammingDistance 方法得出海明距离 distance,再由 distance 计算出相似度。

2.关键算法:

①Simhash算法

  • 该算法主要原理:
    simhash是由 Charikar 在2002年提出来的,参考 《Similarity estimation techniques from rounding algorithms》 。
    介绍下这个算法主要原理,为了便于理解尽量不使用数学公式,分为这几步:
    1、分词,把需要判断文本分词形成这个文章的特征单词。最后形成去掉噪音词的单词序列并为每个词加上权重,我们假设权重分为5个级别(1~5)。比如:“ 美国“51区”雇员称内部有9架飞碟,曾看见灰色外星人 ” ==> 分词后为 “ 美国(4) 51区(5) 雇员(3) 称(1) 内部(2) 有(1) 9架(3) 飞碟(5) 曾(1) 看见(3) 灰色(4) 外星人(5)”,括号里是代表单词在整个句子里重要程度,数字越大越重要。
    2、hash,通过hash算法把每个词变成hash值,比如“美国”通过hash算法计算为 100101,“51区”通过hash算法计算为 101011。这样我们的字符串就变成了一串串数字,还记得文章开头说过的吗,要把文章变为数字计算才能提高相似度计算性能,现在是降维过程进行时。
    3、加权,通过 2步骤的hash生成结果,需要按照单词的权重形成加权数字串,比如“美国”的hash值为“100101”,通过加权计算为“4 -4 -4 4 -4 4”;“51区”的hash值为“101011”,通过加权计算为 “ 5 -5 5 -5 5 5”。
    4、合并,把上面各个单词算出来的序列值累加,变成只有一个序列串。比如 “美国”的 “4 -4 -4 4 -4 4”,“51区”的 “ 5 -5 5 -5 5 5”, 把每一位进行累加, “4+5 -4+-5 -4+5 4+-5 -4+5 4+5” ==》 “9 -9 1 -1 1 9”。这里作为示例只算了两个单词的,真实计算需要把所有单词的序列串累加。
    5、降维,把4步算出来的 “9 -9 1 -1 1 9” 变成 0 1 串,形成我们最终的simhash签名。 如果每一位大于0 记为 1,小于0 记为 0。最后算出结果为:“1 0 1 0 1 1”。
    整个过程图为:

参照文章:海量数据相似度计算之simhash和海明距离

  • 该算法的优势:
    SimHash是一种局部敏感hash,它也是Google公司进行海量网页去重使用的主要算法。
    传统的Hash算法只负责将原始内容尽量均匀随机地映射为一个签名值,原理上仅相当于伪随机数产生算法。传统的hash算法产生的两个签名,如果原始内容在一定概率下是相等的;如果不相等,除了说明原始内容不相等外,不再提供任何信息,因为即使原始内容只相差一个字节,所产生的签名也很可能差别很大。所以传统的Hash是无法在签名的维度上来衡量原内容的相似度,而SimHash本身属于一种局部敏感哈希算法,它产生的hash签名在一定程度上可以表征原内容的相似度。
    我们主要解决的是文本相似度计算,要比较的是两个文章是否相似,当然我们降维生成了hash签名也是用于这个目的。看到这里估计大家就明白了,我们使用的simhash就算把文章中的字符串变成 01 串也还是可以用于计算相似度的,而传统的hash却不行。
    我们可以来做个测试,两个相差只有一个字符的文本串,“你妈妈喊你回家吃饭哦,回家罗回家罗” 和 “你妈妈叫你回家吃饭啦,回家罗回家罗”。
    通过simhash计算结果为:
    1000010010101101111111100000101011010001001111100001001011001011
    1000010010101101011111100000101011010001001111100001101010001011
    通过传统hash计算为:
    0001000001100110100111011011110
    1010010001111111110010110011101

通过上面的例子我们可以很清晰的发现simhash的局部敏感性,相似文本只有部分01变化,而hash值很明显,即使变化很小一部分,也会相差很大。

参照文章:NLP点滴——文本相似度

②Hamming distance算法

两个simhash对应二进制(01串)取值不同的数量称为这两个simhash的海明距离。举例如下: 10101 和 00110 从第一位开始依次有第一位、第四、第五位不同,则海明距离为3。对于二进制字符串的a和b,海明距离为等于在a XOR b运算结果中1的个数(普遍算法)。
因此,我们通过海明距离(Hamming distance)就可以计算出两个simhash到底相似不相似。

参照文章:海量数据相似度计算之simhash和海明距离

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

  • 性能分析如下:
  • 实时内存为:
  • 从分析图可看出:
    调用次数最多的是com.hankcs.hanlp包提供的接口, 即分词、取关键词与计算词频花费了最多的时间。
    很遗憾,目前我能力有限,无法改进。

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

  • mainTest:

  • TxtIOTest:

  • HammingTest:

  • SimHashTest:

  • ShortStringExceptionTest:

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

待补充。

8.总结

1.实现设计的过程比预想更加艰难,也在实现的过程中发现了设计时存在的问题,导致不断更改。
2.由于一开始建工程时忘记选择maven导致做了很多无用功。
3.当出现无法解决但不应出现的问题时,应从头溯源,是否遗漏某些信息或操作失误。

posted @ 2021-09-17 13:30  nnny  阅读(37)  评论(0编辑  收藏  举报