【问题标题】:Row Aggregation after Cross Join in BigQueryBigQuery 中交叉联接后的行聚合
【发布时间】:2015-06-16 09:12:24
【问题描述】:

假设您在 BigQuery 中有下表:

A = user1 | 0 0 |
    user2 | 0 3 |
    user3 | 4 0 |

交叉连接后,你有

dist = |user1  user2  0 0 , 0 3 |  #comma is just showing user val seperation
       |user1  user3  0 0 , 4 0 |
       |user2  user3  0 3 , 4 0 |

如何在 BigQuery 中执行行聚合以跨行计算成对聚合。作为一个典型的用例,您可以计算两个用户之间的欧几里得距离。我想计算两个用户之间的以下指标:

sum(min(user1_row[i], user2_row[i]) / abs(user1_row[i] - user2_row[i]))

对每对用户的所有 i 求和。

例如,在 Python 中,您只需:

for i in np.arange(row_length/2)]):
dist.append([user1, user2, np.sum(min(r1[i], r2[i]) / abs(r1[i] - r2[i]))])

【问题讨论】:

    标签: sql google-bigquery aggregation data-analysis cross-join


    【解决方案1】:

    从丑陋的方式开始:您可以将数学展开到查询中。也就是转 for i in ... sum(min(...)/abs(...)) 进入对每个字段进行 SQL 操作。请注意,MINSUM 是您不想使用的聚合函数。而是将 + 用于 SUM,将 IF(a < b, a, b) 用于 MINABS(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
    

    【讨论】:

      猜你喜欢
      • 2016-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-04
      • 2018-09-16
      • 2015-03-01
      相关资源
      最近更新 更多