国产99久久精品_欧美日本韩国一区二区_激情小说综合网_欧美一级二级视频_午夜av电影_日本久久精品视频

最新文章專題視頻專題問答1問答10問答100問答1000問答2000關(guān)鍵字專題1關(guān)鍵字專題50關(guān)鍵字專題500關(guān)鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關(guān)鍵字專題關(guān)鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
當(dāng)前位置: 首頁 - 科技 - 知識百科 - 正文

海量數(shù)據(jù)處理算法之BloomFilter

來源:懂視網(wǎng) 責(zé)編:小采 時間:2020-11-09 14:07:08
文檔

海量數(shù)據(jù)處理算法之BloomFilter

海量數(shù)據(jù)處理算法之BloomFilter:算法介紹 Bloom Filter的中文名稱叫做布隆過濾器,因為他最早的提出者叫做布隆(Bloom),因而而得此名。布隆過濾器簡單的說就是為了檢索一個元素是否存在于某個集合當(dāng)中,以此實(shí)現(xiàn)數(shù)據(jù)的過濾。也許你會想,這還不簡單,判斷元素是否存在某集合中,遍歷集合,
推薦度:
導(dǎo)讀海量數(shù)據(jù)處理算法之BloomFilter:算法介紹 Bloom Filter的中文名稱叫做布隆過濾器,因為他最早的提出者叫做布隆(Bloom),因而而得此名。布隆過濾器簡單的說就是為了檢索一個元素是否存在于某個集合當(dāng)中,以此實(shí)現(xiàn)數(shù)據(jù)的過濾。也許你會想,這還不簡單,判斷元素是否存在某集合中,遍歷集合,

算法介紹 Bloom Filter的中文名稱叫做布隆過濾器,因為他最早的提出者叫做布隆(Bloom),因而而得此名。布隆過濾器簡單的說就是為了檢索一個元素是否存在于某個集合當(dāng)中,以此實(shí)現(xiàn)數(shù)據(jù)的過濾。也許你會想,這還不簡單,判斷元素是否存在某集合中,遍歷集合,

算法介紹

Bloom Filter的中文名稱叫做布隆過濾器,因為他最早的提出者叫做布隆(Bloom),因而而得此名。布隆過濾器簡單的說就是為了檢索一個元素是否存在于某個集合當(dāng)中,以此實(shí)現(xiàn)數(shù)據(jù)的過濾。也許你會想,這還不簡單,判斷元素是否存在某集合中,遍歷集合,一個個去比較不就能得出結(jié)果,當(dāng)然這沒有任何的問題,但是當(dāng)你面對的是海量數(shù)據(jù)的時候,在空間和時間上的代價是非常恐怖的,顯然需要更好的辦法來解決這個問題,而Bloom Filter就是一個不錯的算法。具體怎么實(shí)現(xiàn),接著往下看。

Bloom Filter

先來說說傳統(tǒng)的元素檢索的辦法,比如說事先在內(nèi)存中存儲了一堆的url字符數(shù)組,然后給定一個指定的url,判斷是否存在于之前的集合中,我們肯定是加載整個數(shù)組到內(nèi)存中,然后一個個去比較,假設(shè)每條url字符平均所占的量只有幾個字節(jié),但是當(dāng)數(shù)據(jù)變?yōu)楹A康臅r候,也足以撐爆整個內(nèi)存,這是空間上的一個局限。再者,逐次遍歷的方式本身就是一種暴力搜索,搜索的時間將會隨著集合容量的本身而線性擴(kuò)展,一旦數(shù)據(jù)量變大,查詢時間上的開銷也是非常恐怖的。針對時間和空間上的問題,Bloom Filter都給出了完美的解決辦法。首先第一個空間的問題,原本的數(shù)據(jù)占用的是字符,在這里我們用1個位占據(jù),也就是說1個元素我用1/8的字節(jié)表示,不管你的url長度是10個字符,100字符,統(tǒng)統(tǒng)用一個位表示,所以在這里我們需要能夠保證每個字符所代表的位不能沖突。因為用到了位的存儲,我們需要對數(shù)據(jù)進(jìn)行一個hash映射,以此得到他的位置,然后將此位置上的位置標(biāo)為1(默認(rèn)都是為0)。所以說白了,Bloom Filter就是由一個很長的位數(shù)組和一些隨機(jī)的哈希函數(shù)構(gòu)成。位數(shù)組你可以想象成下面的這種形式:

