使用 BYTES 数据类型的 BigQuery UDF
BigQuery UDF using BYTES datatype
我目前正在尝试使用 Javascript 中的用户定义函数计算 BigQuery 中两个二进制字符串之间的汉明距离,我的模式非常简单:
row_id STRING
descriptors BYTES REPEATED
phash BYTES
我发现有点困惑的是,您显然将 BigQuery 中的 BYTES 作为 Base64 字符串处理,我导入了两个函数 atob()
和 btoa()
,这样我就可以工作了使用字节字符串的二进制形式而不是 Base64 表示:
我的查询目前看起来像这样:
CREATE TEMP FUNCTION f_PHASH_distance(ph1 BYTES, ph2 BYTES)
RETURNS INT64
LANGUAGE js AS
"""
return HammingDistance(ph1, ph2);
"""
OPTIONS (
library=["gs://test.appspot.com/HammingDistance.js",
"gs://test.appspot.com/btoa_atob.js"]
);
SELECT f_PHASH_distance(phash, CAST("9Slp3g9OgVI=" AS BYTES))
FROM ims.images WHERE row_id = "2333USX"
id = "2333USX" phash 的行在 base64 中等于 "9Slp3g9OgVI=",这意味着汉明距离为 0。但我目前在 BigQuery 上得到的不是 0,而是 35。
HammingDistance.js有以下内容:
function HammingDistance(a, b){
var count = 0;
for(var i = 0; i < a.length; i++){
// calculate XOR between the two chars
var xor = a.charCodeAt(i) ^ b.charCodeAt(i);
// count number of 1's on the result
for(var j = 0; j < 16; j++){
//add if LSB is 1
count += xor % 2;
//right shift the variable
xor = xor >> 1;
}
}
return count;
}
/**
* Calculates the distance between two Perceptual hashes of two images encoded
* in base 64
*/
function PHASHDistance(a, b){
return HammingDistance(atob(a), atob(b));
}
并在浏览器的 JS 控制台中进行测试,我确实得到了预期的结果。所以我假设我在转换方面做错了,但是关于带有 BYTE 参数的 UDF 的文档非常稀少。
如有任何帮助,我们将不胜感激。
看起来问题是您将 "9Slp3g9OgVI="
转换为字节,而不是将其从 base64 转换为字节。我想你想要这个:
SELECT f_PHASH_distance(phash, FROM_BASE64("9Slp3g9OgVI="))
FROM ims.images WHERE row_id = "2333USX"
您最好使用 SQL 函数而不是 JavaScript 函数,因为 JavaScript 通常没有那么快。这是 SQL 中的汉明距离实现,假设字节长度相等:
#standardSQL
CREATE TEMP FUNCTION HammingDistance(b1 BYTES, b2 BYTES) AS (
BIT_COUNT(b1 ^ b2)
);
WITH Input AS (
SELECT b'defdef' AS bytes UNION ALL
SELECT b'123de4' UNION ALL
SELECT b'abc123'
)
SELECT HammingDistance(b'abcdef', bytes)
FROM Input;
它对两个字节值进行按位异或,然后检查有多少位不相同。
如果有人正在寻找比较常规字符串(不是这个问题的二进制字符串)的解决方案,
我目前正在尝试使用 Javascript 中的用户定义函数计算 BigQuery 中两个二进制字符串之间的汉明距离,我的模式非常简单:
row_id STRING
descriptors BYTES REPEATED
phash BYTES
我发现有点困惑的是,您显然将 BigQuery 中的 BYTES 作为 Base64 字符串处理,我导入了两个函数 atob()
和 btoa()
,这样我就可以工作了使用字节字符串的二进制形式而不是 Base64 表示:
我的查询目前看起来像这样:
CREATE TEMP FUNCTION f_PHASH_distance(ph1 BYTES, ph2 BYTES)
RETURNS INT64
LANGUAGE js AS
"""
return HammingDistance(ph1, ph2);
"""
OPTIONS (
library=["gs://test.appspot.com/HammingDistance.js",
"gs://test.appspot.com/btoa_atob.js"]
);
SELECT f_PHASH_distance(phash, CAST("9Slp3g9OgVI=" AS BYTES))
FROM ims.images WHERE row_id = "2333USX"
id = "2333USX" phash 的行在 base64 中等于 "9Slp3g9OgVI=",这意味着汉明距离为 0。但我目前在 BigQuery 上得到的不是 0,而是 35。
HammingDistance.js有以下内容:
function HammingDistance(a, b){
var count = 0;
for(var i = 0; i < a.length; i++){
// calculate XOR between the two chars
var xor = a.charCodeAt(i) ^ b.charCodeAt(i);
// count number of 1's on the result
for(var j = 0; j < 16; j++){
//add if LSB is 1
count += xor % 2;
//right shift the variable
xor = xor >> 1;
}
}
return count;
}
/**
* Calculates the distance between two Perceptual hashes of two images encoded
* in base 64
*/
function PHASHDistance(a, b){
return HammingDistance(atob(a), atob(b));
}
并在浏览器的 JS 控制台中进行测试,我确实得到了预期的结果。所以我假设我在转换方面做错了,但是关于带有 BYTE 参数的 UDF 的文档非常稀少。
如有任何帮助,我们将不胜感激。
看起来问题是您将 "9Slp3g9OgVI="
转换为字节,而不是将其从 base64 转换为字节。我想你想要这个:
SELECT f_PHASH_distance(phash, FROM_BASE64("9Slp3g9OgVI="))
FROM ims.images WHERE row_id = "2333USX"
您最好使用 SQL 函数而不是 JavaScript 函数,因为 JavaScript 通常没有那么快。这是 SQL 中的汉明距离实现,假设字节长度相等:
#standardSQL
CREATE TEMP FUNCTION HammingDistance(b1 BYTES, b2 BYTES) AS (
BIT_COUNT(b1 ^ b2)
);
WITH Input AS (
SELECT b'defdef' AS bytes UNION ALL
SELECT b'123de4' UNION ALL
SELECT b'abc123'
)
SELECT HammingDistance(b'abcdef', bytes)
FROM Input;
它对两个字节值进行按位异或,然后检查有多少位不相同。
如果有人正在寻找比较常规字符串(不是这个问题的二进制字符串)的解决方案,