草图

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 的精确度。

默认情况下,近似分位数的排名与精确分位数的排名之间的差值最多为 ±1/1000 * n,其中 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 的两列。一列提供来自有限宇宙(大小为 10 亿)的项目的草图大小上限,另一列提供任意输入值的上限。

精确率 FLOAT64 INT64(<10 亿) 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 算法在《Optimal Quantile Approximation in Streams》一文中定义,并以其作者 Karnin、Lang 和 Liberty 的名字命名,他们于 2016 年发表了该论文。KLL 算法使用可变大小的缓冲区来减少大型数据集的内存使用量,从而改进了旧的 MP80 算法,将草图大小从 O(log n) 减小到 O(1)。由于算法具有不确定性,因此使用相同精度对同一组数据创建的草图可能并不完全相同。

分位数

分位数是用于将概率分布的范围划分为具有相等概率的连续区间的分割点,或者以相同方式划分样本中的观测值。支持分位数的 sketch 可让您通过将这些区间和概率汇总为近乎精确的分位数结果来估计分位数。

分位数的定义通常有两种:

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

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

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

近似聚合函数

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

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