\

你可以想象這個長度非常長,反正1個單位就占據(jù)1個位,1k的空間就已經(jīng)能夠表示1024*8=8192位了。所以說內(nèi)存空間得到了巨大的節(jié)約。現(xiàn)在一個問題來了,為什么我剛剛用了一些隨機(jī)的哈希函數(shù)這個詞而不是說一個呢,因為會有哈希碰撞,再好的哈希函數(shù)也不能保證不會發(fā)生哈希沖突,所以這里需要采用多個哈希函數(shù),所以元素是否存在的判斷條件就變?yōu)榱酥挥兴械墓:瘮?shù)映射的位置的值都是true的情況下,此元素才是存在于集合中的,這樣判斷的準(zhǔn)確率就會大大提升了,哈希映射之后的效果圖如下:

\

假設(shè)我們的程序采用了如上圖所示的3個隨機(jī)獨(dú)立的哈希函數(shù),1個元素需要進(jìn)行3次不同的哈希函數(shù)的映射算法,對3個位置進(jìn)行標(biāo)記,對此元素的誤判概率我們做個計算,要使此元素誤判,就是說,他的這3個位置都有人占據(jù)了,就是說都與別的哈希函數(shù)有沖突,這最糟糕的情況就是他的3個映射位置與某個其他的元素通過哈希函數(shù)計算完全重疊,假設(shè)位空間長度1W位。每個位置被映射的概率就為1/1w,所以最糟糕的情況的沖突概率就是1/1w*1/1w*1/1w=1/10的12次方,如果最大的沖突概率的可能性呢,就是每個位置都與其中的某個哈希函數(shù)映射沖突,那誤差概率就是疊加的情況1/1w+1/1w+1/1w=0.0003。結(jié)果已經(jīng)非常明顯了,通過3個哈希函數(shù)就已經(jīng)能夠保證足夠低的誤判率了,更別說當(dāng)你用4個,5個哈希函數(shù)做映射的情況。下面問題又轉(zhuǎn)移到了我們用什么方式去作為位數(shù)組呢,int數(shù)組,字符char數(shù)組,答案都不是。結(jié)果在下面。

BitSet

這個是java中的某個數(shù)據(jù)類型,C,C++我目前不清楚有沒有這樣的類,為什么選用這個而不是前面說的int,或char數(shù)組,首先int當(dāng)然不行,1個int本身就有32位,占了4個字節(jié),用他做出0,1的存儲顯然相當(dāng)于沒省下空間,自然我們就想到了用字符數(shù)組char[],在C語言中1個char占一個字節(jié),而在java中由于編碼方式的不同,一個char占2個字節(jié),用char做存儲也只是稍稍比int介紹了一半的空間,并沒有真正的做到一個元素用一個位來表示,后來查了一下,java里面就有內(nèi)置了BitSet專門就是做位存儲的,還能夠進(jìn)行位相關(guān)的許多操作,他的操作其實(shí)就是和數(shù)組一樣,也是從0開始的。不熟悉的同學(xué)可以自行上網(wǎng)查閱相關(guān)資料,其實(shí)int數(shù)組也可以實(shí)現(xiàn)類似的功能,不過自己要做轉(zhuǎn)換,把int當(dāng)成32位來算,之前我寫過相關(guān)的文章,是關(guān)于位示圖法存儲大數(shù)據(jù)。

算法的實(shí)現(xiàn)

算法其實(shí)非常的簡單,我這里用一組少量的數(shù)據(jù)進(jìn)行模擬。

輸入數(shù)據(jù)input.txt:

mike
study
day
get
last
exam
think
fish
he
然后是測試數(shù)據(jù),用于查詢操作testInput.txt:
play
mike
study
day
get
Axis
last
exam
think
fish
he
其實(shí)就是我隨便組合的一些詞語。

算法的工具類BloomFilterTool.java:

