Guava 10-散列

概述

Java内建的散列码[hash code]概念被限制为32位,并且没有分离散列算法和它们所作用的数据,因此很难用备选算法进行替换。此外,使用Java内建方法实现的散列码通常是劣质的,部分是因为它们最终都依赖于JDK类中已有的劣质散列码。

Object.hashCode往往很快,但是在预防碰撞上却很弱,也没有对分散性的预期。这使得它们很适合在散列表中运用,因为额外碰撞只会带来轻微的性能损失,同时差劲的分散性也可以容易地通过再散列来纠正(Java中所有合理的散列表都用了再散列方法)。然而,在简单散列表以外的散列运用中,Object.hashCode几乎总是达不到要求——因此,有了com.google.common.hash包。

散列包的组成

在这个包的Java doc中,我们可以看到很多不同的类,但是文档中没有明显地表明它们是怎样 一起配合工作的。在介绍散列包中的类之前,让我们先来看下面这段代码范例:

HashFunction hf = Hashing.md5();
HashCode hc = hf.newHasher()
        .putLong(id)
        .putString(name, Charsets.UTF_8)
        .putObject(person, personFunnel)
        .hash();

HashFunction

HashFunction是一个单纯的(引用透明的)、无状态的方法,它把任意的数据块映射到固定数目的位指,并且保证相同的输入一定产生相同的输出,不同的输入尽可能产生不同的输出。

Hasher

HashFunction的实例可以提供有状态的Hasher,Hasher提供了流畅的语法把数据添加到散列运算,然后获取散列值。Hasher可以接受所有原生类型、字节数组、字节数组的片段、字符序列、特定字符集的字符序列等等,或者任何给定了Funnel实现的对象。

Hasher实现了PrimitiveSink接口,这个接口为接受原生类型流的对象定义了fluent风格的API

Funnel

Funnel描述了如何把一个具体的对象类型分解为原生字段值,从而写入PrimitiveSink。比如,如果我们有这样一个类:

class Person {
    final int id;
    final String firstName;
    final String lastName;
    final int birthYear;
}

它对应的Funnel实现可能是:

Funnel<Person> personFunnel = new Funnel<Person>() {
    @Override
    public void funnel(Person person, PrimitiveSink into) {
        into
            .putInt(person.id)
            .putString(person.firstName, Charsets.UTF_8)
            .putString(person.lastName, Charsets.UTF_8)
            .putInt(birthYear);
    }
}

注:putString(“abc”, Charsets.UTF_8).putString(“def”, Charsets.UTF_8)完全等同于putString(“ab”, Charsets.UTF_8).putString(“cdef”, Charsets.UTF_8),因为它们提供了相同的字节序列。这可能带来预料之外的散列冲突。增加某种形式的分隔符有助于消除散列冲突。

HashCode

一旦Hasher被赋予了所有输入,就可以通过hash()方法获取HashCode实例(多次调用hash()方法的结果是不确定的)。HashCode可以通过asInt()asLong()asBytes()方法来做相等性检测,此外,writeBytesTo(array, offset, maxLength)把散列值的前maxLength字节写入字节数组。

布鲁姆过滤器[BloomFilter]

布鲁姆过滤器是哈希运算的一项优雅运用,它可以简单地基于Object.hashCode()实现。简而言之,布鲁姆过滤器是一种概率数据结构,它允许你检测某个对象是一定不在过滤器中,还是可能已经添加到过滤器了。布鲁姆过滤器的维基页面对此作了全面的介绍,同时我们推荐github中的一个教程

Guava散列包有一个内建的布鲁姆过滤器实现,你只要提供Funnel就可以使用它。你可以使用create(Funnel funnel, int expectedInsertions, double falsePositiveProbability)方法获取BloomFilter<T>,缺省误检率[falsePositiveProbability]为3%。BloomFilter<T>提供了boolean mightContain(T) 和void put(T),它们的含义都不言自明了。

BloomFilter<Person> friends = BloomFilter.create(personFunnel, 500, 0.01);
for(Person friend : friendsList) {
    friends.put(friend);
}

// 很久以后
if (friends.mightContain(dude)) {
    //dude不是朋友还运行到这里的概率为1%
    //在这儿,我们可以在做进一步精确检查的同时触发一些异步加载
}

Hashing类

Hashing类提供了若干散列函数,以及运算HashCode对象的工具方法。

已提供的散列函数

md5() murmur3_128() murmur3_32() sha1()
sha256() sha512() goodFastHash(int bits)  

HashCode运算

方法 描述
HashCode combineOrdered( Iterable<HashCode>) 以有序方式联接散列码,如果两个散列集合用该方法联接出的散列码相同,那么散列集合的元素可能是顺序相等的
HashCode   combineUnordered( Iterable<HashCode>) 以无序方式联接散列码,如果两个散列集合用该方法联接出的散列码相同,那么散列集合的元素可能在某种排序下是相等的
int   consistentHash( HashCode, int buckets) 为给定的”桶”大小返回一致性哈希值。当”桶”增长时,该方法保证最小程度的一致性哈希值变化。详见一致性哈希

