2015-04-10 3 views
2

Supposons que vous avez le tableau suivant BigQuery:Agrégation rang après Cross Joignez-vous à BigQuery

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

Après une jointure croisée, vous avez

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 | 

Comment pouvez-vous effectuer une agrégation de ligne dans BigQuery pour calculer agrégation par paires sur des lignes. Comme cas d'utilisation typique, vous pouvez calculer la distance euclidienne entre les deux utilisateurs. Je veux calculer la métrique suivante entre les deux utilisateurs:

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

sommé sur tous les i pour chaque paire d'utilisateurs.

Par exemple en Python vous suffit:

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

Répondre

5

Pour commencer par la façon laide: vous pouvez aplatir le calcul dans la requête. C'est-à-dire, tournez for i in ... sum(min(...)/abs(...)) en SQL fonctionnant sur chacun des champs. Notez que MIN et SUM sont des fonctions agrégées que vous ne voulez pas utiliser. Utilisez plutôt + pour SUM et IF(a < b, a, b) pour MIN. ABS(a, b) ressemble à IF(a < b, b-a, a-b). Si vous venez de calculer la distance euclidienne, vous pourriez faire

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) 

La plus belle façon est des fonctions définies par l'utilisateur, et de créer des vecteurs comme des valeurs répétées. Vous pouvez ensuite écrire une fonction DISTANCE() qui effectue votre calcul sur les deux tableaux à gauche et à droite de la jointure croisée. Si vous ne participez pas au programme bêta UDF et que vous souhaitez vous joindre à nous, veuillez contacter l'assistance google cloud.

Enfin, si vous changez votre schéma {user:string, field1:float, field2:float, field3:float,...}-{user:string, fields:[field:float]}

Vous pouvez ensuite aplatir le champ avec la position et faire la jointure croisée sur ce point. Comme dans:

SELECT 
    user, 
    field, 
    index, 
FROM (FLATTEN((
    SELECT 
    user, 
    fields.field as field, 
    POSITION(fields.field) as index, 
    from [dataset1.table1] 
), fields)) 

Si vous enregistrez cela comme une vue, appelez « dataset1.flat_view »

Ensuite, vous pouvez faire votre rejoindre:

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 

Cela vous donnera une ligne chaque pour chaque paire d'utilisateurs et chaque champ correspondant. Vous pouvez l'enregistrer en tant que vue "dataset1.joined_view".

Enfin, vous pouvez faire vos agrégations:

Puisque vous voulez ceci:

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

il ressemblerait à ceci:

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