1. 程式人生 > >基於Redis的Bloomfilter去重(基於git上的pybloom修改,誤差可測)

基於Redis的Bloomfilter去重(基於git上的pybloom修改,誤差可測)

1.pybloom.py

# -*- encoding: utf-8 -*-
from __future__ import absolute_import
import math
import hashlib
from pybloom.utils import range_fn, running_python_3
from struct import unpack, pack, calcsize


__version__ = '2.0'
__author__ = "Jay Baird <[email protected]>, Bob Ippolito <[email protected]
>,\ Marius Eriksen <[email protected]>,\ Alex Brasetvik <[email protected]>,\ Matt Bachmann <[email protected]>,\ " def make_hashfuncs(num_slices, num_bits): if num_bits >= (1 << 31): fmt_code, chunk_size = 'Q', 8 elif num_bits >= (1 << 15): fmt_code, chunk_size = 'I', 4 else: fmt_code, chunk_size = 'H', 2 total_hash_bits = 8 * num_slices * chunk_size if total_hash_bits > 384: hashfn = hashlib.sha512 elif total_hash_bits > 256: hashfn = hashlib.sha384 elif total_hash_bits > 160: hashfn = hashlib.sha256 elif total_hash_bits > 128: hashfn = hashlib.sha1 else: hashfn = hashlib.md5 fmt = fmt_code * (hashfn().digest_size // chunk_size) num_salts, extra = divmod(num_slices, len(fmt)) if extra: num_salts += 1 salts = tuple(hashfn(hashfn(pack('I', i)).digest()) for i in range_fn(num_salts)) def _make_hashfuncs(key): if running_python_3: if isinstance(key, str): key = key.encode('utf-8') else: key = str(key).encode('utf-8') else: if isinstance(key, unicode): key = key.encode('utf-8') else: key = str(key) i = 0 for salt in salts: h = salt.copy() h.update(key) for uint in unpack(fmt, h.digest()): yield uint % num_bits i += 1 if i >= num_slices: return return _make_hashfuncs class BloomFilter(object): FILE_FMT = b'<dQQQQ' def __init__(self, capacity, error_rate=0.001, conn=None, redis_key='BloomFilter'): if not (0 < error_rate < 1): raise ValueError("Error_Rate must be between 0 and 1.") if not capacity > 0: raise ValueError("Capacity must be > 0") # given M = num_bits, k = num_slices, P = error_rate, n = capacity # k = log2(1/P) # solving for m = bits_per_slice # n ~= M * ((ln(2) ** 2) / abs(ln(P))) # n ~= (k * m) * ((ln(2) ** 2) / abs(ln(P))) # m ~= n * abs(ln(P)) / (k * (ln(2) ** 2)) num_slices = int(math.ceil(math.log(1.0 / error_rate, 2))) bits_per_slice = int(math.ceil( (capacity * abs(math.log(error_rate))) / (num_slices * (math.log(2) ** 2)))) self._setup(error_rate, num_slices, bits_per_slice, capacity, 0) self.redis = conn self.redis_key = redis_key def _setup(self, error_rate, num_slices, bits_per_slice, capacity, count): self.error_rate = error_rate self.num_slices = num_slices print("切片個數=%s" % self.num_slices) self.bits_per_slice = bits_per_slice self.capacity = capacity self.num_bits = num_slices * bits_per_slice print("總位元組數=%s" % self.num_bits) # 需要的多少M記憶體 self.mem = math.ceil(self.num_bits / 8 / 1024 / 1024) self.blocknum = math.ceil(self.mem/512) self.count = count self.make_hashes = make_hashfuncs(self.num_slices, self.bits_per_slice) def __contains__(self, key): """Tests a key's membership in this bloom filter. >>> b = BloomFilter(capacity=100) >>> b.add("hello") False >>> "hello" in b True """ bits_per_slice = self.bits_per_slice name = self.redis_key + "_" + str(ord(key[0]) % self.blocknum) hashes = self.make_hashes(key) offset = 0 for k in hashes: if not self.redis.getbit(name, offset + k): return False offset += bits_per_slice return True def __len__(self): """Return the number of keys stored by this bloom filter.""" return self.count def add(self, key, skip_check=False): """ Adds a key to this bloom filter. If the key already exists in this filter it will return True. Otherwise False. >>> b = BloomFilter(capacity=100) >>> b.add("hello") False >>> b.add("hello") True >>> b.count 1 """ name = self.redis_key + "_" + str(ord(key[0]) % self.blocknum) bits_per_slice = self.bits_per_slice hashes = self.make_hashes(key) found_all_bits = True if self.count > self.capacity: raise IndexError("BloomFilter is at capacity") offset = 0 for k in hashes: if not skip_check and found_all_bits and not self.redis.getbit(name, offset + k): found_all_bits = False print("add name={} hash={}".format(name, offset + k)) self.redis.setbit(name, offset + k, 1) offset += bits_per_slice if skip_check: self.count += 1 return False elif not found_all_bits: self.count += 1 return False else: return True def __getstate__(self): d = self.__dict__.copy() del d['make_hashes'] return d def __setstate__(self, d): self.__dict__.update(d) self.make_hashes = make_hashfuncs(self.num_slices, self.bits_per_slice)

