1

给定一张桌子

     name  ip 
A = |A     1  |
    |B     1  |
    |C     1  |
    |B     2  |
    |C     2  |
    |D     3  |
    |E     2  |

如果任何两个名称共享相同的 ip,则它们属于同一组。同名的ip也属于同一组。如果您找到 ip 1、{A,B,C} 的所有名称,那么您应该在同一组 {1,2} 中包含与 {A,B,C} 关联的所有 ip,然后再包含所有具有这些 ip 的名称尚未包含 {E} 等等。在此特定示例中,{A,B,C,E} x {1, 2} 中的任何内容都将位于同一组中。上表的结果将是

     name  ip  group
A = |A     1     1    |
    |B     1     1    |
    |C     1     1    |
    |B     2     1    |
    |C     2     1    |
    |D     3     2    |
    |E     2     1    |

只是要清楚:

如果名称 A、B 和 C 都是 ip 1 则它们被组合在一起,你应该有

A, 1 = group1
B, 1 = group1
C, 1 = group1

如果名称 A、B 也共享 ip 2,那么他们不应该创建一个新组,而是应该在同一个组中,如下所示:

A, 1 = group1
B, 1 = group1
C, 1 = group1
A, 2 = group1
B, 2 = group1

目标是在 Google BigQuery SQL 中解决这个问题。

到目前为止我有

select ip, row_number() over () as group,
GROUP_CONCAT(name,',') as names,
from A
group by ip

这会产生一个 ip 的所有名称并给出一个组,但没有找到一个名称的所有 ip 或找到包含所有名称和 ip 的所有对的组。

请注意,您可以使用 split 来访问连接的名称(在这种情况下使用 ',')。

更新 - 这称为传递闭包。如果这太难了,那么展示如何只进行传递闭包的第一次迭代(如何找到与每个 ip 关联的所有名称相关联的所有 ip)并将它们标记为组就足够了。

4

1 回答 1

2

这是我第一次迭代的解决方案。它有点长,可能会改进,但这就是我所拥有的。

步骤1。

select name, nest(ip) ips, group_concat(string(ip)) sip from 
(select 'a' name, 1 ip),
(select 'b' name, 1 ip),
(select 'c' name, 1 ip),
(select 'b' name, 2 ip),
(select 'c' name, 2 ip),
(select 'd' name, 3 ip),
(select 'e' name, 2 ip)
group by name

将结果存储在临时表 x 中

第2步。

select a.name name, group_concat(b.name) as cluster from (
select a.name, b.name from (
select a.*, b.* from dataset.x a cross join dataset.x b
) omit record if every(not b.sip contains string(a.ips))
group by 1, 2 order by 1, 2) group by 1

将结果存储在临时表 y 中

步骤 3。

select cluster from (
select group_concat(part) cluster from (
select name, part from (
select a.name name, split(b.cluster) part 
from dataset.y a cross join dataset.y b
where b.cluster contains a.name) group by 1, 2 order by 1, 2) 
group by name) group by cluster

这应该产生所有独特的集群,即

a,b,c,e
d
于 2015-04-23T20:45:27.973 回答