Algorithm 具有公共元素的集合合并的高效分布式算法

Algorithm 具有公共元素的集合合并的高效分布式算法,algorithm,scala,merge,distributed-computing,apache-flink,Algorithm,Scala,Merge,Distributed Computing,Apache Flink,我正在Flink上开发MinHash LSH的分布式实现,作为最后一步,我需要合并一些集群,这些集群被标识为它们之间相似的元素集 所以我有一个分布式集合作为输入,我需要一个算法来有效地将集合与公共元素合并。鉴于Flink的计算模型,该算法可能是迭代的,不一定像map-reduce那样 这里有一个例子: 从{1,2}、{2,3}、{3、{4,5}、{4{1,27}}开始,结果应该是{1,2,3,27}、{4,5},因为集合#1、#2和#4至少有一个共同元素 只是一个想法,也许有更好的方法,但是这个

我正在Flink上开发MinHash LSH的分布式实现,作为最后一步,我需要合并一些集群,这些集群被标识为它们之间相似的元素集

所以我有一个分布式集合作为输入,我需要一个算法来有效地将集合与公共元素合并。鉴于Flink的计算模型,该算法可能是迭代的,不一定像map-reduce那样

这里有一个例子:


{1,2}、{2,3}、{3、{4,5}、{4{1,27}}
开始,结果应该是
{1,2,3,27}、{4,5}
,因为集合#1、#2和#4至少有一个共同元素

只是一个想法,也许有更好的方法,但是这个怎么样:

  • 在映射步骤中,为每个集合中的每个元素发出一个键值对,如:
    element->other elements
  • 在reduce步骤中,收集这些其他元素并丢弃重复项
  • 重复此操作,直到数据结构停止更改
第一次迭代后,您的数据如下所示:

1 -> 2, 27
2 -> 1,3
3 -> 2
4 -> 5
5 -> 4
27 -> 1
第二次之后:

1 -> 2, 3, 27
2 -> 1, 3, 27
3 -> 1, 2
4 -> 5
5 -> 4
27 -> 1, 2
最后在第三次之后:

1 -> 2, 3, 27
2 -> 1, 3, 27
3 -> 1, 2, 27
4 -> 5
5 -> 4
27 -> 1, 2, 3
我目前还没有解决方案来确定更改何时停止


要仅获取每个结果的一个副本,您可以删除键大于任何其他元素的所有元素。

只是一个想法,可能有更好的方法,但如何:

  • 在映射步骤中,为每个集合中的每个元素发出一个键值对,如:
    element->other elements
  • 在reduce步骤中,收集这些其他元素并丢弃重复项
  • 重复此操作,直到数据结构停止更改
第一次迭代后,您的数据如下所示:

1 -> 2, 27
2 -> 1,3
3 -> 2
4 -> 5
5 -> 4
27 -> 1
第二次之后:

1 -> 2, 3, 27
2 -> 1, 3, 27
3 -> 1, 2
4 -> 5
5 -> 4
27 -> 1, 2
最后在第三次之后:

1 -> 2, 3, 27
2 -> 1, 3, 27
3 -> 1, 2, 27
4 -> 5
5 -> 4
27 -> 1, 2, 3
我目前还没有解决方案来确定更改何时停止


要仅获取每个结果的一个副本,您可以删除键大于任何其他元素的所有元素。

如果有
N
集合,每个集合大约有
M
个元素,如果复制很少,则最简单的方法是
O(N^2*M^2)
。如果你实际上只有
R如果你有
N
个集合,每个集合大约有
M
个元素,如果复制很少,那么最简单的方法(测试每个集合中的每个元素)是
O(N^2*M^2)
。如果你实际上只有
R,这里有一个想法:Gelly,Flink的一部分,有一个连接组件查找器。用每个集合元素的一个节点和以最简单的方式连接每个集合元素的边制作一个图,例如,对于{a,b,c,d,}添加[a,b],[a,c],[a,d],[a,…。现在找到连接的组件。它们的节点给出了您要查找的集合

编辑 如果您担心从集合到图形再到集合的转换对性能的影响(尽管这种担心是过早的优化;您应该尝试一下),那么在集合上重新实现Gelly的令牌推送方案就足够简单了。这是如何工作的。您的示例中已经有了令牌:集合编号。让我们[i]如示例中所示,设为集合i。例如,S[1]={1,2}。设R为逆多重映射,将每个集合元素带到它所属的集合集合。例如,在示例中,R[2]={1,2}。设T[i]为可通过传递的非空交集“链接”从集合i到达的元素。然后计算:

T[i] = S[i] for all i // with no links at all, a set reaches its own elements
loop
  for all i, Tnew[i] = \union_{ x \in T[i] } S[R[x]]  // add new reachables
  exit if Tnew == T
  T = Tnew
end loop

完成后,map T的不同值就是您想要的答案。最大迭代次数应该是log | U |,其中U是集合元素的宇宙。

这里有一个想法:Gelly是Flink的一部分,它有一个连接组件查找器。制作一个图形,每个集合元素有一个节点,边连接simp中每个集合的元素以尽可能避免的方式,例如为{a,b,c,d,}添加[a,b],[a,c],[a,d],[a,…。现在找到连接的组件。它们的节点给出了您要查找的集合

编辑 如果您担心从集合到图形再到集合的转换对性能的影响(尽管这种担心是过早的优化;您应该尝试一下),那么在集合上重新实现Gelly的令牌推送方案就足够简单了。这是如何工作的。您的示例中已经有了令牌:集合编号。让我们[i]如示例中所示,设为集合i。例如,S[1]={1,2}。设R为逆多重映射,将每个集合元素带到它所属的集合集合。例如,在示例中,R[2]={1,2}。设T[i]为可通过传递的非空交集“链接”从集合i到达的元素。然后计算:

T[i] = S[i] for all i // with no links at all, a set reaches its own elements
loop
  for all i, Tnew[i] = \union_{ x \in T[i] } S[R[x]]  // add new reachables
  exit if Tnew == T
  T = Tnew
end loop

完成后,map T的不同值就是您想要的答案。最大迭代次数应该是log | U |,其中U是集合元素的宇宙。

那么这是可传递的?即,如果A和B有一个公共元素,而B和C有一个不同的公共元素,那么您想要结果中的并集B并集C?我们的行为就好像它是可传递的,是吗他是可传递的?也就是说,如果A和B有一个公共元素,B和C有一个不同的公共元素,你想要一个联合体B联合体C在结果中?我们表现得好像它是可传递的,是的,他考虑过这一点,它可能会起作用,但Gelly还不成熟,但总的来说转换会太昂贵,我相信。我无论如何都会尝试,因为maybe它的性能足够好。@Chobeat很好,如果你正在寻找一种分布式算法,像Gelly做的事情可能是你能做的最好的事情。不成熟比从头开始要好。注意:我改变了连接图中集合元素的方式,以从Gelly的算法获得更好的性能。@Chobeat好的,我将Gelly a转换为如果你想尝试的话,我会回到你的问题中去。明天我会花一天的时间来尝试这里提出的建议,从你的开始。非常感谢。:)好的,我尝试了Gelly,我想我会按照你的建议来避免早期优化。谢谢。我