原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: [Google Guava] 10-散列

时间: 2024-07-30 13:52:16

Guava 10-散列的相关文章

HashMap实现 Hash优化与高效散列

OverView Hash table based implementation of the Map interface. This implementation provides all of the optional map operations, and permits null values and the null key. (The HashMap class is roughly equivalent to Hashtable, except that it is unsynch

Redis常用命令(一) 字符串键、散列键

redis是key-value的数据结构,每条数据都是一个键值对 键的类型是字符串,因为默认是字符串所以都不用加引号 注意:键不能重复 值的类型分为五种: 字符串string 散列hash 列表list 集合set 有序集合zset string字符串键 set key value  # 设置的键不存在则为添加,如果设置的键已经存在则修改 set name daiby set key value [NX|XX]  # NX: 如果key不存在则成功,反之失败(不覆盖旧值)! XX: 如果key存

散列、加密、编码 漫谈

散列(又叫Hash)和加密在身份校验.敏感信息传输等应用中用途广泛. 把他们放在一起写的原因是,网上太多资料,将散列和加密的概念混为一谈,误导性极大. 由于编码/解码运算和上述二者有一定的相似之处,因此放在这里一并讲述. 注:本文中,为了表述严谨,所有的"位"代表的是字符个数之意,而bit则指代计算机数据中的基本单位比特. 1.三者的共同点 它们都表述了一种映射关系,将原始数据A映射到新的数据B. 在散列运算中,B一般称之为摘要,英文为digest. 其代表算法有MD5,SHA1, S

散列(C++实现)

散列的构成:散列函数,散列表的存储方式,散列表的冲突解决方法. 1.散列函数 较常用的散列函数有除留余数法,数字分析法,平方取中法,折叠法. 2.散列表的存储方式 闭散列法(开地址法),用数组存储:开散列法(链地址法),用邻接链表存储. 3.散列表的冲突解决方法 主要是针对闭散列中关键码位置冲突的问题,常用的方法有线性探查法,二次探查法,双散列法. 性能分析:在存储方式中,开散列法优于闭散列法:在散列函数中,除留余数法最优. 实现代码: 1 #include<iostream> 2 using

c语言 &lt;除法散列法&gt; 高效 HashTable Dictionary

c语言 <除法散列法> 高效 HashTable Dictionary  ,不管集合大小,任意长度根据key查询都只是一次寻址左右,so 最快时间复杂度为O1! 先上代码,明天写原理注释! HashDictionary.h #define CM_STR_HASHFUNC_CONSTANT 31 #define KEYSIZE 40 struct Entry { int hashCode; int next; char key[KEYSIZE]; void* value; }; struct H

没事写个散列玩~

感觉散列的查找性能真心不错,如果使用普通线性结构查找,平均时间是n/2.而刚才用实验,256大小的散列,存储128个数据,平均时间为2次以内.感觉真心NB 1 #include <iostream> 2 #include <vector> 3 #include <string> 4 #include <cstdlib> 5 #include <ctime> 6 7 using namespace std; 8 typedef bool BOOL;

Python matplot画散列图

同matlab一样,matplot也可画散列图scatter. 1 import numpy as np 2 import matplotlib.pyplot as plt 3 #fig = plt.figure() 4 #ax = fig.add_subplot(111) 5 a1 = np.array([1, 2, 3, 4]) 6 a2 = np.array([1, 2, 3, 4]) 7 #ax.scatter(np.random.rand(5), np.random.rand(5))

容器深入研究 --- 散列与散列码(一)

通常的: 当标准类库中的类被作用HashMap的键.它用的很好,因为它具备了键所需的全部性质. 当你自己创建用作HashMap的键的类,有可能会忘记在其中放置必须的方法,而这时通常会犯的一个错误. 例如:考虑一个天气系统,将Groundhog对象与Prediction对象联系起来. class Groundhog { protected int number; public Groundhog(int n) { number = n; } public String toString() { r

php密码加密(密码散列)

php在5.5版本中新增了password_hash.password_verify两个密码散列函数 使用方法: // 散列 $password = '123456'; $hash = password_hash($password, PASSWORD_BCRYPT); // $2y$10$8ob0qXBKuW1.YoAh1xSCFeXeftnsLRgP7XYb9KMG5TpcXNN/M0Q/2 // 验证 if (password_verify($password, $hash)) { ret

HBase Rowkey的散列与预分区设计

转自:http://www.cnblogs.com/bdifn/p/3801737.html 问题导读:1.如何防止热点?2.如何预分区?扩展:为什么会产生热点存储? HBase中,表会被划分为1...n个Region,被托管在RegionServer中.Region二个重要的属性:StartKey与EndKey表示这个Region维护的rowKey范围,当我们要读/写数据时,如果rowKey落在某个start-end key范围内,那么就会定位到目标region并且读/写到相关的数据.简单地说