@祁俊辉,2017年6月4日测试。

1  说明

  • 本文章衔接关于SimHash算法的实现及测试V1.0;
  • 将Hash函数更新为MD5_Hash函数(二进制为128位);
  • 个人感觉用海明距离并不能只管说明两篇文章(字符串)相似,故添加相似度,但对于相似度的计算只是利用最简单的,有很多不妥之处。

2  MD5_Hash算法

2.1  MD5简介

MD5即“消息-摘要算法第五版”,是计算机领域广泛使用的一种散列函数,用以提供消息的完整性保护。

特点:

  1. 压缩性:任意长度的数据,算出的MD5值是长度固定的。
  2. 易计算:从原数据计算出MD5值很容易。
  3. 抗修改性:对原数据进行任何改动,所得到的MD5值都有很大区别。
  4. 强抗碰撞:已知原数据和其MD5值,想找到一个具有相同的MD5值的数据是非常困难的。

注:加密和摘要是不一样的!

  • 加密后的消息是完整的,具有解密算法,得到原始数据。
  • 摘要得到的消息是不完整的,通过摘要的数据,不能得到原始数据。

2.2  MD5长度问题

标准的MD5算法输出的是128bit二进制串。

但有些情况下,对于128bit数据不易处理,故取4bit成一个十六进制,常用32位十六进制串表示。

网上也有16位十六进制串所表示的MD5值,是将正常的32位十六进制串的前8位和后8位去掉,中间的部分所组成的16位十六进制串。

2.3  MD5应用

  • 一致性效验。如常见的下载站点中,常用MD5值验证用户得到的软件与站点提供的软件是否一致,或是否下载过程中出现丢失数据等情况。
  • 数字签名。如将文件经MD5映射为唯一“指纹”。(注:不是绝对的“唯一”)
  • 安全访问认证。如密码在数据库的存储。

2.4  MD5原理

简要叙述:MD5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。
详细过程请自行百度,本文不予叙述。

2.5  MD5算法的Java实现

 1 import java.math.BigInteger;
 2 import java.security.MessageDigest;
 3
 4 public class MD5 {
 5
 6     public static void main(String[] args) {
 7         String md5 = getMD5("中国");
 8         System.out.println(md5);
 9         String md6 = getMD5("SimHash");
10         System.out.println(md6);
11     }
12
13     public static String getMD5(String str) {
14         try{
15             //生成一个MD5加密计算摘要
16             MessageDigest md = MessageDigest.getInstance("MD5");
17             //计算md5函数
18             //md.update(str.getBytes());
19             //System.out.println("字符串:"+str);
20             //System.out.println("字符串的MD5_Hash:"+md.digest(str.getBytes()));
21             //digest()最后确定返回MD5_Hash值,返回值为8为字符串。因为MD5_Hash值是16位的hex值,实际上就是8位的字符
22             //BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值
23             //toString中可自由将返回值变换为十六进制或二进制串
24             return new BigInteger(1,md.digest(str.getBytes("UTF-8"))).toString(16);
25         }catch(Exception e){
26             e.printStackTrace();
27             return str;
28         }
29     }
30 }

注:中文字符必须使用“UTF-8”编码,否则会出错。