package BloomFilter;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.HashMap;
import java.util.Map;

/**
 * 布隆過濾器算法工具類
 * 
 * @author lyq
 * 
 */
public class BloomFilterTool {
	// 位數(shù)組設(shè)置為10w位的長度
	public static final int BIT_ARRAY_LENGTH = 100000;

	// 原始文檔地址
	private String filePath;
	// 測試文檔地址
	private String testFilePath;
	// 用于存儲的位數(shù)組,一個單元用1個位存儲
	private BitSet bitStore;
	// 原始數(shù)據(jù)
	private ArrayList totalDatas;
	// 測試的查詢數(shù)據(jù)
	private ArrayList queryDatas;

	public BloomFilterTool(String filePath, String testFilePath) {
	this.filePath = filePath;
	this.testFilePath = testFilePath;

	this.totalDatas = readDataFile(this.filePath);
	this.queryDatas = readDataFile(this.testFilePath);
	}

	/**
	 * 從文件中讀取數(shù)據(jù)
	 */
	public ArrayList readDataFile(String path) {
	File file = new File(path);
	ArrayList dataArray = new ArrayList();

	try {
	BufferedReader in = new BufferedReader(new FileReader(file));
	String str;
	String[] tempArray;
	while ((str = in.readLine()) != null) {
	tempArray = str.split(" ");
	for(String word: tempArray){
	dataArray.add(word);
	}
	}
	in.close();
	} catch (IOException e) {
	e.getStackTrace();
	}

	return dataArray;
	}
	
	/**
	 * 獲取查詢總數(shù)據(jù)
	 * @return
	 */
	public ArrayList getQueryDatas(){
	return this.queryDatas;
	}

	/**
	 * 用位存儲數(shù)據(jù)
	 */
	private void bitStoreData() {
	long hashcode = 0;
	bitStore = new BitSet(BIT_ARRAY_LENGTH);

	for (String word : totalDatas) {
	// 對每個詞進(jìn)行3次哈希求值,減少哈希沖突的概率
	hashcode = BKDRHash(word);
	hashcode %= BIT_ARRAY_LENGTH;

	
	bitStore.set((int) hashcode, true);

	hashcode = SDBMHash(word);
	hashcode %= BIT_ARRAY_LENGTH;

	bitStore.set((int) hashcode, true);

	hashcode = DJBHash(word);
	hashcode %= BIT_ARRAY_LENGTH;

	bitStore.set((int) hashcode, true);
	}
	}

	/**
	 * 進(jìn)行數(shù)據(jù)的查詢,判斷原數(shù)據(jù)中是否存在目標(biāo)查詢數(shù)據(jù)
	 */
	public Map queryDatasByBF() {
	boolean isExist;
	long hashcode;
	int pos1;
	int pos2;
	int pos3;
	// 查詢詞的所屬情況圖
	Map word2exist = new HashMap();

	hashcode = 0;
	isExist = false;
	bitStoreData();
	for (String word : queryDatas) {
	isExist = false;
	
	hashcode = BKDRHash(word);
	pos1 = (int) (hashcode % BIT_ARRAY_LENGTH);

	hashcode = SDBMHash(word);
	pos2 = (int) (hashcode % BIT_ARRAY_LENGTH);

	hashcode = DJBHash(word);
	pos3 = (int) (hashcode % BIT_ARRAY_LENGTH);

	// 只有在3個哈希位置都存在才算真的存在
	if (bitStore.get(pos1) && bitStore.get(pos2) && bitStore.get(pos3)) {
	isExist = true;
	}

	// 將結(jié)果存入map
	word2exist.put(word, isExist);
	}

	return word2exist;
	}

	/**
	 * 進(jìn)行數(shù)據(jù)的查詢采用普通的過濾器方式就是,逐個查詢
	 */
	public Map queryDatasByNF() {
	boolean isExist = false;
	// 查詢詞的所屬情況圖
	Map word2exist = new HashMap();

	// 遍歷的方式去查找
	for (String qWord : queryDatas) {
	isExist = false;
	for (String word : totalDatas) {
	if (qWord.equals(word)) {
	isExist = true;
	break;
	}
	}

	word2exist.put(qWord, isExist);
	}

	return word2exist;
	}

