标签:
Redis 在 2.8.9 版本添加了 HyperLogLog 结构。
Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。
在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。
但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。
什么是基数?
比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数(不重复元素)为5。 基数估计就是在误差可接受的范围内,快速计算基数。
实例
以下实例演示了 HyperLogLog 的工作过程:
redis 127.0.0.1:6379> PFADD w3ckey “redis”
1) (integer) 1
redis 127.0.0.1:6379> PFADD w3ckey “mongodb”
1) (integer) 1
redis 127.0.0.1:6379> PFADD w3ckey “mysql”
1) (integer) 1
redis 127.0.0.1:6379> PFCOUNT w3ckey
(integer) 3
Redis HyperLogLog 命令
下表列出了 redis HyperLogLog 的基本命令:
序号 命令及描述
1 PFADD key element [element …]
添加指定元素到 HyperLogLog 中。
2 PFCOUNT key [key …]
返回给定 HyperLogLog 的基数估算值。
3 PFMERGE destkey sourcekey [sourcekey …]
将多个 HyperLogLog 合并为一个 HyperLogLog
package com.hong.api.redis;
import redis.clients.jedis.Jedis;
public class JedisUserVisitTest {
private Jedis jedis = null;
public JedisUserVisitTest(String host, int port) {
jedis = new Jedis(host, port);
}
public void setHyperLogLog(String key, String value) {
jedis.pfadd(key, value);
}
public void setHyperLogLog(String key, String[] values) {
jedis.pfadd(key, values);
}
public Jedis getJedis() {
return jedis;
}
public void setJedis(Jedis jedis) {
this.jedis = jedis;
}
public static void main(String[] args) {
JedisUserVisitTest jedisUserVisitTest = new JedisUserVisitTest("192.168.109.133", 6379);
Gen3 rand = new Gen3();
int size = 1000000 + 1;
String[] arr = new String[size];
int top = 0;
for (long i = 0; i < 50000000000L; ++i) {
arr[top++] = rand.next() + "";
if (top == size) {
top = 0;
jedisUserVisitTest.setHyperLogLog("visit", arr);
}
}
if (top != size) {
top = 0;
jedisUserVisitTest.setHyperLogLog("visit", arr);
}
System.out.println(jedisUserVisitTest.getJedis().pfcount("visit"));
}
}
package com.hong.api.redis;
public class Gen3 {
private long[] state = new long[624];
private int left = 1;
public Gen3() {
for (int j = 1; j < 624; j++) {
state[j] = (1812433253L * (state[j - 1] ^ (state[j - 1] >> 30)) + j);
state[j] &= 0xfffffffffL;
}
}
private static final long twist(long u, long v) {
return (((u & 0x80000000L) | (v & 0x7fffffffL)) >> 1) ^ ((v & 1) == 1 ? 0x9908b0dfL : 0);
}
public void next_state() {
int p = 0;
left = 624;
for (int j = 228; --j > 0; p++)
state[p] = state[p + 397] ^ twist(state[p], state[p + 1]);
for (int j = 397; --j > 0; p++)
state[p] = state[p - 227] ^ twist(state[p], state[p + 1]);
state[p] = state[p - 227] ^ twist(state[p], state[0]);
}
public long next() {
if (--left == 0)
next_state();
return state[624 - left];
}
public static void main(String[] args) {
Gen3 rand = new Gen3();
long a = System.currentTimeMillis();
long max = 0;
for (long i = 0; i < 50000000000L; i++) {
// System.out.println(rand.next());
long ans = rand.next();
if (ans > max)
max = ans;
}
long b = System.currentTimeMillis();
System.out.println(b - a);
System.out.println(max);
}
}
标签:
原文地址:http://blog.csdn.net/hong0220/article/details/51347692