3  程序

  1 import java.math.BigInteger;
  2 import java.security.MessageDigest;
  3
  4 /* 【算法】SimHash->128位
  5  * 【说明】1.本程序手动分词,假设每个词的权重都为1
  6  * 【说明】2.对每个词进行MD5Hash算法,在此基础上加减权重
  7  * 【说明】3.将所有词整合后,降维
  8  * 【说明】4.计算各个句子的海明距离
  9  * 【时间】祁俊辉->2017.6.2
 10  * */
 11 public class SimHash_128 {
 12     //定义待比较的字符串
 13     static String s1="SimHash/算法/的/研究";
 14     static String s2="SimHash/算法/的/探讨";
 15     static String s3="SimHash/研究/的/算法";
 16     static String s4="SimHash/是/一种/文本/相似性/算法";
 17     //定义待比较的字符串
 18     static String s5="电视剧/小时代/由/郭敬明/的/同名/小说/改编/而/成/故事/以/经济/飞速/发展/的/上海/这/座/风光/而/时尚/的/城市/为/背景/讲述/了/林萧/南湘/顾里/唐宛如/这/四/个/从小/感情/深厚/有着/不同/价值观/和/人生观/的/女生/先后/所/经历/的/友情/爱情/乃至/亲情/的/巨大/转变/是/一/部/当下/年轻人/生活/一个/侧面/的/真实/写照";
 19     static String s6="电视剧/大时代/由/郭敬明/的/同名/小说/改编/而/成/该剧情/以/经济/飞速/发展/的/大上海/这/座/风光/而/时尚/的/城市/为/背景/讲述/了/林萧/南湘/顾里/唐宛如/这/四/个/从小/感情/深厚/有着/不同/价值观/和/人生观/的/女生/先后/所/经历/的/友情/爱情/乃至/亲情/的/巨大/转变/是/一/部/当下/年轻人/生活/一个/侧面/的/真实/写照";
 20     //定义待比较的字符串
 21     static String s7="你/妈妈/喊/你/回家/吃饭/哦/回家/喽/回家/喽";
 22     static String s8="你/妈妈/叫/你/回家/吃饭/哦/回家/喽/回家/喽";
 23     /* 函数名:MD5_Hash(String str)
 24      * 功能:计算字符串str的128位hash值,并将其以String型返回
 25      * */
 26     static String MD5_Hash(String str){
 27         try{
 28             // 生成一个MD5加密计算摘要
 29             MessageDigest md = MessageDigest.getInstance("MD5");
 30             // 计算md5函数
 31             //System.out.println("字符串:"+str);
 32             //System.out.println("字符串的MD5_Hash:"+md.digest(str.getBytes()));
 33             // digest()最后确定返回md5 hash值,返回值为8为字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符
 34             // BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值
 35             return new BigInteger(1,md.digest(str.getBytes("UTF-8"))).toString(2);
 36         }catch(Exception e){
 37             e.printStackTrace();
 38             return str;
 39         }
 40     }
 41     /* 函数名:First_FC(String str)
 42      * 功能:1.先创建一个存储SimHash值的128数组,并初始化为0
 43      * 功能:2.将str字符串分词,并存入临时数组
 44      * 功能:3.计算此字符串的SimHash值(加权、但没有降维),存储在数组中
 45      * 功能:4.将数组中的SimHash值降维,并以字符串形式返回
 46      * */
 47     static String First_FC(String str){
 48         //1.先创建一个存储SimHash值的128数组,并初始化为0
 49         int Hash_SZ[] = new int[128];
 50         for(int i=0;i<Hash_SZ.length;i++)
 51             Hash_SZ[i]=0;
 52         //2.将str字符串分词,并存入临时数组
 53         String[] newstr = str.split("/");
 54         //下面的for循环是为了增加前后文关联性//即12/23/34/45···
 55         /*for(int i=0;i<newstr.length-1;i++){
 56             newstr[i]=newstr[i]+newstr[i+1];
 57         }*/
 58         //相应的,若增加上面的关联性语句,下面一行的代码要改为
 59         //for(int i=0;i<newstr.length-1;i++){
 60         //3.计算此字符串的SimHash值(加权、但没有降维),存储在数组中
 61         for(int i=0;i<newstr.length;i++){//循环传入字符串的每个词
 62             String str_hash=MD5_Hash(newstr[i]);//先计算每一个词的Hash值(128位)
 63             //MD5哈希计算时,二进制转换若最高位为7以下,也就是转换成二进制最高位为0,会不存储该0,导致后面程序出错
 64             //这里主要是为了保证它是128位的二进制
 65             if(str_hash.length() < 128){
 66                 int que = 128 - str_hash.length();
 67                 for(int j=0;j<que;j++){
 68                     str_hash = "0" + str_hash;
 69                 }
 70             }
 71             //System.out.println(str_hash);//输出该词的128位MD5哈希值
 72             char str_hash_fb[]=str_hash.toCharArray();//将该词的哈希值转为数组,方便检查
 73             //System.out.println(Integer.toBinaryString(str_hash));
 74             //对每个词的Hash值(32位)求j位是1还是0,1的话加上该词的权重,0的话减去该词的权重
 75             for(int j=0;j<Hash_SZ.length;j++){
 76                 if(str_hash_fb[j] == '1'){
 77                     Hash_SZ[j]++;//Hash_SZ中,0是最高位,依次排低
 78                 }else{
 79                     Hash_SZ[j]--;
 80                 }
 81             }
 82         }
 83         //4.将数组中的SimHash值降维,并以字符串形式返回
 84         String SimHash_number="";//存储SimHash值
 85         for(int i=0;i<Hash_SZ.length;i++){//从高位到低位
 86             System.out.print(Hash_SZ[i]+" ");//输出未降维的串
 87             if(Hash_SZ[i]<=0)//小于等于0,就取0
 88                 SimHash_number += "0";
 89             else//大于0,就取1
 90                 SimHash_number += "1";
 91         }
 92         System.out.println("");//换行
 93         return SimHash_number;
 94     }
 95     /* 函数名:HMJL(String a,String b)
 96      * 功能:a、b都是以String存储的二进制数,计算他们的海明距离,并将其返回
 97      * */
 98     static int HMJL(String a,String b){
 99         char[] FW1 = a.toCharArray();//将a每一位都存入数组中
100         char[] FW2 = b.toCharArray();//将b每一位都存入数组中
101         int haiming=0;
102         if(FW1.length == FW2.length){//确保a和b的位数是相同的
103             for(int i=0;i<FW1.length;i++){
104                 if(FW1[i] != FW2[i])//如果该位不同,海明距离加1
105                     haiming++;
106             }
107         }
108         return haiming;
109     }
110
111     public static void main(String[] args) {
112         String a1 = First_FC(s1);
113         String a2 = First_FC(s2);
114         String a3 = First_FC(s3);
115         String a4 = First_FC(s4);
116         System.out.println("【s1】的SimHash值为:"+a1);
117         System.out.println("【s2】的SimHash值为:"+a2);
118         System.out.println("【s3】的SimHash值为:"+a3);
119         System.out.println("【s4】的SimHash值为:"+a4);
120         System.out.println("【s1】和【s2】的海明距离为:"+HMJL(a1,a2)+",相似度为:"+(100-HMJL(a1,a2)*100/128)+"%");
121         System.out.println("【s1】和【s3】的海明距离为:"+HMJL(a1,a3)+",相似度为:"+(100-HMJL(a1,a3)*100/128)+"%");
122         System.out.println("【s1】和【s4】的海明距离为:"+HMJL(a1,a4)+",相似度为:"+(100-HMJL(a1,a4)*100/128)+"%");
123         System.out.println("【s2】和【s3】的海明距离为:"+HMJL(a2,a3)+",相似度为:"+(100-HMJL(a2,a3)*100/128)+"%");
124         System.out.println("【s2】和【s4】的海明距离为:"+HMJL(a2,a4)+",相似度为:"+(100-HMJL(a2,a4)*100/128)+"%");
125         System.out.println("【s3】和【s4】的海明距离为:"+HMJL(a3,a4)+",相似度为:"+(100-HMJL(a3,a4)*100/128)+"%");
126
127         String a5 = First_FC(s5);
128         String a6 = First_FC(s6);
129         String a7 = First_FC(s7);
130         String a8 = First_FC(s8);
131         System.out.println("【s5】的SimHash值为:"+a5);
132         System.out.println("【s6】的SimHash值为:"+a6);
133         System.out.println("【s7】的SimHash值为:"+a7);
134         System.out.println("【s8】的SimHash值为:"+a8);
135         System.out.println("【s5】和【s6】的海明距离为:"+HMJL(a5,a6)+",相似度为:"+(100-HMJL(a5,a6)*100/128)+"%");
136         System.out.println("【s5】和【s7】的海明距离为:"+HMJL(a5,a7)+",相似度为:"+(100-HMJL(a5,a7)*100/128)+"%");
137         System.out.println("【s5】和【s8】的海明距离为:"+HMJL(a5,a8)+",相似度为:"+(100-HMJL(a5,a8)*100/128)+"%");
138         System.out.println("【s6】和【s7】的海明距离为:"+HMJL(a6,a7)+",相似度为:"+(100-HMJL(a6,a7)*100/128)+"%");
139         System.out.println("【s6】和【s8】的海明距离为:"+HMJL(a6,a8)+",相似度为:"+(100-HMJL(a6,a8)*100/128)+"%");
140         System.out.println("【s7】和【s8】的海明距离为:"+HMJL(a7,a8)+",相似度为:"+(100-HMJL(a7,a8)*100/128)+"%");
141     }
142 }