	/**
	 * BKDR字符哈希算法
	 * 
	 * @param str
	 * @return
	 */
	private long BKDRHash(String str) {
	int seed = 31; /* 31 131 1313 13131 131313 etc.. */
	long hash = 0;
	int i = 0;

	for (i = 0; i < str.length(); i++) {
	hash = (hash * seed) + (str.charAt(i));
	}

	hash = Math.abs(hash);
	return hash;
	}

	/**
	 * SDB字符哈希算法
	 * 
	 * @param str
	 * @return
	 */
	private long SDBMHash(String str) {
	long hash = 0;
	int i = 0;
	
	for (i = 0; i < str.length(); i++) {
	hash = (str.charAt(i)) + (hash << 6) + (hash << 16) - hash;
	}

	hash = Math.abs(hash);
	return hash;
	}

	/**
	 * DJB字符哈希算法
	 * 
	 * @param str
	 * @return
	 */
	private long DJBHash(String str) {
	long hash = 5381;
	int i = 0;

	for (i = 0; i < str.length(); i++) {
	hash = ((hash << 5) + hash) + (str.charAt(i));
	}

	hash = Math.abs(hash);
	return hash;
	}

}
場景測試類Client.java:
package BloomFilter;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Map;

/**
 * BloomFileter布隆過濾器測試類
 * 
 * @author lyq
 * 
 */
public class Client {
	public static void main(String[] args) {
	String filePath = "C:\\Users\\lyq\\Desktop\\icon\\input.txt";
	String testFilePath = "C:\\Users\\lyq\\Desktop\\icon\\testInput.txt";
	// 總的查詢詞數(shù)
	int totalCount;
	// 正確的結(jié)果數(shù)
	int rightCount;
	long startTime = 0;
	long endTime = 0;
	// 布隆過濾器查詢結(jié)果
	Map bfMap;
	// 普通過濾器查詢結(jié)果
	Map nfMap;
	//查詢總數(shù)據(jù)
	ArrayList queryDatas;

	BloomFilterTool tool = new BloomFilterTool(filePath, testFilePath);

	// 采用布隆過濾器的方式進(jìn)行詞的查詢
	startTime = System.currentTimeMillis();
	bfMap = tool.queryDatasByBF();
	endTime = System.currentTimeMillis();
	System.out.println("BloomFilter算法耗時" + (endTime - startTime) + "ms");

	// 采用普通過濾器的方式進(jìn)行詞的查詢
	startTime = System.currentTimeMillis();
	nfMap = tool.queryDatasByNF();
	endTime = System.currentTimeMillis();
	System.out.println("普通遍歷查詢操作耗時" + (endTime - startTime) + "ms");

	boolean isExist;
	boolean isExist2;

	rightCount = 0;
	queryDatas = tool.getQueryDatas();
	totalCount = queryDatas.size();
	for (String qWord: queryDatas) {
	// 以遍歷的查詢的結(jié)果作為標(biāo)準(zhǔn)結(jié)果
	isExist = nfMap.get(qWord);
	isExist2 = bfMap.get(qWord);

	if (isExist == isExist2) {
	rightCount++;
	}else{
	System.out.println("預(yù)判錯誤的詞語:" + qWord);
	}
	}
	System.out.println(MessageFormat.format(
	"Bloom Filter的正確個數(shù)為{0},總查詢數(shù)為{1}個,正確率{2}", rightCount,
	totalCount, 1.0 * rightCount / totalCount));
	}
}
在算法的測試類中我對于Bloom Filter和普通的遍歷搜索方式進(jìn)行了時間上的性能比較,當(dāng)數(shù)據(jù)量比較小的時候,其實(shí)是看不出什么差距,甚至有可能布隆過濾器所花的時間可能更長比如我下面的某次測試結(jié)果:
BloomFilter算法耗時2ms
普通遍歷查詢操作耗時0ms
Bloom Filter的正確個數(shù)為11,總查詢數(shù)為11個,【本文來自鴻網(wǎng)互聯(lián) (http://www.68idc.cn)】正確率1
但是當(dāng)我用真實(shí)的測試數(shù)據(jù)進(jìn)行測試,我把原始數(shù)據(jù)緩存了一篇標(biāo)準(zhǔn)的文檔,然后把查詢的結(jié)果詞語數(shù)量進(jìn)行了翻倍,然后執(zhí)行同樣的程序結(jié)果變?yōu)榱讼旅孢@個樣子:
BloomFilter算法耗時16ms
普通遍歷查詢操作耗時47ms
Bloom Filter的正確個數(shù)為2,743,總查詢數(shù)為2,743個,正確率1
其實(shí)這還不足以模擬海量數(shù)據(jù)的場景,對于這個結(jié)果也不難理解,普通的暴力搜尋,是和原始數(shù)據(jù)的總量相關(guān),時間復(fù)雜度為O(n)的,而Bloom Filter,則是常量級別,做一個哈希映射就OK 了,時間復(fù)雜度O(l),

