1. 程式人生 > >大資料處理演算法--Bloom Filter

大資料處理演算法--Bloom Filter


一、布隆過濾器(Bloom Filter)的定義

布隆過濾器可以用來檢測資料是否存在於一個集合中。它是hash的擴充套件,底層就是一個位數組,每一個bit位可以表示一個數字,所以布隆過濾器是基於點陣圖來實現的。

二、布隆過濾器的原理

1、插入資料

在點陣圖中,每一個bit對應一個數字,出現一個數字就可以在相應的位上置1。但是布隆過濾器不一樣,它要處理的不僅僅是整型還有其他如string型別的資料,因此,當大量的string類資訊需要處理的時候,難免會引起大量的衝突。布隆過濾器在這裡的處理是用多個bit位來表示string型別的資料,這多個bit位通過不同的hash函式得出,這樣衝突的概率就減少了。

2、刪除資料

布隆過濾器不支援刪除資料,因為一個數據型別是由好幾個bit位來表示的,難免幾個資料的bit位會重疊,如果刪除一個bit位,其他的資料也可能受到影響。那麼如何實現布隆過濾器的刪除呢?這裡可以引入引用計數的概念,將位陣列擴充套件位整型陣列,陣列的下標對應資料通過hash函式得出的數,陣列中存放的是數字出現的次數,即引用計數。

3、檢測資料

同插入資料時一樣,這裡的資料需要用幾個hash函式得出多個bit位,如果每個bit位都存在於位陣列中,那麼這個資料可能存在。為什麼說是可能存在呢,因為有可能這個資料的幾個bit位是由其他資料置為1的。如果幾個bit中有一個為0,那麼這個資料一定就不存在了。

三、布隆過濾器的特點

1、優點:它相比於hash,紅黑樹等結構更加節省空間,而且插入效率和查詢效率都遠遠超過一般演算法

2、缺點:不支援刪除操作;查詢的結果不一定準確(結果為不存在時是準確的,為存在時是不準確的);

四、布隆過濾器的應用

 像網易,QQ這樣的公眾電子郵件(email)提供商,總是需要過濾來自發送垃圾郵件的人(spamer)的垃圾郵件。

一個辦法就是記錄下那些發垃圾郵件的 email地址。由於那些傳送者不停地在註冊新的地址,全世界少說也有幾十億個發垃圾郵件的地址,將他們都存起來則需要大量的網路伺服器。

如果用雜湊表,每儲存一億個 email地址,就需要 1.6GB的記憶體(用雜湊表實現的具體辦法是將每一個 email地址對應成一個八位元組的資訊指紋,然後將這些資訊指紋存入雜湊表,由於雜湊表的儲存效率一般只有 50%,因此一個email地址需要佔用十六個位元組。一億個地址大約要 1.6GB,即十六億位元組的記憶體)。因此存貯幾十億個郵件地址可能需要上百 GB的記憶體。

而Bloom Filter只需要雜湊表 1/8到 1/4 的大小就能解決同樣的問題。

BloomFilter決不會漏掉任何一個在黑名單中的可疑地址。而至於誤判問題,常見的補救辦法是在建立一個小的白名單,儲存那些可能別誤判的郵件地址。

五、布隆過濾器的實現

#include<iostream>
#include "bitmap.h"
using namespace std;

struct HashFunc1
{
	static size_t BKDRHash(const char *str)
	{
		unsigned int seed = 131;
		unsigned int hash = 1;
		while (*str)
		{
			hash = hash * seed + (*str++);
		}

		return (hash & 0x7fffffff);
	}

	size_t operator()(const std::string &str)
	{
		return BKDRHash(str.c_str());
	}
};
struct HashFunc2
{
	static size_t BKDRHash(const char *str)
	{
		register size_t hash = 0;
		while (size_t ch = (size_t)*str++)
		{
			hash = hash * 131 + ch;
		}
		return hash;
	}

	size_t operator()(const std::string &str)
	{
		return BKDRHash(str.c_str());
	}
};
struct HashFunc3
{
	static size_t BKDRHash(const char *str)
	{
		if (!*str)        // 這是由本人新增,以保證空字串返回雜湊值0  
			return 0;
		register size_t hash = 1315423911;
		while (size_t ch = (size_t)*str++)
		{
			hash ^= ((hash << 5) + ch + (hash >> 2));
		}
		return hash;
	}

	size_t operator()(const std::string &str)
	{
		return BKDRHash(str.c_str());
	}
};
struct HashFunc4
{
	static size_t BKDRHash(const char *str)
	{
		register size_t hash = 0;
		size_t magic = 63689;
		while (size_t ch = (size_t)*str++)
		{
			hash = hash * magic + ch;
			magic *= 378551;
		}
		return hash;
	}

