从丑陋的方式开始:您可以将数学展开到查询中。也就是转
for i in ... sum(min(...)/abs(...)) 进入对每个字段进行 SQL 操作。请注意,MIN 和 SUM 是您不想使用的聚合函数。而是将 + 用于 SUM,将 IF(a < b, a, b) 用于 MIN。 ABS(a, b) 看起来像 IF(a < b, b-a, a-b)。如果你只是计算欧几里得距离,你可以这样做
SELECT left.user, right.user,
SQRT((left.x-right.x)*(left.x-right.x)
+ (left.y-right.y)*(left.y-right.y)
+ (left.z-right.z)*(left.z-right.z)) as dist
FROM (
SELECT *
FROM dataset.table1 AS left
CROSS JOIN dataset.table1 AS right)
更好的方法是用户定义函数,并将向量创建为重复值。然后,您可以编写一个 DISTANCE() 函数,该函数从交叉连接的左侧和右侧对两个数组执行计算。如果您尚未加入 UDF 测试版计划并想加入,请联系谷歌云支持。
最后,如果您将架构从 {user:string, field1:float, field2:float, field3:float,...} 更改为 {user:string, fields:[field:float]}
然后,您可以使用位置展平该字段并对其进行交叉连接。如:
SELECT
user,
field,
index,
FROM (FLATTEN((
SELECT
user,
fields.field as field,
POSITION(fields.field) as index,
from [dataset1.table1]
), fields))
如果将其保存为视图,则将其命名为“dataset1.flat_view”
然后你就可以加入了:
SELECT left.user as user1, right.user as user2,
left.field as l, right.field as r,
FROM dataset1.flat_view left
JOIN dataset1.flat_view right
ON left.index = right.index
WHERE left.user != right.user
这将为每对用户和每个字段匹配字段提供一行。您可以将其保存为视图“dataset1.joined_view”。
最后,您可以进行聚合:
既然你想要这个:
sum(min(user1_row[i], user2_row[i]) / abs(user1_row[i] - user2_row[i]))
看起来像:
SELECT user1, user2,
SUM((if (l < r, l, r)) / (if (l > r, l-r, r-l))
FROM [dataset1.joined_view]
GROUP EACH BY user1, user2