用于两个数据集之间的n到m映射的高效算法

时间:2015-04-09 01:03:26

标签: java algorithm mapreduce combinatorics

我一边有三组动态元素。例如

a = [101,102,104] //possible values 101 to 115
b = [201,202] //possible values 201 to 210
c = [301,302,303,304] //possible values 301 to 305

我生成这3组的所有组合,例如

setA = ["101|201|301,303", "101,104|202|304", "101,104|202|301,304", ...]
此时

a,b,c不在图片中。现在我想将setA的所有元素与另一个setB匹配,setB只有每个类别中的一个元素。 e.g。

setB = ["101|202|304","104|202|301" ,"102|202|303", ...] 

setAsetB之间存在n到m的映射。即setA的一个组合可以在setB中具有多个匹配,反之亦然。

匹配条件:对于setB的任何元素(例如" 101 | 202 | 304")如果它的所有部分(101,202,304)都包含在setA的某些组合中(例如" 101,104 | 202 | 304"," 101,104 | 202 | 301,304")然后认为它是一个匹配。所以在这个例子中" 101 | 202 | 304"据说与" 101,104 | 202 | 304"和" 101,104 | 202 | 301,304"

目前我有O(n ^ 2)时间和O(n)空间算法,但我真的在寻找一些改进,因为这个计算重复了许多这样的集合。 (它实际上是一个hadoop map-reduce的reducer任务,我生成维度的所有组合和符合给定组合的聚合度量)。任何框架级优化也是受欢迎的。例如打破多个工作岗位。

3 个答案:

答案 0 :(得分:1)

浏览B并挑选出你拥有的所有第一个元素,然后将它们变回一组。对于该集合的每个元素,从该元素到B中以该元素开头的所有元素进行映射。现在你有了一张地图:firstElement -> subsetOfBStartingWithThat

现在对子集和第二个元素等做同样的事情,直到你有一系列地图

firstElement -> secondElement -> thirdElement -> ... -> entry in B

现在,您将浏览A中的每个条目,并使用地图判断是否有任何内容。如果是,请将其添加到集合中。如果不是,请将其留空。使用它来构建从A元素到B元素集的映射。

然后通过迭代A - >制作从B到A的集合的映射来反转该过程。 B映射并以相反方向添加对。

您有O(m)个空间来创建B-lookup-map,并且您将花费O(m+n)时间进行扫描,因为设置查找是线性的。构建最终查找集将占用与m * n/2^k成比例的空间(和时间),其中k是单独集合的数量(在您的情况下为3)。没有办法避免这种情况:这实际上是有多少链接。 (要了解原因,请注意每个源集的每个元素都可以被视为打开或关闭的位,并且您需要将该位打开。这只发生在1/2^k时间,这是1/8在你的情况下。

所以你几乎坚持n^2步。除非你不需要全面,否则它是问题所固有的。如果没有,您可以使用我上面概述的方案来更便宜地找到 a 匹配。

答案 1 :(得分:0)

与Rex Kerr略有不同的解决方案。首先,我从setB元素创建了一个mapB。每个元素完全代表一个键,相关的值是我用例中的不同度量。 然后,我迭代了setA的每个子元素。从每个元素创建3个子列表,并以某种方式迭代每个子列表以获取密钥(3个嵌套用于循环)。我在mapB中查找了该键。如果找到,我将mapB值计入此组合。因此,在所有迭代结束时,我聚集了来自setB的值,这有资格获得setA的给定组合。就是这样。如果有人希望我对此更加详细,请告诉我。
ps - 这项变化(从7小时起2小时)我的工作速度提高了4倍

答案 2 :(得分:-1)

问题不明确,但如果我理解正确,我会这样解决:

  • setA对我来说不存在。
  • a,b和c也不合适。

我首先选择“setB”中的公共元素(在您的示例中为202),对于其余元素(101,102,104,201,301,302等),我会为每个元素迭代4个状态它们:

  • 0 =它不在setB
  • 1 =它位于setB
  • 的第一个“条目”中
  • 2 =它位于setB的第二个“条目”
  • 3 =它在setB
  • 的两个条目中

我假设setB总是有2个“条目”。