草图

GoogleSQL for BigQuery 支持数据草图。数据草图是数据聚合的简洁汇总。它会捕获所有必要的信息,以提取聚合结果、继续数据聚合或与其他草图合并从而进行重新聚合。

使用草图计算指标比计算确切值便宜很多。如果您的计算速度太慢或需要过多的临时存储空间,请使用草图来缩短查询时间并减少资源。

此外,计算基数(例如不同用户的数量)或分位数(例如访问时长中位数)通常只能通过对原始数据运行作业来实现,因为已聚合的数据无法再组合。

假设一个表包含以下数据:

产品 用户数量 访问时长中位数
产品 A 5 亿 10 分钟
产品 B 2000 万 2 分钟

我们无法计算这两个产品的用户总数,因为我们不知道表中有多少用户同时使用了两个产品。 同样,由于访问时长分布已丢失,因此无法计算访问时长中位数。

一种解决方案是改为将草图存储在表中。每个草图是特定输入属性(例如基数)的近似和紧凑表示,您可以存储、合并(或重新聚合)和查询接近精确的结果。在上一个示例中,您可以通过创建并合并(重新汇总)每个商品的草图来估算商品 A 和商品 B 的不同用户数。您还可以使用同样可以合并和查询的分位数草图来估算访问时长中位数。

例如,以下查询使用 HLL++KLL 草图来估算 YouTube(产品 A)和 Google 地图(产品 B)的唯一身份用户数和访问时长中位数:

-- Build sketches for YouTube stats.
CREATE TABLE user.YOUTUBE_ACCESS_STATS
AS
SELECT
  HLL_COUNT.INIT(user_id) AS distinct_users_sketch,
  KLL_QUANTILES.INIT_INT64(visit_duration_ms) AS visit_duration_ms_sketch,
  hour_of_day
FROM YOUTUBE_ACCESS_LOG()
GROUP BY hour_of_day;

-- Build sketches for Maps stats.
CREATE TABLE user.MAPS_ACCESS_STATS
AS
SELECT
  HLL_COUNT.INIT(user_id) AS distinct_users_sketch,
  KLL_QUANTILES.INIT_INT64(visit_duration_ms) AS visit_duration_ms_sketch,
  hour_of_day
FROM MAPS_ACCESS_LOG()
GROUP BY hour_of_day;

-- Query YouTube hourly stats.
SELECT
  HLL_COUNT.EXTRACT(distinct_users_sketch) AS distinct_users,
  KLL_QUANTILES.EXTRACT_POINT_INT64(visit_duration_ms_sketch, 0.5)
  AS median_visit_duration, hour_of_day
FROM user.YOUTUBE_ACCESS_STATS;

-- Query YouTube daily stats.
SELECT
  HLL_COUNT.MERGE(distinct_users_sketch),
  KLL_QUANTILES.MERGE_POINT_INT64(visit_duration_ms_sketch, 0.5)
  AS median_visit_duration, date
FROM user.YOUTUBE_ACCESS_STATS
GROUP BY date;

-- Query total stats across YouTube and Maps.
SELECT
  HLL_COUNT.MERGE(distinct_users_sketch) AS unique_users_all_services,
  KLL_QUANTILES.MERGE_POINT_INT64(visit_duration_ms_sketch, 0.5)
    AS median_visit_duration_all_services,
FROM
  (
    SELECT * FROM user.YOUTUBE_ACCESS_STATS
    UNION ALL
    SELECT * FROM user.MAPS_ACCESS_STATS
  );

由于草图是原始数据的有损压缩,因此会引入统计误差,该误差由误差界限或置信区间 (CI) 表示。对于大多数应用而言,这种不确定性很小。例如,一个典型的基数计数草图的相对误差为所有案例的 95% 的 1%。草图会牺牲一些准确率或精确率,以换取更快、更便宜的计算以及更少的存储空间。

简而言之,草图具有以下主要属性:

  • 表示特定指标的近似汇总
  • 是否紧凑
  • 是内存中次线性数据结构的序列化形式
  • 通常具有固定大小,并且渐近地小于输入
  • 可能会引入统计误差,您可以通过精确度级别确定
  • 可与其他草图合并,以汇总底层数据集的并集

通过草图合并进行重新聚合

借助草图,您可以存储和合并数据,以便高效地重新汇总数据。这使得草图对于数据集的具体化视图特别有用。您可以合并草图,以便根据为每个数据流创建的部分草图构建多个数据流的汇总。

例如,如果您为每天估算的不同用户数创建一个草图,您可以通过合并每日草图来获得过去 7 天的不同用户数。重新聚合已合并的每日草图有助于避免读取数据集的完整输入。

