关于SimHash算法的实现及测试V1.0

2021-02-20 00:05发布

@祁俊辉,2017年5月21日测试。

1  说明

  • 本程序是简化版的SimHash算法(分词暂为手动分词,每个词的权重都设为1);
  • 本程序是基于《数学之美 》第二版第16章所介绍的原理展开;
  • 本篇文章将计算多个字符串的SimHash值,并将对其分析;
  • 本篇文章暂不介绍SimHash算法的原理,因为网上的资源相对较杂,待我彻底理解,整理过后更新(已在笔记本中);
  • 本篇文章(程序)将持续更新。

2  程序(32位)

关于程序的解释,都在程序源码中有相应的注释。若有不明白之处,请联系本人:qce.hui@qq.com。

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

3  测试结果

3.1  第一个测试A1

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

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

未降维时四个字符串的SimHash值为:

降维后的SimHash值为:

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

从上可以看出,S1和S3之间的海明距离竟然为0,这是因为并未考虑上下文相关性,而S1和S3是相同的内容,但顺序不同。

另外,看似最相似的S1和S2之间的海明距离为4(因为这两个字符串只有最后两个字不一样)。

最后,S1、S2、S3都与S4之间的海明距离较大(比其他各个之间的大),这一点还蛮准确。

3.2  第二个测试A2

测试时使用短字符串,对每个词使用的是32位BKDRHash算法,此次测试考虑上下文相关性(主要是与第一个测试A1做对比),四个字符串分别为:

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

注:“考虑上下文相关性”,即比如S1字符串,将其分解为:“SimHash算法”、“算法的”、“的研究”。

未降维时四个字符串的SimHash值为:

降维后的SimHash值为:

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

从上可以看出,在这次测试的结果中,S1和S2之间的的海明距离最小(为6),也就是这两个字符串最为相似,这与预料中的是一样的。

另外,因为考虑到上下文相关性,S1和S3之间的海明距离也不再是0,说明这两个字符串之间还是有差别的。

最后,S1、S2、S3都与S4之间的海明距离较大(比其他各个之间的大),这一点相对于第一个测试A1更为明显。

3.3  第三个测试A3

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

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

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

降维后的SimHash值为:

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

从上可以看出,在这次测试的结果中,因为S5和S6本就是相似的(两个词不同),S7和S8本就是相似的(一个词不同),检测结果显示S5和S6、S7和S8之间的海明距离都非常小(1和0),而其他情况的海明距离就相对比较大了(因为根本很明显不是相似的),这与预期是相同的。

3.4  第四个测试A4

测试时使用中等长度字符串,对每个词使用的是32位BKDRHash算法,此次测试考虑上下文相关性(主要是与第三个测试A3做对比),四个字符串分别为:

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

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

降维后的SimHash值为:

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

从上可以看出,在这次测试的结果中,因为S5和S6本就是相似的(两个词不同),S7和S8本就是相似的(一个词不同),检测结果显示S5和S6、S7和S8之间的海明距离都非常小(1和0),而其他情况的海明距离就相对比较大了(因为根本很明显不是相似的),这与预期是相同的。

另外,与第三次测试A3相比较,这次的结果与上次基本相同(相似的海明距离小,不相似的海明距离大),只是海明距离数值有差别而已。

3.5  第五个测试A5

以上四个测试(A1~A4)中,对每个词使用的都是32位BKDRHash算法,至于这一块需要使用哪一种Hash转换算法,在我查找的资料中并没有给出明确表示,只有在一篇文章中说“使用传统的Hash算法”,下面对这一块做测试,将分别使用RSHash、BKDRHash、DJBHash、JSHash和SDBMHash。

本次测试以第一个测试A1为基准,测试时使用短字符串,对每个词分别使用32位的RSHash、BKDRHash、DJBHash、JSHash和SDBMHash(至于这几种Hash算法,请参考我的另一篇文章《关于Hash的几种常用算法》),此次测试并未考虑上下文相关性,四个字符串分别为:

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

本次测试将只看以上四个字符串的SimHash值(降维后)和各个字符串之间的海明距离:

RSHash

BKDRHash

DJBHash

JSHash

SDBMHash

此次测试总结:之前我以为,不管使用哪种Hash算法对词转换,最后得到的字符串之间海明距离是由规律的(比如最小的还是最小,最大的还是最大),可事实证明,然后并没有。

3.6  第六个测试A6

在第五个测试A5中,并未考虑上下文相关性,本次测试考虑上下文相关性,再次对5钟Hash算法进行比较。

本次测试以第一个测试A1为基准,测试时使用短字符串,对每个词分别使用32位的RSHash、BKDRHash、DJBHash、JSHash和SDBMHash(至于这几种Hash算法,请参考我的另一篇文章《关于Hash的几种常用算法》),此次测试考虑上下文相关性(主要是与第五个测试A5做对比),四个字符串分别为:

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

本次测试将只看以上四个字符串的SimHash值(降维后)和各个字符串之间的海明距离:

RSHash

BKDRHash

DJBHash

JSHash

SDBMHash

此次测试总结:此次测试结合第五次测试A5,几乎证明了在对文本进行SimHash时,对每个词Hash转换所使用的Hash算法还是对结果会产生较大影响的,但至于使用哪一种Hash算法更准确,我目前还不太清楚。

3.7  第七个测试A7

从前几次测试中,不知读者是否发现一个现象:在不考虑文本上下文相关性的前提下(文本相同),计算得到的SimHash值较小;考虑文本上下文相关性后(文本相同),计算得到的SimHash值相对较大。这与所使用的Hash函数有直接的关系,但是还有一个因素->每个词的长度。

当对每个词进行Hash函数转换时,大多数Hash函数是根据词的长度进行循环累乘的,所以考虑文本上下文相关性后,词的长度变长了,计算所得的Hash值固然就变长了,进而也就影响了SimHash值的长度(所有词的Hash累加)。

以上分析都是在相同文本下两种情况所产生的SimHash长度,当然,SimHash长度主要还与文本的长度有关,在进行大文本处理时,累加所产生的长度变化也是要考虑的。下面一段程序是基于第一次测试A1扩展成的64位SimHash算法,但是前面那么多位的“0”好像并没有太大意义哦。

注:怎么产生64位呢?其实就是“int”和“long”的差别,在对每个词进行Hash函数转换时,所使用的数值类型不同而已。

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

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

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

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

降维后的SimHash值为:

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

从上可以看出,与第一次测试A1所产生的结果完全相同,无非就是前面加了几个“0”而已。

可以得出:在进行短文本计算时,完全没必要使用64位的SimHash算法。

标签: