日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

【单机版,以两个文件为例】K-Shingle+最小Hash签名+LSH算法+LSH族....Java代码

發布時間:2023/12/20 java 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【单机版,以两个文件为例】K-Shingle+最小Hash签名+LSH算法+LSH族....Java代码 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
import java.util.ArrayList; import java.util.Random; import java.util.Scanner; import java.io.*; import java.util.regex.Matcher; import java.util.regex.Pattern;//只能處理a-z+空格 public class ShingleSet {String filepath;int k;int signatureNumber;int times;int [] randomArray;int [] randomArrayForLSH;ArrayList <String> array=new ArrayList <String>();//存儲所有的Shingles的集合,這些Shingles是無序的/**數組中的值是哈希桶的編號,即各個Shingles對應的桶號,和Shingles在array中的順序相同但也是無序的,可以看做矩陣的行號,* * 但這些行號并沒有按從小到大排序* * 從array變到resultOfHashToShingle的過程采用了相同的哈希函數** 如果是多篇文檔的話,各自的resultOfHashToShingle數組中存儲的桶號并不相同,也沒有按照桶號的順序來存儲,僅僅存儲了文* * 檔的shingles都被哈希到了哪些桶* */long [] resultOfHashToShingle;long [] signature;//這個數組用于存儲文本的簽名矩陣int bandNumber;int [] bucketNumber;//這個數組用于存儲簽名被哈希到的桶號int [] bucketNumberANDOR;//這個數組用于存儲簽名被哈希到的桶號BufferedReader inputStream;public ShingleSet (String filepath,int k,int signatureNumber,int bandNumber,int times, int[] randomArray,int [] randomArrayForLSH){this.filepath=filepath; this.k=k; this.signatureNumber=signatureNumber;this.bandNumber=bandNumber;this.times=times;this.randomArray=randomArray;this.randomArrayForLSH=randomArrayForLSH;}public void createShingleSet() {try{inputStream =new BufferedReader(new FileReader(filepath));String line=inputStream.readLine();Pattern p = Pattern.compile("\\s+|\t|\r|\n");//去掉讀入行的空格,制表,換行,回車while(line!=null){Matcher m = p.matcher(line);line = m.replaceAll(" ");if(!(line.length()<k)){//這塊的處理有點粗糙,行過短的被忽略,并且是先讀入行再進行去除制表符、回車等字符int start =0;String tmp=null;do{tmp=line.substring(start,start+(k-1));start++;if(!array.contains(tmp)){array.add(tmp);//如果文檔長度不同的話,自己所包含的shingle種類大小可能也不同}}while(!(start>line.length()-(k-1)));}line=inputStream.readLine();}}catch(FileNotFoundException e){System.out.println("文檔打開出錯");}catch(IOException e){System.out.println("文檔讀取出錯");}}public void hashToShingle(){resultOfHashToShingle=new long[array.size()];for(int i=0;i<array.size();i++){String tmp=array.get(i);long sum=0;//設為longfor(int t=0;t<k-4;t++){char[] chartmp=tmp.substring(t,t+4).toCharArray();//將九位字符串中的連續四位以字符數組的形式存儲//將字符串轉化為32位整數。這里的強制類型轉換將char轉為int,再將double轉long時,由于double此時為整數且不大于long最大值,所以轉換無損long inttmp=(long)((int)chartmp[0]*Math.pow(128,3)+(int)chartmp[1]*Math.pow(128,2)+(int)chartmp[2]*Math.pow(128,1)+(int)chartmp[3]*Math.pow(128,0));sum+=inttmp;}long hashResult=(sum%(long)Math.pow(2,32));//java中模運算的操作數范圍大;將字符串哈希到2^32個桶中,而int占-2^31到+2^31。但桶數目小于27^9//hashResult的結果是0-2^32-1resultOfHashToShingle[i]=hashResult;}}/**對所有的桶重新進行大量哈希,每個哈希取最小的桶號* * 強制沒和哈希函數的結果共有27^9個桶(每個哈希函數的桶數目可以不一樣嗎?)因為27^9中字符串* */public void produceSignature(){signature=new long[signatureNumber];for(int i=0;i<signatureNumber;i++){long min=(long)Math.pow(27, k);//一個哈希函數將resultOfHashToShingle中的桶號在重新排序到27^k個桶中,找出最小的桶號即為簽名存儲進signature即可for(int t=0;t<resultOfHashToShingle.length;t++){long tmp=(resultOfHashToShingle[t]*randomArray[2*i]+randomArray[2*i+1])%(long)Math.pow(27, k);//結果是0-27^kif(tmp<min) min=tmp;}signature[i]=min;}} public void localitySensitiveHahing(){int rows=signatureNumber/bandNumber;//因為有bandNumber個行條,所以使得哈希函數也有bandNumber*time個桶。同一個行條必須使用同一個哈希函數。//這里不同行條使用了不同的hash函數//所以,第i個行條的哈希值=[(行條內簽名之和)*randomArray[row*i]+randomArray(row*i+1)]%(bandNumber*time)//對一個文檔的簽名向量的每個行條使用一個哈希函數,并存入了數組bucketNumber,對每篇文檔的簽明進行了bandNumber次hashbucketNumber=new int[bandNumber];for(int i=0;i<bandNumber;i++){int begin=i*rows;int end=(i+1)*rows;long sum=0;for(int t=begin;t<end;t++) sum+=signature[t];//將本文檔的第i行條的哈希值(即被哈希到的桶號)放入bucketNumber[i],如果兩個文檔的bucketNumber[i]相等,這說明這兩個文檔的第i個行條完全一樣//每個行條一組桶。bucketNumber[i]=(int)((sum*randomArray[rows*i]+randomArray[rows*i+1])%(bandNumber*times));}//與構造+或構造,選用的hash函數并不一定要是在局部敏感哈希中使用過的哈希函數。所以在再這里再構造4*4*bucketNumber個哈希函數對文檔進行重新處理//也就是對每個行條是用來16個hash函數//每個行條使用不同的hash函數,并將結果存入數組,每篇文檔進行了4*4*bandNumber次哈希。bucketNumberANDOR=new int[4*4*bandNumber];for(int i=0;i<bandNumber;i++){int begin=i*rows;int end=(i+1)*rows;long sum=0;for(int t=begin;t<end;t++) sum+=signature[t];for(int k=0;k<(4*4);k+=2) bucketNumberANDOR[(4*4)*i+k]=(int)((sum*randomArrayForLSH[(4*4)*i+k]+randomArrayForLSH[(4*4)*i+k+1])%(bandNumber*times));}}public void run() {this.createShingleSet();this.hashToShingle();this.produceSignature();this.localitySensitiveHahing();}public static void main(String[] args){int bandNumber=1;int times=100;int signatureNumber=100;double Jaccard;int [] randomArray;Scanner keyboard=new Scanner(System.in);//產生最小哈希簽名的哈希函數數目強制設初始化為100個(100對隨機數),即每個文本有100個簽名,下邊進行重新賦值。System.out.println("請問您希望將使用多少個Hash函數用于為文檔產生簽名?");signatureNumber=keyboard.nextInt();randomArray=new int [signatureNumber*2];Random random = new Random();for(int i=0;i<signatureNumber;i++){int tmp=(int)Math.pow(signatureNumber,0.5);randomArray[2*i]=(Math.abs(random.nextInt())%tmp)+1;//隨機數在0-(tmp-1),改為1-tmprandomArray[2*i+1]=(Math.abs(random.nextInt())%tmp)+1;}//根據簽名向量的長度以及預期的相似度來確定行條的數目,對double進行了運算,可能產生誤差System.out.println("請問您希望將相似度為多少的文檔在LSH過程中盡可能成為后選對?");Jaccard=keyboard.nextDouble();System.out.println("請問您希望在LSH過程中哈希桶的數目是行條數的幾倍?");times=keyboard.nextInt();keyboard.close();double difference=Math.abs(Math.pow(1.0/1.0,1.0/100.0)-Jaccard); for(int i=2;i<=signatureNumber;i++){if(signatureNumber%i==0){double tmp=Math.abs(Math.pow((double)1/(double)i,(double)i/(double)signatureNumber)-Jaccard);System.out.printf("行條=%4d時 ",i);System.out.printf("差值為%8f",tmp);if(tmp<difference) {difference=tmp;bandNumber=i;System.out.println(" 行條被改變");}else{System.out.println(" 行條未改變");}}}System.out.println("簽名矩陣被分為了"+bandNumber+"個行條");int [] randomArrayForLSH=new int [4*4*bandNumber];for(int i=0;i<(4*4*bandNumber);i++){//將所需hash數目開方得出的數字作為mod后的值,因這樣使得mod后的值盡量小,同時從概率角度認為恰好可以產生足夠個不同的hash函數//運行測試程序過程中出現過F2產生的相同行條相等情況多于F產生的。可能的原因是出現了系數使得出現hash沖突,而這系數被使用了四次。但是//增加hash系數的范圍似乎并不能避免這種系數相同的情況//在簽名足夠多時也可能無法區分,原因如上。不過會不會系數并沒連續使用四次,而僅僅是因為四對系數均哈希沖突//在簽名數目過少時也會出現F2無法鑒別不同行的情況,原因可能是簽名少,所以行條少,所以系數的范圍小,所以系數被重復使用。所以“與”無效//當行條少時,桶的數目也會變少int tmp=(int)Math.pow(4*4*bandNumber,0.5 );randomArrayForLSH[i]=(Math.abs(random.nextInt())%tmp)+1;//隨機數在0-(tmp-1),改為1-tmp}ShingleSet test1=new ShingleSet ("C:\\Users\\fujiaxiaoshao\\Desktop\\test1.txt",5,signatureNumber,bandNumber,times,randomArray,randomArrayForLSH);ShingleSet test2=new ShingleSet ("C:\\Users\\fujiaxiaoshao\\Desktop\\test2.txt",5,signatureNumber,bandNumber,times,randomArray,randomArrayForLSH);test1.run();test2.run();System.out.println("文檔的簽名為:");for(int i=0;i<signatureNumber;i++){System.out.printf("%5d",(i+1));System.out.printf("%20d",test1.signature[i]);System.out.printf("%20d",test2.signature[i]);System.out.println("");}for(int i=0;i<signatureNumber;i++){if(test1.signature[i]==test2.signature[i])System.out.printf("第%3d個簽名相等,簽名為:%-13d位于第%d個行條\n",(i+1),test1.signature[i],((i/(signatureNumber/bandNumber))+1));}System.out.println("\n\n使用"+bandNumber+"個哈希函數,每個哈希函數的桶數目是行條數的"+times+"倍,每個哈希函數hash一個行條:");int countF=0;for(int i=0;i<bandNumber;i++){if(test1.bucketNumber[i]==test2.bucketNumber[i]){countF++;System.out.printf("\n在第"+(i+1)+"個行條中,兩個文檔都被哈希到了第"+test1.bucketNumber[i]+"個桶中\n");System.out.printf("在第"+(i+1)+"個行條中的所有簽名為:\n");long sumOfTest1=0;long sumOfTest2=0;for(int t=(signatureNumber/bandNumber)*i;t<(signatureNumber/bandNumber)*(i+1);t++){System.out.printf("%5d",t+1);sumOfTest1+=test1.signature[t];System.out.printf("%20d",test1.signature[t]);sumOfTest2+=test2.signature[t];System.out.printf("%20d\n",test2.signature[t]);}System.out.printf("和:");System.out.printf("%d",sumOfTest1);System.out.printf(" %d\n",sumOfTest2);System.out.printf("模:");System.out.printf("%d %d\n",(sumOfTest1*randomArray[(signatureNumber/bandNumber)*i]+randomArray[(signatureNumber/bandNumber)*i+1])%(times*bandNumber),(sumOfTest2*randomArray[(signatureNumber/bandNumber)*i]+randomArray[(signatureNumber/bandNumber)*i+1])%(times*bandNumber));}}System.out.println("\n使用"+(4*4*bandNumber)+"個哈希函數,每個哈希函數的桶數目是行條數的"+times+"倍,"+(4*4)+"個哈希函數hash一個行條:");int countF2=0;for(int k=0;k<bandNumber;k++){int count=0;for(int i=0;i<(4*4);i+=4){if(test1.bucketNumberANDOR[(4*4)*k+i]==test2.bucketNumberANDOR[(4*4)*k+i]&&test1.bucketNumberANDOR[(4*4)*k+i+1]==test2.bucketNumberANDOR[(4*4)*k+i+1]&&test1.bucketNumberANDOR[(4*4)*k+i+2]==test2.bucketNumberANDOR[(4*4)*k+i+2]&&test1.bucketNumberANDOR[(4*4)*k+i+3]==test2.bucketNumberANDOR[(4*4)*k+i+3])count++;}if(count!=0) {countF2++;System.out.printf("在第%5d個行條中,兩個文檔的簽名很大概率保證完全相同\n",(k+1));}}System.out.printf("\n使用F時,得到相同的行條為:"+countF+"個\n使用F2時,得到相同的行條為:"+countF2+"個");}}