草图重新聚合在在线分析处理 (OLAP) 中也很有用。您可以合并草图,以创建 OLAP 立方体的总览,其中草图汇总了立方体的一个或多个特定维度的数据。真正不同的计数无法实现 OLAP 总览。

我应该使用哪种类型的草图?

不同的草图算法针对不同类型的指标而设计,例如针对计数的 HLL++ 和针对分位数的 KLL。GoogleSQL 还提供了近似聚合函数,您可以使用这些函数查询这些类型的数据,而无需指定查询详情(例如精度级别)。

您使用的草图取决于您需要估算的数据类型。

估算基数

如果您需要估算基数,请使用 HLL++ 草图

例如,如需获取在给定月份内活跃使用产品的唯一身份用户数量(MAU 或 28DAU 指标),请使用 HLL++ 草图。

计算分位数

如果您需要获取数据集的分位数,请使用 KLL 草图

例如,如需获取实体店内客户的光顾时长中位数,或者跟踪票据在解决之前留在队列中的第 95 百分位延迟时间,请使用 KLL 草图。

HLL++ 草图

HyperLogLog++ (HLL++) 是一种用于估算基数的草图算法。HLL++ 基于《HyperLogLog 实践》白皮书,其中 ++ 表示对 HyperLogLog 算法进行的增强。

基数是草图输入中的不同元素的数量。例如,您可以使用 HLL++ 草图来获取打开应用的唯一身份用户数量。

HLL++ 估算极小和极大的基数。HLL++ 包括一个 64 位哈希函数、用于减少较小基数估计值内存要求的稀疏表示法,以及用于较小基数估计值的经验偏差校正。

精度

HLL++ 草图支持自定义精度。下表展示了支持的精确率值、最大存储空间大小以及典型精确率级别的置信区间 (CI):

精确率 存储空间上限 65% CI 95% CI 99% CI
10 1 KiB + 28 B ±3.25% ±6.50% ±9.75%
11 2 KiB + 28 B ±2.30% ±4.60% ±6.89%
12 4 KiB + 28 B ±1.63% ±3.25% ±4.88%
13 8 KiB + 28 B ±1.15% ±2.30% ±3.45%
14 16 KiB + 30 B ±0.81% ±1.63% ±2.44%
15(默认) 32 KiB + 30 B ±0.57% ±1.15% ±1.72%
16 64 KiB + 30 B ±0.41% ±0.81% ±1.22%
17 128 KiB + 30 B ±0.29% ±0.57% ±0.86%
18 256 KiB + 30 B ±0.20% ±0.41% ±0.61%
19 512 KiB + 30 B ±0.14% ±0.29% ±0.43%
20 1024 KiB + 30 B ±0.10% ±0.20% ±0.30%
21 2048 KiB + 32 B ±0.07% ±0.14% ±0.22%
22 4096 KiB + 32 B ±0.05% ±0.10% ±0.15%
23 8192 KiB + 32 B ±0.04% ±0.07% ±0.11%
24 16384 KiB + 32 B ±0.03% ±0.05% ±0.08%

您可以在使用 HLL_COUNT.INIT 函数初始化 HLL++ 草图时定义精确率。

删除

您不能从 HLL++ 草图中删除值。

其他详情

如需查看可与 HLL++ 草图结合使用的函数列表,请参阅 HLL++ 函数

Sketch 集成

您可以将 HLL++ 草图与其他系统集成。例如,您可以在外部应用(如 DataflowApache SparkZetaSketch)中构建草图,并在 GoogleSQL 中使用它们,反之亦然。

除了 GoogleSQL 之外,您还可以将 HLL++ 草图与 Java 结合使用。

KLL 草图

KLL(Karnin-Lang-Liberty 的缩写)是一种流式算法,用于计算近似分位数的草图。与精确计算相比,它可以更高效地计算任意分位数,但代价是会产生一些近似误差。

精度

KLL 草图支持自定义精度。精度定义了返回的近似分位数 q 的精确程度。

默认情况下,近似分位数的排名最多可以与 ⌈Φ * n⌉ 相差 ±1/1000 * n,其中 n 是输入中的行数,而 ⌈Φ * n⌉ 是确切分位数的排名。

如果您提供自定义精度,大致分位数的排名最多会与确切分位数的排名相差 ±1/precision * n。在 99.999% 的情况下,误差都在此误差范围内。此误差保证仅适用于精确排名和近似排名之间的差异。某个分位数的确切值与近似值之间的数值差异可能会非常大。