2.utils.py

import sys
try:
    import StringIO
    import cStringIO
except ImportError:
    from io import BytesIO

running_python_3 = sys.version_info[0] == 3


def range_fn(*args):
    if running_python_3:
        return range(*args)
    else:
        return xrange(*args)


def is_string_io(instance):
    if running_python_3:
       return isinstance(instance, BytesIO)
    else:
        return isinstance(instance, (StringIO.StringIO,
                                     cStringIO.InputType,
                                     cStringIO.OutputType))

3.測試模組

import redis
from pybloom.pybloom import BloomFilter

pool = redis.ConnectionPool(host='127.0.0.1', port=6379, password='', db=0)
conn = redis.StrictRedis(connection_pool=pool)
if __name__ == '__main__':
    f = BloomFilter(capacity=1000, error_rate=0.001)
    for i in range(0, f.capacity):
        _ = f.add(i)
    print((1.0 - (len(f) / float(f.capacity))) <= f.error_rate + 2e-18)

相關推薦

基於Redis的Bloomfilter基於gitpybloom修改誤差

1.pybloom.py# -*- encoding: utf-8 -*- from __future__ import absolute_import import math import hashlib from pybloom.utils import range_fn

給定一個字串重複的字元只保留第一次出現的

原始碼(c++): #include <iostream> #include <string> using namespace std; int main(){ string str; cin>>str; int

呼叫系統相機、相簿、剪裁圖片並常用於傳頭像相容Android7.0

轉載請註明出處文章地址 本文轉自Hansion的部落格 由於在Android 7.0 採用了StrictMode API政策禁,其中有一條限制就是對目錄訪問的限制。 這項變更意味著我們無法通過File API訪問手機儲存上的資料,也就是說,給其他應用傳

基於Redis的Bloomfilter附Python程式碼

“去重”是日常工作中會經常用到的一項技能,在爬蟲領域更是常用,並且規模一般都比較大。去重需要考慮兩個點:去重的資料量、去重速度。為了保持較快的去重速度,一般選擇在記憶體中進行去重。 資料量不大時,可以直接放在記憶體裡面進行去重,例如python可以使用set()

JavaScript陣列12種方法最全

陣列去重,一般都是在面試的時候才會碰到,一般是要求手寫陣列去重方法的程式碼。如果是被提問到,陣列去重的方法有哪些?你能答出其中的10種,面試官很有可能對你刮目相看。在真實的專案中碰到的陣列去重,一般都是後臺去處理,很少讓前端處理陣列去重。雖然日常專案用到的概率比較低

海量資料億資料

   在資料開發中,我們不難遇到重複資料的問題,搞過這類資料開發的同志肯定覺得,重複資料是真的煩人,特別是當資料量十分大的時候,如果我們用空間複雜度去換時間複雜度,會十分耗內容,稍不注意,就會記憶體溢位,那麼針對如此龐大的資料量我們一般能怎麼解決呢?下面分享幾個方案: 方案一

[轉抄]oracle單表查詢效率比較高的一種方式