4  测试结果

4.1  第一个测试A1

测试时使用短字符串,对每个词使用的是128位MD5_Hash算法,此次测试并未考虑上下文相关性,四个字符串分别为:

  • S1:SimHash/算法/的/研究
  • S2:SimHash/算法/的/探讨
  • S3:SimHash/研究/的/算法
  • S4:SimHash/是/一种/文本/相似性/算法

未降维时四个字符串的SimHash值为(太长,截取了一部分):

降维后的SimHash值为(太长,截取了一部分):

计算各个字符串之间的海明距离:

结果与关于SimHash算法的实现及测试V1.0中的测试结果几乎相同,但更为明显,且增加了相似度的计算。

这里的相似度计算是用“(128-海明距离)/128”得到的,对于这个公式个人感觉是不正确的,但是目前还没有想到更好的办法,后期将会改正。

4.2  第二个测试A2

测试时使用中等长度字符串,对每个词使用的是128位MD5_Hash算法,此次测试并未考虑上下文相关性,四个字符串分别为:

  • S5:电视剧/小时代/由/郭敬明/的/同名/小说/改编/而/成/故事/以/经济/飞速/发展/的/上海/这/座/风光/而/时尚/的/城市/为/背景/讲述/了/林萧/南湘/顾里/唐宛如/这/四/个/从小/感情/深厚/有着/不同/价值观/和/人生观/的/女生/先后/所/经历/的/友情/爱情/乃至/亲情/的/巨大/转变/是/一/部/当下/年轻人/生活/一个/侧面/的/真实/写照
  • S6:电视剧/大时代/由/郭敬明/的/同名/小说/改编/而/成/该剧情/以/经济/飞速/发展/的/大上海/这/座/风光/而/时尚/的/城市/为/背景/讲述/了/林萧/南湘/顾里/唐宛如/这/四/个/从小/感情/深厚/有着/不同/价值观/和/人生观/的/女生/先后/所/经历/的/友情/爱情/乃至/亲情/的/巨大/转变/是/一/部/当下/年轻人/生活/一个/侧面/的/真实/写照
  • S7:你/妈妈/喊/你/回家/吃饭/哦/回家/喽/回家/喽
  • S8:你/妈妈/叫/你/回家/吃饭/哦/回家/喽/回家/喽

