HyperLogLog
HyperLogLog 是一种概率型数据结构,用于估计集合的基数。
HyperLogLog 是一种概率型数据结构,用于估计集合的基数。作为一种概率型数据结构,HyperLogLog 以牺牲完美准确性为代价,换取了高效的空间利用率。
Redis HyperLogLog 实现使用最多 12 KB,并提供 0.81% 的标准误差。
计算唯一项目的数量通常需要与要计算的项目数量成正比的内存量,因为您需要记住过去已经看到的元素,以避免重复计数。但是,存在一组算法可以将内存换取精度:它们返回一个具有标准误差的估计值,在 Redis 对 HyperLogLog 的实现中,该误差小于 1%。该算法的神奇之处在于,您不再需要使用与计算的项目数量成正比的内存量,而可以使用固定量的内存;在最坏情况下为 12k 字节,或者如果您的 HyperLogLog(我们现在将其简称为 HLL)仅看到很少的元素,则使用更少的内存。
Redis 中的 HLL,虽然在技术上是一种不同的数据结构,但被编码为 Redis 字符串,因此您可以调用 GET
来序列化 HLL,并使用 SET
将其反序列化回服务器。
从概念上讲,HLL API 类似于使用集合来执行相同的任务。您将使用 SADD
将每个观察到的元素添加到集合中,并将使用 SCARD
检查集合中元素的数量,这些元素是唯一的,因为 SADD
不会重新添加现有元素。
虽然您实际上并没有将项目添加到 HLL 中,因为数据结构仅包含一个不包含实际元素的状态,但 API 是一样的。
- 每次看到一个新元素时,您都会使用
PFADD
将其添加到计数中。
- 当您要检索使用
PFADD
命令添加的唯一元素的当前近似值时,可以使用 PFCOUNT
命令。如果您需要合并两个不同的 HLL,可以使用 PFMERGE
命令。由于 HLL 提供了唯一元素的近似计数,因此合并的结果将为您提供两个源 HLL 中唯一元素数量的近似值。
> PFADD bikes Hyperion Deimos Phoebe Quaoar
(integer) 1
> PFCOUNT bikes
(integer) 4
> PFADD commuter_bikes Salacia Mimas Quaoar
(integer) 1
> PFMERGE all_bikes bikes commuter_bikes
OK
> PFCOUNT all_bikes
(integer) 6
"""
Code samples for HyperLogLog doc pages:
https://redis.ac.cn/docs/latest/develop/data-types/probabilistic/hyperloglogs/
"""
import redis
r = redis.Redis(decode_responses=True)
res1 = r.pfadd("bikes", "Hyperion", "Deimos", "Phoebe", "Quaoar")
print(res1) # >>> 1
res2 = r.pfcount("bikes")
print(res2) # >>> 4
res3 = r.pfadd("commuter_bikes", "Salacia", "Mimas", "Quaoar")
print(res3) # >>> 1
res4 = r.pfmerge("all_bikes", "bikes", "commuter_bikes")
print(res4) # >>> True
res5 = r.pfcount("all_bikes")
print(res5) # >>> 6
import assert from 'assert';
import { createClient } from 'redis';
const client = createClient();
await client.connect();
const res1 = await client.pfAdd('bikes', ['Hyperion', 'Deimos', 'Phoebe', 'Quaoar']);
console.log(res1); // >>> true
const res2 = await client.pfCount('bikes');
console.log(res2); // >>> 4
const res3 = await client.pfAdd('commuter_bikes', ['Salacia', 'Mimas', 'Quaoar']);
console.log(res3); // >>> true
const res4 = await client.pfMerge('all_bikes', ['bikes', 'commuter_bikes']);
console.log(res4); // >>> OK
const res5 = await client.pfCount('all_bikes');
console.log(res5); // >>> 6
package io.redis.examples;
import org.junit.Assert;
import org.junit.Test;
import redis.clients.jedis.UnifiedJedis;
public class HyperLogLogExample {
public void run() {
UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379");
long res1 = jedis.pfadd("bikes", "Hyperion", "Deimos", "Phoebe", "Quaoar");
System.out.println(res1); // >>> 1
long res2 = jedis.pfcount("bikes");
System.out.println(res2); // >>> 4
long res3 = jedis.pfadd("commuter_bikes", "Salacia", "Mimas", "Quaoar");
System.out.println(res3); // >>> 1
String res4 = jedis.pfmerge("all_bikes", "bikes", "commuter_bikes");
System.out.println(res4); // >>> OK
long res5 = jedis.pfcount("all_bikes");
System.out.println(res5); // >>> 6
}
}
using NRedisStack.Tests;
using StackExchange.Redis;
public class Hll_tutorial
{
[SkipIfRedis(Is.OSSCluster)]
public void run()
{
var muxer = ConnectionMultiplexer.Connect("localhost:6379");
var db = muxer.GetDatabase();
bool res1 = db.HyperLogLogAdd("{bikes}", new RedisValue[] { "Hyperion", "Deimos", "Phoebe", "Quaoar" });
Console.WriteLine(res1); // >>> True
long res2 = db.HyperLogLogLength("{bikes}");
Console.WriteLine(res2); // >>> 4
bool res3 = db.HyperLogLogAdd("commuter_{bikes}", new RedisValue[] { "Salacia", "Mimas", "Quaoar" });
Console.WriteLine(res3); // >>> True
db.HyperLogLogMerge("all_{bikes}", "{bikes}", "commuter_{bikes}");
long res4 = db.HyperLogLogLength("all_{bikes}");
Console.WriteLine(res4); // >>> 6
// Tests for 'pfadd' step.
}
}
此数据结构的一些用例示例包括:每天计算用户在搜索表单中执行的唯一查询次数、网站的唯一访客数量以及其他类似的情况。
Redis 也能够执行 HLL 的并集操作,请查看 完整文档 以了解更多信息。
用例
网页的匿名唯一访问(SaaS、分析工具)
此应用程序回答了以下问题
- 该页面在这一天收到了多少次唯一访问?
- 有多少个唯一用户播放了这首歌?
- 有多少个唯一用户观看了此视频?
注意
在某些国家/地区,存储 IP 地址或任何其他类型的个人标识符违反法律,这使得无法获取您网站的唯一访客统计信息。
每个页面(视频/歌曲)每个周期都会创建一个 HyperLogLog,并且每次访问都会将每个 IP/标识符添加到其中。
基本命令
查看 HyperLogLog 命令的完整列表。
写入 (PFADD
) 和读取 (PFCOUNT
) HyperLogLog 的操作在恒定时间和空间内完成。合并 HLL 的时间复杂度为 O(n),其中 n 是草图的数量。
限制
HyperLogLog 可以估计最多 18,446,744,073,709,551,616 (2^64) 个成员的集合的基数。
了解更多信息