在BigQuery中,如何随机拆分查询结果?

syl*_*ong 2 sql random ansi-sql google-bigquery

在 BigQuery(标准 SQL)中,我想从查询中随机分割结果行。

  • 分割需要保持一致,并且不应随时间变化:这意味着每次运行查询时,分割都应保持不变。

  • 特别是,如果将数据添加到源表,则先前位于拆分一侧的数据应保留在同一拆分中。

  • 该策略应该能够处理不同的分割比率

例如,我目前有一个表mytable,其中包含列(order_id、、)created_atcountry

一方面,10%/90% 的分配

SELECT 
   *
FROM
   `mytable`
WHERE RAND() <= 10/90
Run Code Online (Sandbox Code Playgroud)

另一方面

SELECT 
   *
FROM
   `mytable`
WHERE RAND() > 10/90
Run Code Online (Sandbox Code Playgroud)

但这会产生不一致的分裂。有没有办法正确实现这一目标?

syl*_*ong 6

解决方案是在一个列上使用哈希函数来唯一区分源表的每一行(例如此处orderId)。

BigQuery 有一个哈希函数,其目标类型是有符号的INT64(源STRINGBYTES):(FARM_FINGERPRINT来自此处)。

一种解决方案是根据每行编码,FARM_FINGERPRINT(orderId)该行是所有数字均匀分布的样本INT64

对于给定的k,MOD(ABS(FARM_FINGERPRINT(orderId)),k)构成 中整数的均匀分布[0,k-1](请注意MOD(a,b)负数ab正数可能会返回负数)。

因此,假设您想要 10%/90% 的分割。

每个拆分的查询如下所示:

SELECT 
   *
FROM
   `mytable`
WHERE MOD(ABS(FARM_FINGERPRINT(orderId)),10) = 0
Run Code Online (Sandbox Code Playgroud)

SELECT 
   *
FROM
   `mytable`
WHERE MOD(ABS(FARM_FINGERPRINT(orderId)),10) != 0
Run Code Online (Sandbox Code Playgroud)

它可以推广到任何 1/k 分割:

SELECT 
   *
FROM
   `mytable`
WHERE MOD(ABS(FARM_FINGERPRINT(orderId)),@k) = 0
Run Code Online (Sandbox Code Playgroud)

SELECT 
   *
FROM
   `mytable`
WHERE MOD(ABS(FARM_FINGERPRINT(orderId)),@k) != 0
Run Code Online (Sandbox Code Playgroud)

更改判别模整数的值(0在上面)允许有k不同的分割(例如,如果您在 ML 中进行多重交叉验证,这可能非常有用)。

最后但并非最不重要的:

  • 折叠对于表中的数据添加具有鲁棒性
  • 无论何时运行查询,折叠都保持不变