syl*_*ong 2 sql random ansi-sql google-bigquery
在 BigQuery(标准 SQL)中,我想从查询中随机分割结果行。
分割需要保持一致,并且不应随时间变化:这意味着每次运行查询时,分割都应保持不变。
特别是,如果将数据添加到源表,则先前位于拆分一侧的数据应保留在同一拆分中。
该策略应该能够处理不同的分割比率
例如,我目前有一个表mytable,其中包含列(order_id、、)created_at:country
一方面,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)
但这会产生不一致的分裂。有没有办法正确实现这一目标?
解决方案是在一个列上使用哈希函数来唯一区分源表的每一行(例如此处orderId)。
BigQuery 有一个哈希函数,其目标类型是有符号的INT64(源STRING或BYTES):(FARM_FINGERPRINT来自此处)。
一种解决方案是根据每行编码,FARM_FINGERPRINT(orderId)该行是所有数字均匀分布的样本INT64。
对于给定的k,MOD(ABS(FARM_FINGERPRINT(orderId)),k)构成 中整数的均匀分布[0,k-1](请注意MOD(a,b)负数a和b正数可能会返回负数)。
因此,假设您想要 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 中进行多重交叉验证,这可能非常有用)。
最后但并非最不重要的: