Scala中用于聚合的高效数据结构

时间:2016-02-11 17:36:55

标签: scala types aggregation

如下面的示例所示,我希望按键累积值。 我可以使用ListArrayBufferArraymutable.HashSet等。 当每个密钥的值的数量变化很大且未知数量,即宽(例如10k-1M)时,哪种数据结构最有效?

当然,在Java中,由于内存动态扩展,我避免使用ListVector。在Scala中,性能和/或内存方面的最佳实践是什么?

感谢。

val res = data.flatMap{ x =>
          if ( some condition )
            Some(( x._2._2, ArrayBuffer[(Int, Double)]( x._1,, x._2._1)) ) )
          } else {
            None
          }
        }
        .reduceByKey {(x, y) => x ++ y}

更新: 随后的转换如下所示。我创建了特征矩阵(使用稀疏向量)作为数据准备。

.map(x => (x._1, x._2.toArray.sortBy(_._1 )) )
.map { x => (yieldMap.value.get(x._1).get  , x._2.map(_._1), x._2.map(_._2)) }

2 个答案:

答案 0 :(得分:1)

好吧,如果你积累它们以便快速访问,那么当然你需要提供O(1)查找的东西(例如HashMap)。从您的示例中我可以看到您希望在稍后阶段按键减少,这意味着您无论如何都需要遍历它。

如果您只需要附加到集合的头部,则列表是可以的。在这种情况下,请制作ListBuffer,逐步填写,然后在完成添加后调用.toList()。这样可以节省一些记忆。

如果您不是仅仅追加头,请选择Vector。由于树的表示形式,它实际上是恒定的时间(参见here),如果性能有问题,通常建议使用列表。

Here可能有所帮助的效果概述。

答案 1 :(得分:1)

你似乎正在使用spark,所以我假设你想以某种方式在集群上计算这些东西?在进行分布式计算时,最重要的问题是如何分配以及群集节点之间需要多少通信。

最快的方法可能是将每个密钥映射到一个集群节点,然后将结果按顺序汇总到一个列表中。通过查看API,您可以使用分区程序实现到群集节点的映射,并使用aggregateByKey实现聚合。 AggregateByKey允许您指定一个函数,该函数以线性顺序应用于分区上的数据,因此您可以将所有值有效地聚合到列表中。您还必须指定关联聚合函数,但它的效率无关紧要,因为它永远不会被调用。

如果你坚持使用你拥有的东西,而不知道能否假设调用reduce函数的顺序,那么普通数组实际上可能是最好的数据结构。如果您在前面添加元素,列表可能会更快,但您无法确保这一点。另一方面,向量具有有效恒定的时间来附加和前置元素,但是相似大小的两个向量的合并无论如何都应该是线性的,并且与向量有关的常数更大。如果您现在正在执行的操作存在效率问题,我会尝试将聚合与最佳数据分区结合使用。