sel select 單表查詢 效率 查詢 rownum 說明 acl 分組 1 select 2 * 3 from 4 ( 5 select 6 a.*, rownum r_n 7

Git與GitHub利用git傳本地文件到GitHub上面

add 到你 star mit gpg 輸入 ssh git add remote GitHub就是代碼倉庫(管理代碼的工具)可以共享給所有人 Git就是從GitHub上提取文件或者將本地文件上傳到GitHub的工具(等同於SVN) 利用Git上傳項目 步驟一:(用戶和郵箱

php數組一維數組

print 技術分享 unique 重復 數組去重 img ech pan tro <?php $arr = [‘1‘, ‘1‘, ‘PHP‘, ‘PHP‘, 2, 3]; print_r($arr); echo "<br>"; print_r(

List資料為物件的情況及String中的equals()方法和hashCode()方法原始碼分析

面試中經常被問到的list如何去重,用來考察你對list資料結構,以及相關方法的掌握,體現你的java基礎學的是否牢固。 我們大家都知道,set集合的特點就是沒有重複的元素。如果集合中的資料型別是基本資料型別,可以直接將list集合轉換成set,就會自動去除重複的元素,這個就相對比較簡單。上一篇

【HihoCoder - 1850】字母 字串思維

題幹: 給定一個字串S,每次操作你可以將其中任意一個字元修改成其他任意字元。 請你計算最少需要多少次操作,才能使得S中不存在兩個相鄰的相同字元。 Input 只包含小寫字母的字串S。   1 ≤ |S| ≤ 100000 Output 一個整數代表答案

陣列時間複雜度nlgn時間複雜度o(1)

public static void quickSort(int[] numArr, int left, int right) { //如果left等於right,即陣列只有一個元素,直接返回 if (left >= right) { return;

JavaScript陣列12種方法

陣列去重,一般都是在面試的時候才會碰到,一般是要求手寫陣列去重方法的程式碼。如果是被提問到,陣列去重的方法有哪些?你能答出其中的10種,面試官很有可能對你刮目相看。 在真實的專案中碰到的陣列去重,一般都是後臺去處理,很少讓前端處理陣列去重。雖然日常專案用到的概率比較低,但還是需要了解一下,以防面試的

Java8 list根據一個欄位記錄

list = list.stream().collect( Collectors.collectingAndThen( Collectors.toCollection(() -> new TreeSet&l

原生JS--兩種方法去掉重複字元

所謂“去重”,即是去掉重複的字元。本篇部落格講述兩種方式去重,一種是比較簡單但程式碼比較囉嗦點的,另一種是有點深度但是簡潔的。  我直接寫JavaScript程式碼了。  方式一: function deleteRepetionChar(arr){ //先判斷輸入進

集合 集合元素為引用型別--- java 8 新特性 --- 根據元素單屬性、多屬性實現

1. 程式碼寫法: (要求 JDK 1.8 或 1.8 以上) package gentle.entity; import lombok.Data; /** * * @author sile

Dstream[Row] 資料批量匯入Mysql 並大致為如果資料庫中有某行資料了本次執行若有一行與資料庫中的那行相同則不會再插入進去

def Save2Mysql(stateDStream: DStream[Row]): Unit = { stateDStream.foreachRDD { rdd => { rdd.foreachPartition(partitionRecord

Java遇到需要去掉重複的問題怎麼辦

JAVA去重 去掉在List中物件屬性重複的物件 /** * 去重 * 需要去掉學生中分數相同的 */ //建立一個set Set set = new HashSet(); //記錄set的大小 int nowsize = set.size(); /

JS 陣列陣列元素是物件的情況

js陣列去重有經典的 幾種方法 但當陣列元素是物件時,就不能簡單地比較了,需要以某種方式遍歷各值再判斷是否已出現。 因為: 1.如果是雜湊判斷法,物件作雜湊表的下標,就會自動轉換成字元型型別,從而導致所有元素都相等,這時判斷方法不再有意義。一般最後陣列就只剩一個

合併兩個陣列並ES5和ES6兩種方式實現

 ES6實現方式 let arr1 = [1, 1, 2, 3, 6, 9, 5, 5, 4] let arr2 = [1, 2, 5, 4, 9, 7, 7, 8, 8] f