對於海量數據來講,數據內存佔用會變得很高. Probabilistic數據結構犧牲了一下準確率去換取更低內存佔用。好比一個HyperLogLog的數據結構只須要花費12KB內存,就能夠計算接近2^64個不一樣元素的基數,而錯誤率在1.625%.算法
HyperLogLog一個經常使用的場景就是統計網站的UV。數據結構
簡單來講,基數(cardinality,也譯做勢),是指一個集合(這裏的集合容許存在重複元素)中不一樣元素的個數。例如看下面的集合:
{1,2,3,4,5,2,3,9,7}
這個集合有9個元素,可是2和3各出現了兩次,所以不重複的元素爲1,2,3,4,5,9,7,因此這個集合的基數是7。maven
<dependency> <groupId>net.agkn</groupId> <artifactId>hll</artifactId> <version>1.6.0</version> </dependency>
使用網站
@Test public void testSimpleUse(){ final int seed = 123456; HashFunction hash = Hashing.murmur3_128(seed); // data on which to calculate distinct count final Integer[] data = new Integer[]{1, 1, 2, 3, 4, 5, 6, 6, 6, 7, 7, 7, 7, 8, 10}; final HLL hll = new HLL(13, 5); //number of bucket and bits per bucket for (int item : data) { final long value = hash.newHasher().putInt(item).hash().asLong(); hll.addRaw(value); } System.out.println("Distinct count="+ hll.cardinality()); }
設想成一次不斷投硬幣的過程,非正面即反面(每一面的機率爲0.5)。 在這個過程當中,投擲次數大於k的機率是0.5^k(連續投擲出k個反面),在一次過程當中,投擲次數小於k的機率是(1-0.5)^k。
所以,在n次投擲過程當中,投擲次數均小於k的機率是.net
P(x<=k)=(1-0.5^k)^n P(x>=k)=1-(1-0.5^k)^n
從以上公式,能夠看出,當n<=k)的機率,接近爲0。而當n>>k時,P(x<=k)的機率接近爲0。因此,當n>>k時,沒有一次投擲次數大於k的機率幾乎爲0。code
將一次過程,理解成一個比特子串,反面爲0,正面爲1, 投擲次數k對應第一個1出現的位置,當統計子串足夠多時,其最大的第一個1的位置爲j,那麼當n>>2^j時,P(x<=k)接近爲0,當n<<2^j時,P(x>=0)也趨向爲0。也就是說,在獲得x=k的前提下,咱們能夠認爲n=2^j。blog
再通俗點說明: 假設咱們爲一個數據集合生成一個8位的哈希串,那麼咱們獲得00000111的機率是很低的,也就是說,咱們生成大量連續的0的機率是很低的。生成連續5個0的機率是1/32,那麼咱們獲得這個串時,能夠估算,這個數據集的基數是32。內存