我没有去很关注数学,下次补上
突然产生一个疑问,我为什么每次写博客,都没有以尽可能别人看的舒服看的明白为目标,都是以自己想到哪就记录哪?
Bitmap能够将原先需要用32bit存的整数用1bit来表示,它的空间复杂度与要表示的最大的数有关,与有多少个数无关。当要存的数到达64bit的时候占用内存依旧太大
bloom filter是对Bitmap的扩展,有很高效的时间和空间,但是是以牺牲一定的准确度为代价的,以及存在删除困难的问题
文章目录
Bitmap
应用背景:大数据查找和排序
Bitmap
漫画算法:什么是 Bitmap 算法?
一个byte是8bit,每个bit位代表一个数,如果bit值为1,说明这个数出现过,如果bit值为0.说明没出现过。以byte[0]所示为例,第8,6,3,2位上是1,表示数字7,5,2,1出现过。
从上图可以看出,逻辑上我们开长度为8的byte数组来存储数据。我们在维护Bitmap时,需要知道每个数对应数组的什么位置,其本质是要知道数字x在A[][8]中的行数和列数(从0开始计数)。但实际时我们用一维数组A[](称之为位数组),他代表一个整数,每个整数有8个bit,可以存储8个数据。
如果数据中的最大值是n,那么需要开的数组大小是(n>>3)+1
数据x的行数index为(x>>3),即落入哪个byte中
数据x的列数position为(x&0x07) 本质上是取后三位来定位列 即落入byte的哪个bit中
A[index]|=1<<position
判断一个数x是否存在:
A[index]&(1<<position)如果为1则存在,说明A[index]的position位bit被置为1,说明x存在。否则bit位为0,x不存在。
清除一个数x:
A[index]&=~(1<<position) 不影响其他位,只把position位清零
当我需要进行排序的时候,遍历一下byte[bit],如果是1就输出下标,那么最后输出的就是排好序的数字。比如上图 1 2 5 7 11
bloom filter
大数据量下的集合过滤—Bloom Filter
讲的很清晰
常见的几个应用场景:
- cerberus在收集监控数据的时候, 有的系统的监控项量会很大, 需要检查一个监控项的名字是否已经被记录到db过了, 如果没有的话就需要写入db.
- 爬虫过滤已抓到的url就不再抓,可用bloom filter过滤
- 垃圾邮件过滤。如果用哈希表,每存储一亿个 email地址,就需要 1.6GB的内存(用哈希表实现的具体办法是将每一个 email地址对应成一个八字节的信息指纹,然后将这些信息指纹存入哈希表,由于哈希表的存储效率一般只有 50%,因此一个 email地址需要占用十六个字节。一亿个地址大约要 1.6GB,即十六亿字节的内存)。因此存贮几十亿个邮件地址可能需要上百 GB的内存。而Bloom Filter只需要哈希表 1/8到 1/4 的大小就能解决同样的问题。
需要补充的是expectedInsertions是字符串总数量
fpp是可接受误差
package com.qunar.sage.wang.common.bloom.filter;
import com.google.common.base.Charsets;
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnel;
import com.google.common.hash.Funnels;
import com.google.common.hash.PrimitiveSink;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.ToString;
/**
* BloomFilterTest
*
* @author sage.wang
* @date 18-5-14 下午5:02
*/
public class BloomFilterTest {
public static void main(String[] args) {
long expectedInsertions = 10000000;
double fpp = 0.00001;
BloomFilter<CharSequence> bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8), expectedInsertions, fpp);
bloomFilter.put("aaa");
bloomFilter.put("bbb");
boolean containsString = bloomFilter.mightContain("aaa");
System.out.println(containsString);
BloomFilter<Email> emailBloomFilter = BloomFilter
.create((Funnel<Email>) (from, into) -> into.putString(from.getDomain(), Charsets.UTF_8),
expectedInsertions, fpp);
emailBloomFilter.put(new Email("sage.wang", "quanr.com"));
boolean containsEmail = emailBloomFilter.mightContain(new Email("sage.wangaaa", "quanr.com"));
System.out.println(containsEmail);
}
@Data
@Builder
@ToString
@AllArgsConstructor
public static class Email {
private String userName;
private String domain;
}
}
Sketch
第三次寒假作业 sketch 了解
sketch 是一种基于散列的数据结构,可以在高速网络环境中,实时地存储流量特征信息,只占用较小的空间资源,并且具备在理论上可证明的估计精度与内存的平衡特性。
通过设置散列函数,将具有相同散列值的键值数据存入相同的桶内,以减少空间开销。桶内的数据值作为测量结果,是真实值的近似。利用开辟二维地址空间,多重散列等技术减少散列冲突,提高测量结果的准确度。
一些算法的局部代码和数学推导,代码节选的不是很好,只能将就着看
Count sketch
Sketch调研
C sketch相较于CM多了一组hash函数S1,……St,它们的取值空间均为{+1, -1}
当需要增加某个元素k时,先是和CM一样用原先的一组hash函数找到mapped counters,然后对第i个counter增加Si[k],即有可能加1,也有可能减1。在查询时先得到每个counter的值,再乘上Si[k],并取所有结果的中值为最终估计值。
这里乘Si[k]是因为若高频项的Si[k]值为负,则counter减1的次数多,最终存储的值也为负,因此再乘一次相当于消除符号。而用中值代替平均值是考虑到平均值受极端值的影响较大,相对来说中值更具有鲁棒性
C sketch的思想是通过概率加1和减1,尽量抵消低频项对高频项的干扰,使得对高频项的估计更加精确
讲真这里不是很懂
提出文章《Finding Frequent Items in Data Streams》 Moses Charikar、Kevin Chen、Martin Farach-Colton
Count-Min Sketch(CM算法)
Count-Min Sketch 算法,解决大数据统计难题
我靠,也太直观了叭
CM sketch对元素的频率只会高估而不会低估,且对于重复次数较多的元素的准确率比较高,但是对于出现次数较少的元素的准确率较低
record-all-evict-cold策略
Augmented Sketch
Sketch调研
对二元组(k,u)进行插入操作,k为元素,u为次数:
1、如果过滤器中有k,直接对其new_count加u,而old_count不变
2、如果没有且过滤器未满,把k加入并设其new_count = u, old_count =0
3、如果没有且过滤器已满,先把k加入sketch,若此时对k的估计值大于过滤器中的最小值,则将该最小值散列到sketch中共 (new_count - old_count)次,并把k加入过滤器,new_count和old_count都设为原先k的估计值
对于查询操作较为简单:即现在过滤器中查询,有则返回其new_count值,否则到sketch中进行估计
在这种方式中可能会出现需要多次交换(multiple exchanges)的情况,一个例子如下:
上图中C不在过滤器中且过滤器已满,先将C散列到sketch中,此时对C的估计为9,大于A的8,因此把C加入过滤器,并把A散列6次(8-2)到sketch中。而操作结束后对A的估计值为10,又大于C的9,发生multiple exchanges。
对于这种情况,文章的处理方式是每次最多只进行一次交换(at most one exchange)
A sketch的优点在于节省了很多次的hash计算,因为部分元素聚集在过滤器中。且因为高频项大部分时间都存在过滤器中,而过滤器的计数是完全精确的,因此可以大大提高对高频项的估计情况。
提出文章《Augmented Sketch: Faster and More Accurate Stream Processing》
Augment Sketch的问题在于,filter中的查找是挨个查的,因此比较慢,作者建议存32个hot items。但是在流任务中,需要报告上千个hot items,会导致filter和sketch频繁地互换。
如何查找次数超过k次的元素
数据流基本问题–确定频繁元素(一)
经典的过半元素查找问题
Lossy Counting Algorithm
实时大数据流上的频率统计:Lossy Counting Algorithm
简言之将数据流切分为多个窗口,在每个窗口中对item频次进行统计,然后整体-1,把频次为0的evict掉。最后汇总多个窗口
Sticky sampling 算法
数据流基本问题–确定频繁元素(二)lossy counting和sticky sampling
我没有看懂,之后找论文看,先不记录