未降维时四个字符串的SimHash值为(太长,截取了一部分):

降维后的SimHash值为(太长,截取了一部分):

计算各个字符串之间的海明距离:

结果与关于SimHash算法的实现及测试V1.0中的测试结果几乎相同,但更为明显,且增加了相似度的计算。

可以看出,S5和S6、S7和S8之间的相似度都在90%以上,几乎可以断定两个字符串是相似的,确实他们本身也相似。而其他情况的相似度都在50%以下(因为根本很明显不是相似的),这与预期是相同的。

转载于:https://www.cnblogs.com/qijunhui/p/8448805.html

关于SimHash算法的实现及测试V2.0相关推荐

  1. linux下yolact算法的实现,测试自己的数据集

    ** 环境 Ubuntu16.0 pytorch1.3.0 pycharm 代码链接:https://github.com/dbolya/yolact 下载anaconda cudnn 均为最新版 下 ...

  2. 本文99.99%解答了你对CMMI V2.0的疑问,值得收藏!

    作为企业软件研发管理提升人力和流程能力的公认标准,CMMI系列模型已然成为全球范围内众多企业提升绩效.质量.产品及服务可靠性的重要法宝.目前,为应对不断变化的行业特性,CMMI V2.0版本于2018 ...

  3. 25.怎样在IDEA中使用JUnit4和JUnitGenerator V2.0自动生成测试模块

    转自:https://blog.csdn.net/wangyj1992/article/details/78387728 因为项目的需要,所以研究了一下自动生成测试代码.将经验记录下来,总会有用的.我 ...

  4. 小孔子文章管理系统V2.0发布测试

    小孔子文章管理系统V2.0 [感谢]  本系统是仿照nbArticle开发,在此表示感谢nb联盟的作品. [版权声明]                                          ...

  5. idea怎么运行eclipse的web项目_Apache Storm v2.0入门项目的开发、测试和运行(IDEA/Maven)...

    第一个Apache Storm v2.0流计算入门项目的开发.测试和运行(IDEA/Maven) 关于流计算框架Apache Storm最新版的安装,可以参考: 流计算框架-最新版Apache Sto ...

  6. 猪悟能淘宝商品下载专家v2.0 beta1.0版发布,欢迎测试!

    图1  软件界面 v2.0 版的功能介绍: .下载方式灵活,可以按店铺地址,掌柜名,宝贝分类下载,也可以下载单个宝贝 .这个版本已经可以把数据库的商品导出为淘宝CSV.拍拍CSV.有啊CSV格式.这样 ...

  7. 车载计算机模块,【荐】DIY车载电脑续:开模自制电路板(含DAC和7850)V2.0测试成功...

    更新:2015年3月31日,经过懈努力,2.0版测试成功,期间经历诸多波折.原车音响面板开关无损移植,音响部分按键灯也随电脑启动而亮了,虽然电路有点问题需要跳线,但个人还是比较满意.目前已卖出 ...

  8. 在IDEA中使用JUnit4和JUnitGenerator V2.0自动生成测试模块

    因为项目的需要,所以研究了一下自动生成测试代码.将经验记录下来,总会有用的.我个人认为,好记性不如多做笔记多反思总结. 1.    前提条件 开发环境已正确配置 工程已解决JUnit依赖关系(pom. ...

  9. 明远智睿MY-IMX6-EK200 Linux-4.1.15测试手册v2.0(3)

    [接上一章节明远智睿MY-IMX6-EK200 Linux-4.1.15测试手册v2.0(2)] 2.16  SPI测试(ECSPI1) [测试说明]:采用自发自收的方式测试. [接口标识]:SPI1 ...

最新文章

  1. 『网站升级』PHPWind8.0至8.3升级过程及问题种种回顾录
  2. 计算机书籍-大型网站性能优化实战
  3. matlab stract结构_MATLAB 的基础知识
  4. 文献学习(part29)
  5. Mike and gcd problem(思维)
  6. Socket网络编程--小小网盘程序(5)
  7. 2019/02/11-分布式数据库概述
  8. Microsoft.Web.RedisSessionStateProvider 运行异常问题
  9. python第四章单元测试_MOOC选修课答案第四章单元测试答案_Sar编程基础期末答案...
  10. aspx获取aspx.cs中的变量和方法
  11. C# RabbitMQ(一)介绍
  12. Python实现PDF复制自动去除换行及空格
  13. 数据分析——鸢尾花数据集
  14. 【强化学习】⚠️手把手带你走进强化学习 3⚠️ OPP 算法实现月球登陆器 (Tensorflow2 版)
  15. python身份证号判断_Python实现身份证号码解析
  16. java微信开发页面清除缓存,h5清理微信浏览器网页缓存
  17. 关于Flutter应用程序的AndroidX兼容性
  18. 李宏毅深度学习笔记(CNN)
  19. C语言 itoa函数及atoi函数
  20. 出现10048和9017错误提示的处理

热门文章

  1. 使用定时器按键扫描数码管制作一个可存储数据的秒表
  2. 一个应届生的应聘:直飞Google总部[zt]
  3. Happiness - Happier
  4. Rust交叉编译笔记
  5. 搭建个人博客:Web服务器的选择 Apache or Nginx ?
  6. 书法之美--篆书在线查询
  7. 黑产上演《三体》剧情:蠕虫病毒入侵手机群发“钓鱼”短信
  8. android仿微信发布动态功能,Android 类似微博、微信展示动态(Feed)的WeiBoLayout
  9. 搜索添加数据库+清空历史记录
  10. 高中计算机学考D可以过吗,学业水平d会影响三位一体或高考录取吗?浙江学考必须全过吗?全a难不难?...