Bigquery 中的模运算。计算 `x % y`,其中 `x` 是一个 128 位数字
Modulo arithmetic in Bigquery. Compute `x % y`, where `x` is a 128-bit number
将字符串的 MD5 作为整数 x
的 128 位表示,我如何在 Google Bigquery 中计算 x % y
,其中 y
将通常相对较小(大约 1000)?
Bigquery 有一个 MD5 函数,返回一个 BYTES
类型的结果,有 16 个字节(即 128 位)。
(背景:这是为了计算确定性伪随机数。但是,由于遗留和兼容性原因,我在算法上没有灵活性!即使我们知道它有一个 (very slight) bias .)
每天需要针对不同的输入字符串和不同的模数执行 millions/billions 次,因此希望它可以高效地完成。作为回退,我可以用另一种语言在外部计算它,然后再上传到 Bigquery;但如果我可以直接在 Bigquery 中执行此操作,那就太好了。
我研究了很多数论,所以也许我们可以使用一些数学技巧。但是,我仍然停留在更基本的 BiqQuery 问题上
- 如何将字节数组转换为某种 "big integer" 类型?
- 我可以从
BYTES
数组访问字节的子范围吗?
- 给定一个字节(或者可能是四个字节?),我可以将其转换为可以应用算术运算的整数类型吗?
使用 power of math 和较长的 SQL 函数:
CREATE TEMP FUNCTION modulo_md5(str ANY TYPE, m ANY TYPE) AS ((
SELECT MOD(MOD(MOD(MOD(MOD(MOD(MOD(MOD(MOD(MOD(MOD(MOD(MOD(MOD(MOD(MOD(0
* 256 + num[OFFSET(0)], m )
* 256 + num[OFFSET(1)], m )
* 256 + num[OFFSET(2)], m )
* 256 + num[OFFSET(3)], m )
* 256 + num[OFFSET(4)], m )
* 256 + num[OFFSET(5)], m )
* 256 + num[OFFSET(6)], m )
* 256 + num[OFFSET(7)], m )
* 256 + num[OFFSET(8)], m )
* 256 + num[OFFSET(9)], m )
* 256 + num[OFFSET(10)], m )
* 256 + num[OFFSET(11)], m )
* 256 + num[OFFSET(12)], m )
* 256 + num[OFFSET(13)], m )
* 256 + num[OFFSET(14)], m )
* 256 + num[OFFSET(15)], m )
FROM (SELECT TO_CODE_POINTS(MD5(str)) num)
));
SELECT title, modulo_md5(title, 177) result, TO_HEX(MD5(title)) md5
FROM `fh-bigquery.wikipedia_v3.pageviews_2019`
WHERE wiki='en'
LIMIT 100000
现在您可以将其用作持久共享 UDF:
SELECT fhoffa.x.modulo_md5("any string", 177) result
将字符串的 MD5 作为整数 x
的 128 位表示,我如何在 Google Bigquery 中计算 x % y
,其中 y
将通常相对较小(大约 1000)?
Bigquery 有一个 MD5 函数,返回一个 BYTES
类型的结果,有 16 个字节(即 128 位)。
(背景:这是为了计算确定性伪随机数。但是,由于遗留和兼容性原因,我在算法上没有灵活性!即使我们知道它有一个 (very slight) bias .)
每天需要针对不同的输入字符串和不同的模数执行 millions/billions 次,因此希望它可以高效地完成。作为回退,我可以用另一种语言在外部计算它,然后再上传到 Bigquery;但如果我可以直接在 Bigquery 中执行此操作,那就太好了。
我研究了很多数论,所以也许我们可以使用一些数学技巧。但是,我仍然停留在更基本的 BiqQuery 问题上
- 如何将字节数组转换为某种 "big integer" 类型?
- 我可以从
BYTES
数组访问字节的子范围吗? - 给定一个字节(或者可能是四个字节?),我可以将其转换为可以应用算术运算的整数类型吗?
使用 power of math 和较长的 SQL 函数:
CREATE TEMP FUNCTION modulo_md5(str ANY TYPE, m ANY TYPE) AS ((
SELECT MOD(MOD(MOD(MOD(MOD(MOD(MOD(MOD(MOD(MOD(MOD(MOD(MOD(MOD(MOD(MOD(0
* 256 + num[OFFSET(0)], m )
* 256 + num[OFFSET(1)], m )
* 256 + num[OFFSET(2)], m )
* 256 + num[OFFSET(3)], m )
* 256 + num[OFFSET(4)], m )
* 256 + num[OFFSET(5)], m )
* 256 + num[OFFSET(6)], m )
* 256 + num[OFFSET(7)], m )
* 256 + num[OFFSET(8)], m )
* 256 + num[OFFSET(9)], m )
* 256 + num[OFFSET(10)], m )
* 256 + num[OFFSET(11)], m )
* 256 + num[OFFSET(12)], m )
* 256 + num[OFFSET(13)], m )
* 256 + num[OFFSET(14)], m )
* 256 + num[OFFSET(15)], m )
FROM (SELECT TO_CODE_POINTS(MD5(str)) num)
));
SELECT title, modulo_md5(title, 177) result, TO_HEX(MD5(title)) md5
FROM `fh-bigquery.wikipedia_v3.pageviews_2019`
WHERE wiki='en'
LIMIT 100000
现在您可以将其用作持久共享 UDF:
SELECT fhoffa.x.modulo_md5("any string", 177) result