哈希函数和哈希表
out(f(in))
1)in 无穷
out相对有限
2)same in 得出 same out(不随机)
3)dif in 得到same out (哈希碰撞)
4)均匀性,离散性
in 1 out 1 m1
in 2 out2 m2
in 3 out3 m3
值在0-m-1,均匀分布
给一个范围0 - 的无符号整数,一共有40亿个,给定1G内存,返回出现次数最多的。
当使用哈希表HashMap做时,key(int),四字节,Value四字节,8B*40亿=32G
最差情况:40亿个数全都不一样
思路:先哈希函数映射,然后在模上100,进行分类,对于每个小文件使用HashMap,从而得到每个小文件出现次数最大的数,再把这一百个数进行比较得到结果。
哈希表的扩容:N个str,扩容次数logN,每次扩容代价为N,所以总的扩容代价为O(N*logN),单次扩容代价logN,当K足够长时,逼近O(1),离线扩容技术不占用用户在线时间,进一步降低哈希表使用代价。
设计RandomPool结构
实现:insert(key):不重复插入key到该结构
delete(key):将原本在结构中的某个key移除
getRandom():等概率随机返回结构中的任何一个key
要求:时间复杂度都是o(1)
思路:准备map1:str——index 和 map2:index——str 和size
删除操作:将要删除的str,拿最后一个str去填补漏洞,size--(保证等概率)
public static class Pool<K>{
private HashMap<K, Integer> keyIndexMap;
private HashMap<Integer, K> indexKeyMap;
private int size;
public pool(){
this.keyIndexMap = new HashMap<K, Integer>();
this.indexKeyMap = new HashMap<Integer, K>();
this.size = 0;
}
public void insert(K key){
if(!this.keyIndexMap.containsKey(key)){
this.keyIndexMap.put(key, this.size);
this.indexKeyMap.put(this.size++, key);
}
}
public void delete(K key){
if (this.keyIndexMap.containsKey(key)){
int deleteIndex = this.keyIndexMap.get(key);
int lastIndex = --this.size;
K lastKey = this.indexKeyMap.get(lastIndex);
this.keyIndexMap.put(lastKey, deleteIndex);
this.IndexKeyMap.put(deleteIndex, lastKey);
this.keyIndexMap.remove(key);
this.IndexKeyMap.remove(lastIndex);
}
}
public K getRandom(){
if(this.size == 0){
return null;
}
int randomIndex = (int)(Math.random()* this.size);
return this.indexKeyMap.get(randomIndex);
}
}
布隆过滤器
判断url是否在黑名单里:add,check,存在误判:白名单误判成黑名单,概率较低万分之一
位图(bit arr/ bit map)
int[100] 0~99 4字节= 32bit
long[100] 8字节=64bit
bit[] 每位1bit 100/8字节
方式:拿基础类型拼
int[] arr =new int[10];//32bit * 10 -> 320bits
//arr[0] int 0 ~ 31
//arr[1] int 32 ~ 63
//arr[2] int 64 ~ 95
int i =178;//想要取得178个bit的状态
int numIndex = 178 / 32;
int bitIndex = 178 % 32;
//拿到178位的状态
int s = ( (arr[numIndex] >> (bitIndex)) & 1);
//把178位的状态改为1
arr[numIndex] = arr[numIndex] | ( 1 << (bitIndex));
//改成0
arr[numIndex] = arr[numIndex] & (~( 1 << bitIndex));
布隆过滤器就是一个大的位图 设m个bit 范围是0 ~ m-1
实际占用m/8字节
u1添加到黑名单,u1经过哈希函数f1再模上m得到k1,经过f2模上m得到k2,假设有k个哈希函数,得到k个位置,有可能一样也可能不一样,把这些位置全部描黑,接着u2,一直到u四十亿,黑名单集合建立好。查:某个url经过哈希函数模m后得到k个位置,如果位置全部为1,则是黑名单里的url。
k个hash有几个? m设为多少? K值极具增大时,会耗尽m,失误率增加
失误率:m 和 k
判断是否是布隆过滤器:是不是类似黑名单的系统且无删除行为,允许有失误率
和单样本的大小无关,只要哈希函数能接受这样的url就行
n =样本量 P=预期失误率
向上取整
一致性哈希
hashkey的选择要选择种类较多的,使得高频、中频和低频都有数量
经典的数据库只需要在逻辑层部署,但在扩充数据端数量时,数据迁移的代价是全量的。
不用模的方式,保证数据迁移代价不高
把整个哈希域当作一个环
假设有三台机器,利用机器信息区分三台机器,机器信息经过哈希函数插入环中
查询时:经过哈希函数后,顺时针遇到的第一个机器
逻辑端的每台机器存入机器哈希值的排序的有序数组,要查询的信息经过哈希函数后,做二分,找到大于等于其最左的位置。
每个机器管一段request
当增加机器的时候,数据迁移的代价减少
潜在问题:一开始机器少的时候如果均分环 2.增加减少机器时,负载不均衡
引入虚拟节点技术
m1分配1000个字符串
m2分配1000个字符串
m3也分配1000个字符串
分配的节点去抢环,按比例抢环
增加机器m4,该机器的节点去抢环
使得初始均衡和增减机器之后均衡
管理负载:根据实际机器的强弱来分配数据