	size_t operator()(const std::string &str)
	{
		return BKDRHash(str.c_str());
	}
};
struct HashFunc5
{
	static size_t BKDRHash(const char *str)
	{
		register size_t hash = 0;
		size_t ch;
		for (long i = 0; ch = (size_t)*str++; i++)
		{
			if ((i & 1) == 0)
			{
				hash ^= ((hash << 7) ^ ch ^ (hash >> 3));
			}
			else
			{
				hash ^= (~((hash << 11) ^ ch ^ (hash >> 5)));
			}
		}
		return hash;
	}
	size_t operator()(const std::string &str)
	{
		return BKDRHash(str.c_str());
	}
};
template<class K=string,
class Hash1 = HashFunc1,
class Hash2 = HashFunc2,
class Hash3 = HashFunc3,
class Hash4 = HashFunc4,
class Hash5 = HashFunc5>
class Bloom
{
public:
	Bloom(size_t size)
		:_map(size)
	{}
	void Set(string str1)
	{
		size_t hash1 = HashFunc1()(str1);
		_map.Set(hash1%_map.Size());
		size_t hash2 = HashFunc2()(str1);
		_map.Set(hash2%_map.Size());
		size_t hash3 = HashFunc3()(str1);
		_map.Set(hash3%_map.Size());
		size_t hash4 = HashFunc4()(str1);
		_map.Set(hash4%_map.Size());
		size_t hash5 = HashFunc5()(str1);
		_map.Set(hash5%_map.Size());
	}

	void Unset()
	{

	}

	bool Test(string str1)
	{
		size_t hash1 = HashFunc1()(str1);
		if (false == _map.test(hash1%_map.Size()))
			return false;
		size_t hash2 = HashFunc2()(str1);
		if (false == _map.test(hash2%_map.Size()))
			return false;
		size_t hash3 = HashFunc3()(str1);
		if (false == _map.test(hash3%_map.Size()))
			return false;
		size_t hash4 = HashFunc4()(str1);
		if (false == _map.test(hash4%_map.Size()))
			return false;
		size_t hash5 = HashFunc5()(str1);
		if (false == _map.test(hash5%_map.Size()))
			return false;
		return true;
	}

private:
	bitmap _map;
};
以下是點陣圖的實現
#pragma once
#include<iostream>
#include <vector>
using namespace std;

class bitmap
{
public:
	bitmap(size_t size)
		:_size(size)
	{
		map = new int[(size >> 5) + 1];
		memset(map, 0, sizeof(map));
	}
	~bitmap()
	{
		delete[]map;
	}
	void Set(size_t num)
	{
		int index = num >> 5;
		int pos = num % 32;
		map[index] |= (1 << (pos-1));
	}
	void Unset(size_t num)
	{
		int index = num >> 5;
		int pos = num % 32;
		map[index] &= ~(1 << (pos-1));
	}

	bool test(size_t num)
	{
		int index = num >> 5;
		int pos = num % 32;
		if (((map[index]>>(pos-1))&1)==1)
			return true;
		return false;
	}
	size_t Size()
	{
		return _size;
	}
private:
	int*map;
	size_t _size;
};


相關推薦

資料處理演算法--Bloom Filter

一、布隆過濾器(Bloom Filter)的定義 布隆過濾器可以用來檢測資料是否存在於一個集合中。它是hash的擴充套件,底層就是一個位數組,每一個bit位可以表示一個數字,所以布隆過濾器是基於點陣圖來實現的。 二、布隆過濾器的原理 1、插入資料 在點陣圖中,每一個bi

海量資料處理演算法Bloom Filter

                1. Bloom-Filter演算法簡介        Bloom-Filter,即布隆過濾器,1970年由Bloom中提出。它可以用於檢索一個元素是否在一個集合中。Bloom Filter(BF)是一種空間效率很高的隨機資料結構,它利用位陣列很簡潔地表示一個集合,並能判斷一個

資料處理演算法三:分而治之/hash對映 + hash統計 + 堆/快速/歸併排序

