hyperloglog的java版使用

對於海量數據來講,數據內存佔用會變得很高. 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

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。內存

doc

相關文章
相關標籤/搜索