關于三個參數的的設置問題:

1.使用多少個Hash函數用于為文檔產生簽名?

使用的哈希函數不能太少,少量的哈希函數產生的簽名可能并不足以代表文檔本身。也就是說當每篇文檔的簽名太少時,兩篇文檔簽名的相似度和文檔本身的相似度或許并不相符。

使用的哈希函數不能太多,如果哈希函數太多,可能導致簽名矩陣的行數比文檔的shingles集合矩陣的行數還要多,也就是說,在將shingles集合壓縮成簽名的過程并沒有使得矩陣變小反而增大。

2.將相似度為多少的文檔在LSH過程中盡可能成為后選對?

如果希望將相似度0.8的文檔成為后選對,則將0.8-0.1=0.7設為參數,這樣使得相似度0,8非常可能成為后選對。閾值定義的越低,行條越多,閾值越高行條越少。

3.在LSH過程中哈希桶的數目是行條數的幾倍?

局部敏感哈希過程中,輸入的參數的數目等于行條的數目,當桶數目為1倍時,恰好桶數目足夠。當然也很有可能產生哈希沖突,如果為2倍的話,哈希沖突的可能性會降低。這時候對程序的執行效率并不會降低。因為僅僅是增加了hash函數的mod后的數值。

總結

以上是生活随笔為你收集整理的【单机版,以两个文件为例】K-Shingle+最小Hash签名+LSH算法+LSH族....Java代码的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。