【发布时间】:2021-02-20 12:59:49
【问题描述】:
假设我们有 2 个集合(适合内存),其中包含可以测试相等性的元素(不一定覆盖 equals()),例如
Collection<Integer> c1 = List.of(1,2,3,4,5);
Collection<Integer> c2 = List.of(0,2,3,5,9);
还有一些非并行方法equiJoin(c1, c2),它为您提供两个列表中相等((2,2), (3,3), (5,5)) 的元素的Collection<Tuple<Integer, Integer>>。请参阅this 以了解其在 RDBMS 上下文中的处理。创建一对相等的整数是非常无用的,但是想想任何需要匹配记录列表的情况,比如一个来自 db 和一个来自 Web 服务调用,就像在this post 中一样。让我们假设,相等性归结为简单的类型,并且本身不会产生很多复杂性。
relational databases 区域的连接已被咬死,但在一般编程中并没有看起来那么严重。
我们经常看到的(如here)是嵌套循环方法,它的运行时间复杂度不是很好,O(M*N)。我只知道一个 framework 在 Java 流中包含 equiJoin,但它 looks like 它也执行嵌套循环(它实际上允许任意函数,而不仅仅是相等,这是嵌套循环的原因)。
List<Tuple<Integer, Integer>> joined = new ArrayList<>();
for (Integer i : c1) {
for (Integer j : c2) {
if (i.equals(j)) {
joined.add(new Tuple<>(i, j));
}
}
}
如果你想做得更好,你可以使用更好的散列连接 O(M+N):
List<Tuple<Integer, Integer>> joined = new ArrayList<>();
HashMap<Integer, Integer> C1 = new HashMap<>();
// imagine its not Integer but e.g. bank accounts and a Map<Key, Account>
c1.forEach(i -> C1.put(i, i));
for (Integer i : c2) {
Integer j = C1.get(i);
if (j != null) {
joined.add(new Tuple<>(i, j));
}
}
问题中是否有我没有看到的可用于改进的方面,或者是否存在可以做得更好的现有算法/实现?就像一些奇异的二进制编码或匹配时搜索空间的减少,诸如此类的事情。我能想到的一切都不是很有希望,或者可能会引入比它消除的更多的工作。也许甚至有共识或证据表明您不能比哈希联接做得更好,那么这也是一个答案。
【问题讨论】:
-
如果您询问理论,正如您所指出的,它已经在 DB 上下文中广泛完成,因此磁盘和内存操作的算法都非常完善(并且取决于在更大的体系结构上,例如数据的存储方式和索引方式)。对于实际应用,你可以看看 Kafka 是如何做到的,例如joins。
-
是的,在没有存储/io 负担的情况下看到的问题。 Kafka 不是流式应用程序吗?那是一个不同的问题。但仍然很好,也许我也会在 apache Spark 中挖掘。
-
您基于哈希的解决方案肯定假设您在
int上进行比较。两个相互比较的项目可能在任意字段上进行比较,它们本身执行任意复杂的比较。我认为在一般情况下,你不能做得比排序更好。那么问题就变成了 - 您可以利用的一般情况有哪些限制? -
对于任何比较排序,排序都必须包含 nlgn 复杂度。如果您可以分类排序,那么您将回到整数建议。
标签: java algorithm collections inner-join