【发布时间】:2020-08-06 08:54:10
【问题描述】:
我想减少和限制在将集合中的所有项目组合相互比较时使用的内存占用,其中集合可以增长到任何大小。我正在考虑将集合分成更小的部分,但由于需要所有组合,我无法看到如何做到这一点,而最终在某个时候需要内存中的所有组合。
例如如果我有 A、B、C、D、E、F 项,我需要比较所有不同的组合
A B C D E F
A
B x
C x x
D x x x
E x x x x
F x x x x x
等等。这些集合通常包含 100 到 10,000 个文档,其中包含要使用各种启发式检查的元数据。
我目前正在实现它(无需一次将所有项目加载到内存中),方法是在两个相同的嵌套数据库查询中使用一个游标在两个相同的嵌套数据库查询中对集合进行两次迭代,以遍历组合的两个维度。从理论上讲,这在规模上是无限的,并且使用的内存很少,但感觉有点浪费,因为我将查询每个项目 N+1 次(其中 N 是集合的大小)。当然,它给数据库带来了一些压力。
这是当前的简单算法:
- 为集合准备查询
- 当 cursor.next A:
- 为集合准备查询,不包括 A
- 当 cursor.next B:
- 比较 A 和 B
这导致序列 AB、AC、AD、AE、AF、BA、BC、BD 等,而我一次只在内存中保存两个文档,但它有两个问题。首先,内部查询发生 N 次。如果我没有在查询中排除 A,那将是相同的查询重新运行 N 次,这似乎很浪费。第二个问题是排列,所以我需要做两倍的工作并且必须对结果进行重复数据删除。
我曾考虑在进展过程中缓存这些项目,但意识到它只会增长到最终包含所有项目以完成所有组合。因此,这导致了一个基本思想,即仅将整个集合选择一次到内存中并从一个数组中扫描组合。这很简单,但当然不可扩展。
那么,有没有一种算法可以在任何时候只使用集合的分区来比较集合中不同对的所有组合,从而保证总和覆盖所有组合?
我天真地想不出一个。例如如果你把它分成两半,你仍然需要在某个时候加载两个子集的组合。也许是“所有可能性”和“所有偶数”,但这只会使可扩展性问题减半。
B D F
B
D x
F x x
然后
A C E
A
C x
E x x
但这错过了一半的连击。
我感觉这在理论上是不可能的,但我想知道那里是否有一个聪明的数学技巧。或者我错过了一些非常明显的东西。
更新 - 在最初的 cmets 之后,问题已编辑并希望得到澄清。
Nikos.M 给了我预生成组合对的“索引”的想法,然后我可以查询每一对。
我最初希望实现 MicSim 所说的一些批量大小的中间地带的“最佳位置”。所以不是在一个极端原子加载每一对,也不是在另一端加载整个集合,而是一些固定大小的批处理方法来保持处理足迹平坦。
【问题讨论】:
-
有一种方法可以系统地生成n个对象的所有组合或子集,并且内存中只有一个组合处于活动状态。如果这解决了问题,请告诉我我发布算法
-
但是我需要澄清一下你所说的组合到底是什么意思?您发布的示例既不是组合(即从 n 中选择 k)也不是子集(n 项的所有子集),除非您错过了什么
-
我认为您正在尝试迭代所有无序的项目对,而不是一次将所有项目加载到内存中,并最大限度地减少项目的加载次数。这是对您问题的正确解释吗?
-
@NikosM。是的,我需要这些组合。我只是将子集作为可扩展性问题的一种可能解决方案放在那里,但对想法持开放态度。
-
@kaya3 是的,非常简洁。我希望我写的是那一句话,而不是我漫无边际的问题!
标签: javascript algorithm combinations scalability set-theory