百度面試題1、海量日誌資料,提取出某日訪問百度次數最多的那個IP。 IP 是32位的,最多有個2^32個IP。同樣可以採用對映的方法,比如模1000,把整個大檔案對映為1000個小檔案,再找出每個小文中出現頻率最大的 IP(可以採用hash_map進行頻率統計,然後再找出頻

海量資料處理Bloom Filter詳解

一、什麼是Bloom Filter    Bloom Filter是一種空間效率很高的隨機資料結構,它的原理是,當一個元素被加入集合時,通過K個Hash函式將這個元素對映成一個位陣列(Bit array)中的K個點,把它們置為1。檢索時,我們只要看看這些點是不是都是1就(大約

資料經典演算法——bit-map與bloom filter

明白了雜湊的原理,bit-map就好說了。 bit-map的核心思想是:所謂的Bit-map就是用一個bit位來標記某個元素對應的Value, 而Key即是該元素。每一個bit空間都是儲存單元,而不像

資料演算法:Hadoop_Spark資料處理技巧》艾提拉筆記.docx 第1章二次排序:簡介 19 第2章二次排序:詳細示例 42 第3章 Top 10 列表 54 第4章左外連線 96 第5

《資料演算法:Hadoop_Spark大資料處理技巧》艾提拉筆記.docx       第1章二次排序:簡介 19 第2章二次排序:詳細示例 42 第3章 Top 10 列表 54 第4章左外連線 96 第5章反轉排序 127 第6章

(二)資料處理:基於MapReduce的圖劃分演算法綜述

【宣告:鄙人菜鳥一枚,寫的都是初級部落格,如遇大神路過鄙地,請多賜教;內容有誤,請批評指教,如有雷同,屬我偷懶轉運的,能給你帶來收穫就是我的部落格價值所在。】    今天一位同事跟我談起Hadoop,剛好這期部落格我也正準備寫點這方面相關的綜述,就跟他聊了聊。

資料演算法-Hadoop/Spark資料處理技巧》讀書筆記(一)——二次排序

寫在前面: 在做直播的時候有同學問Spark不是用Scala語言作為開發語言麼,的確是的,從網上查資料的話也會看到大把大把的用Scala編寫的Spark程式,但是仔細看就會發現這些用Scala寫的文章

資料演算法-Hadoop/Spark資料處理技巧》讀書筆記(四)——移動平均

移動平均:對時序序列按週期取其值的平均值,這種運算被稱為移動平均。典型例子是求股票的n天內的平均值。 移動平均的關鍵是如何求這個平均值,可以使用Queue來實現。 public class MovingAverageDriver { public

經典演算法題:資料處理常見演算法

第一部分、十道海量資料處理 1、海量日誌資料,提取出某日訪問百度次數最多的那個IP。   此題,在我之前的一篇文章演算法裡頭有所提到,當時給出的方案是:IP的數目還是有限的,最多2^32個,所以可以考慮使用hash將ip直接存入記憶體,然後進行統計。  再詳細介紹下此方案:

php 資料量及海量資料處理演算法總結

下面的方法是我對海量資料的處理方法進行了一個一般性的總結,當然這些方法可能並不能完全覆蓋所有的問題,但是這樣的一些方法也基本可以處理絕大多數遇到的問題。下面的一些問題基本直接來源於公司的面試筆試題目,方法不一定最優,如果你有更好的處理方法,歡迎與我討論。 1.Bloom f

DKhadoop資料處理平臺監控資料介紹

標題:DKhadoop大資料處理平臺監控資料介紹 2018年國內大資料公司50強榜單排名已經公佈了出來,大快以黑馬之姿闖入50強,並摘得多項桂冠。Hanlp自然語言處理技術也榮膺了“2018中國資料星技術”獎。對這份榜單感興趣的可以找一下看看。本篇承接上一篇《DKM平臺監控引數說明》,繼續就

資料演算法知識)

大資料問題 Map-Reduce和Hadoop逐漸成為熱門。 1介紹雜湊函式 雜湊函式又叫雜湊函式,雜湊函式的輸入域可以是非常大的範圍,但是輸出域是固定範圍。假設為s。 雜湊函式性質: 1:典型的雜湊函式都擁有無限的輸入值域; 2:輸入值相同時,返回值一樣; 3:輸入值不

淺談資料處理

剛接觸大資料處理,將大資料處理的框架記錄下來,之後深入的研究。 大資料處理的必要性 目前網際網路中資料的數量正在飛速的增長,首先是G為單位,然後是T級別、P級別、E級別。資料雖然很多,但是我們往往只慣性我們感興趣的那一部分,因此我們需要對海量資料進行處理獲取有價值的資訊來為我們所用。比如

資料處理神器map-reduce實現(僅python和shell版本)

熟悉java的人直接可以使用java實現map-reduce過程,而像我這種不熟悉java的怎麼辦?為了讓非java程式設計師方便處理資料,我把使用python,shell實現streaming的過程,也即為map-reduce過程,整理如下: 1.如果資料不在hive裡面,而在

海量資料處理演算法—Bit-Map

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Hadoop Streaming 做資料處理詳解

-------------------------------------------------------------------------- 以下內容摘自寒小陽老師大資料課程內容 -----------------------------

最主流的五個資料處理框架的優勢對比

我深入分析了五個大資料處理框架:Hadoop,Spark,Flink,Storm,Samaza Hadoop 頂尖的框架之一,大資料的代名詞。Hadoop,MapReduce,以及其生態系統和相關的技術,比如Pig,Hive,Flume,HDFS等。Hadoop是第一個,在工業

Python資料處理庫PySpark實戰

https://cloud.tencent.com/developer/article/1096712 Spark的安裝和使用(Python版) http://dblab.xmu.edu.cn/blog/1689-2/ https://blog.csdn.net/qq_14959801/

資料處理——雙層桶

轉載:http://diducoder.com/mass-data-topic-6-multi-dividing.html 【什麼是雙層桶】 事實上,與其說雙層桶劃分是一種資料結構,不如說它是一種演算法設計思想。面對一堆大量的資料我們無法處理的時候,我們可以將其分成一個個小的單元,