例如,假设您要查找中位数值 Φ = 0.5,并且使用默认精度 1000。然后,在 99.999% 的情况下,KLL_QUANTILES.EXTRACT_POINT 函数返回的值的排名与实际排名的差值最多为 n/1000。换言之,返回的值几乎总是介于第 49.9 个百分位和第 50.1 个百分位之间。如果您的草图中有 1,000,000 个项,则返回的中位数排名几乎总是介于 499,000 到 501,000 之间。

如果您使用自定义精度 100 来查找中位数值,那么在 99.999% 的情况下,KLL_QUANTILES.EXTRACT_POINT 函数返回的值的排名与实际排名的差值最多为 n/100。换言之,返回的值几乎总是介于第 49 个百分位和第 51 个百分位之间。如果您的草图中有 1,000,000 个项,则返回的中位数排名几乎总是介于 490,000 到 510,000 之间。

您可以在使用 KLL_QUANTILES.INIT 函数初始化 KLL 草图时定义精确率。

大小

KLL 草图大小取决于精度参数和输入类型。如果输入类型为 INT64,则草图可以使用额外的优化,如果输入值来自小型宇宙,这种优化特别有用。下表包含 INT64 的两列。其中一个列会为来自大小为 1B 的有限宇宙的项提供草图大小的上限,而另一个列会为任意输入值提供上限。

精确率 FLOAT64 INT64 (<1B) INT64(任意)
10 761 B 360 B 717 B
20 1.46 KB 706 B 1.47 KB
50 3.49 KB 1.72 KB 3.60 KB
100 6.94 KB 3.44 KB 7.12 KB
200 13.87 KB 6.33 KB 13.98 KB
500 35.15 KB 14.47 KB 35.30 KB
1000 71.18 KB 27.86 KB 71.28 KB
2000 144.51 KB 55.25 KB 144.57 KB
5000 368.87 KB 139.54 KB 368.96 KB
10000 749.82 KB 282.27 KB 697.80 KB
20000 1.52 MB 573.16 KB 1.37 MB
50000 3.90 MB 1.12 MB 3.45 MB
100000 7.92 MB 2.18 MB 6.97 MB

Phi

Phi (Φ) 表示要生成的分位数,以示意输入中的总行数的一部分表示,归一化为 0 到 1 之间的值。如果函数支持 phi,则该函数会返回一个值 v,使得大约 Φ * n 个输入小于或等于 v,而 (1-Φ) * n 个输入大于或等于 v

其他详情

如需查看可与 KLL 草图结合使用的函数列表,请参阅 KLL 分位函数

KLL 算法在流中的最佳分位数近似值论文中定义,并以其作者 Karnin、Lang 和 Liberty 的名字命名,他们于 2016 年发表了这篇论文。KLL 算法通过使用可变大小的缓冲区来减少大型数据集的内存使用量,从而改进了旧版 MP80 算法,将草图大小从 O(log n) 缩减到 O(1)。由于算法具有非确定性,因此使用相同数据集以相同精度创建的草图可能并不相同。

分位数

分位数是将概率分布的范围划分为具有相等概率的连续区间,或以相同方式划分样本中的观测值的切割点。借助支持分位数的草图,您可以通过将这些区间和概率汇总为近似分位数结果来估算分位数。

通常有两种方法可以定义分位数:

  • 对于正整数 qq 分位数是一组值,可将输入集划分为大小几乎相等的 q 个子集。其中一些具有特定名称:单个 2 分位数是中位数,4 分位数是四分位数,100 分位数是百分位数,等等。KLL 函数还会返回输入的(确切)最小值和最大值,因此在查询 2 分位数时,会返回三个值。

  • 或者,可以将分位数视为单个 Φ 分位数,其中 Φ0 <= Φ <= 1 的实数。Φ 分位 x 是输入的一个元素,其中 Φ 分数小于或等于 x(1-Φ) 分数大于或等于 x。在此表示法中,中位数是 0.5 分位数,第 95 分位数是 0.95 分位数。

例如,您可以使用支持分位数的草图来获取用户打开应用的次数的中位数。

近似聚合函数

作为基于草图的近似函数的特定替代方案,GoogleSQL 提供了预定义的近似聚合函数。这些近似聚合函数支持常见估算(例如不同计数、分位数和顶部计数)的草图,但不允许使用自定义精确率。与其他类型的草图一样,它们也不会公开并存储草图以用于重新聚合。近似聚合函数旨在运行基于草图的快速查询,而无需进行详细配置。

如需查看可与基于草图的近似函数结合使用的近似聚合函数列表,请参阅近似聚合函数