The Java Embedded Aggregator Class ApproxDistinctCountAggregate

ApproxDistinctCountAggregate implements the "approximate distinct count" aggregation. (Note that this is not a precise result.)

For an overview see page Java Aggregator Class

Class Definition

 
    public static class ApproxDistinctCountAggregate implements Aggregate
    {
        static final int HASH_BITS = 25;
        static final int N_HASHES = 1 << (32 - HASH_BITS);
         
        public void initialize(Object val) 
        {
            accumulate(val);
        }
 
        public void accumulate(Object val) 
        {
            int h = val.hashCode();
            int j = h >>> HASH_BITS;
            int zeroBits = 1;
            while ((h & 1) == 0 && zeroBits <= HASH_BITS) 
             {
                h >>>= 1;
                zeroBits += 1;
            }
            if (maxZeroBits[j] < zeroBits) 
            {
                maxZeroBits[j] = zeroBits;
            }
        }
         
        public Object result()
        {
            final int m = N_HASHES;
            final double alpha_m = 0.7213 / (1 + 1.079 / (double)m);
            final double pow_2_32 = 0xffffffff;
            double E, c = 0;
            int i;
            for (i = 0; i < m; i++)
            {
                c += 1 / Math.pow(2., (double)maxZeroBits[i]);
            }
            E = alpha_m * m * m / c;
 
            if (E <= (5 / 2. * m))
            {
                double V = 0;
                for (i = 0; i < m; i++)
                {
                    if (maxZeroBits[i] == 0) 
                    {
                        V += 1;
                    }
                }
                if (V > 0)
                {
                    E = m * Math.log(m / V);
                }
            }
            else if (E > (1 / 30. * pow_2_32))
            {
                E = -pow_2_32 * Math.log(1 - E / pow_2_32);
            }
            return new Long((long)E);
        }
 
        public void merge(Aggregate other) 
        {
            int[] otherMaxZeroBits = ((ApproxDistinctCountAggregate)other).maxZeroBits;
            for (int i = 0; i < N_HASHES; i++) 
            {
                if (maxZeroBits[i] < otherMaxZeroBits[i]) 
                {
                    maxZeroBits[i] = otherMaxZeroBits[i];
                }
            }
        }
 
        int[] maxZeroBits = new int[N_HASHES];
    }