算法小結(jié)

算法在實(shí)現(xiàn)的過程中遇到了一些小問題,第一就是在使用哈希函數(shù)的時候,因為我是隨機(jī)的選了3個字符哈希函數(shù),后來發(fā)現(xiàn)老是會越界,一越界數(shù)值就會變?yōu)樨?fù)的再通過BitSet就會報錯,原本在C語言中可以用unsigned int來解決,java中沒有這個概念,于是就直接取hash絕對值了。Bloom Filter算法的一個特點(diǎn)是數(shù)據(jù)可能會出現(xiàn)誤判,但是絕對不會漏判,誤判就是把不是存在集合中的元素判定成有,理由是哈希沖突可能造成此結(jié)果,而漏判指的是存在的元素判定成了不存在集合中,這個是絕對不可能的,因為如果你存在,你所代表的位置就一定會有被哈希映射到,一旦映射到了,在你再去查找就不會漏掉。算法的應(yīng)用范圍其實(shí)挺多的,典型的比如垃圾郵箱地址的過濾。

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文檔

海量數(shù)據(jù)處理算法之BloomFilter

海量數(shù)據(jù)處理算法之BloomFilter:算法介紹 Bloom Filter的中文名稱叫做布隆過濾器,因為他最早的提出者叫做布隆(Bloom),因而而得此名。布隆過濾器簡單的說就是為了檢索一個元素是否存在于某個集合當(dāng)中,以此實(shí)現(xiàn)數(shù)據(jù)的過濾。也許你會想,這還不簡單,判斷元素是否存在某集合中,遍歷集合,
推薦度:
標(biāo)簽: 數(shù)據(jù) 介紹 算法
  • 熱門焦點(diǎn)

最新推薦

猜你喜歡

熱門推薦

專題
Top
主站蜘蛛池模板: 日韩成人在线视频 | 欧洲亚洲欧美国产日本高清 | 欧美激情在线精品一区二区 | 亚洲视频一区二区 | 极品国产高颜值露脸在线 | 亚洲情a成黄在线观看动 | 久久国产一区二区 | 精品国产成人综合久久小说 | 日韩aa在线观看 | 亚洲精品在线视频 | 亚洲一二三区在线观看 | 在线看精品 | 国产精品路线1路线2路线 | 亚洲国产精品久久久久 | 日韩有码在线观看 | 国产原创一区 | 九九国产精品视频 | 九草伊人 | 欧美综合国产精品日韩一 | 91香蕉国产 | 日韩欧美影院 | 国产亚洲免费观看 | 国产午夜视频在线 | 欧美精 | 亚洲一级毛片 | 国产区一区二 | 欧美日韩视频一区二区三区 | 欧美人与禽x0x0牲伦交 | 自拍偷拍欧美亚洲 | 日韩视频在线播放 | 亚洲精彩视频 | 亚洲欧洲在线观看 | 国产亚洲视频在线观看 | 精品视频一区二区三区 | 九九久久精品国产 | 在线观看国产精品入口 | 日韩小视频在线观看 | 91精品一区二区三区久久久久 | 高清国产一区二区三区 | 伊人久久亚洲综合天堂 | 综合 欧美 国产 视频二区 |