Hash

HASH http://baike.baidu.com/view/20089.htm

有些时候,先计算Key的值,比如Objet中的hashcode返回的是一个Key.  得到这个key值然后可以利用hash算法H(Key)会形成一个散列表(类似于hashmap里面的列表).每个H(Key)的值对应一个散列地址. 一个散列地址指向内存中一段连续的地址集(类似于hashmap里面的链表). 如果H(Key1)与H(Key2)得到相同的散列地址,那么具有相同函数值的关键字对该散列函数来说称做同义词。Key1,Key2对于H(Key)就是同义词.当为同义词时,Key1,Key2会放到用同一个散列地址标识的"桶"里. Key1,Key2会分别存储到地址集中(hashmap中,table[index]表示已经找到的元素需要存储的位置。先判断该位置上有没有元素(这个元素是HashMap内部定义的一个类Entity,基本结构它包含三个类,key,value和指向下一个Entity的next),没有的话就创建一个Entity<K,V>对象,在 table[index]位置上插入,这样插入结束;如果有的话,通过链表的遍历方式去逐个遍历,看看有没有已经存在的key,有的话用新的value替换老的value;如果没有,则在table[index]插入该Entity,把原来在table[index]位置上的Entity赋值给新的 Entity的next,这样插入结束).

Hash常用算法
1)hash算法最常用的是%.
H(key) = key MOD p, p<=m。不仅可以对关键字直接取模,也可在折叠、平方取中等运算之后取模。对p的选择很重要,一般取素数或m,若p选的不好,容易产生同义词(负载均衡还故意用到同义词)。
2)hashmap里面使用了Key & (length-1)得到一个小于length的值做为数组的index.


Hash的应用:
1)数据库的水平分区,分表使用的最多的也是基于%的hash. Key是userid或者accountid, 这样可以保证一个user或account的所有操作的数据都可以从一个分区中取出. 对于%算法,动态扩展的例子:
userid为0~20W的数据使用userid % 4;
userid为20~40W的数据可以使用userid % 4+4, 散列函数改变,并不会导致之前0~20W的数据重新计算. 新的数据也不会散列到最初的db server上. 而是到了新加的4台db server上.  不会增加旧的server的负担.
2)缓存
最常用的仍然是%做为散列函数.但是当server发生增减,根据新的p值,之前缓存的内容就会失效,而从对后端服务器产生冲击.
此时的解决办法就是一致性hash. key与cache采用[一致的hash算法],然后按照[顺时针]去找相应的cache节点,按照顺时针去划分.

3)hash就是找到一种数据内容和数据存放地址之间的映射关系
4)java中数据量太大,不推荐使用list,因为遍历list此时比较耗时, 替换的方案就是使用hashmap. 此时通过key的hashcode去定位value要比遍历快得多.

posted @ 2011-08-16 11:37  highriver  阅读(644)  评论(0编辑  收藏  举报