如下面的示例所示,我希望按键累积值。
我可以使用List
,ArrayBuffer
,Array
,mutable.HashSet
等。
当每个密钥的值的数量变化很大且未知数量,即宽(例如10k-1M)时,哪种数据结构最有效?
当然,在Java中,由于内存动态扩展,我避免使用List
或Vector
。在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)) }
答案 0 :(得分:1)
好吧,如果你积累它们以便快速访问,那么当然你需要提供O(1)查找的东西(例如HashMap
)。从您的示例中我可以看到您希望在稍后阶段按键减少,这意味着您无论如何都需要遍历它。
如果您只需要附加到集合的头部,则列表是可以的。在这种情况下,请制作ListBuffer
,逐步填写,然后在完成添加后调用.toList()
。这样可以节省一些记忆。
如果您不是仅仅追加头,请选择Vector
。由于树的表示形式,它实际上是恒定的时间(参见here),如果性能有问题,通常建议使用列表。
Here可能有所帮助的效果概述。
答案 1 :(得分:1)
你似乎正在使用spark,所以我假设你想以某种方式在集群上计算这些东西?在进行分布式计算时,最重要的问题是如何分配以及群集节点之间需要多少通信。
最快的方法可能是将每个密钥映射到一个集群节点,然后将结果按顺序汇总到一个列表中。通过查看API,您可以使用分区程序实现到群集节点的映射,并使用aggregateByKey实现聚合。 AggregateByKey允许您指定一个函数,该函数以线性顺序应用于分区上的数据,因此您可以将所有值有效地聚合到列表中。您还必须指定关联聚合函数,但它的效率无关紧要,因为它永远不会被调用。
如果你坚持使用你拥有的东西,而不知道能否假设调用reduce函数的顺序,那么普通数组实际上可能是最好的数据结构。如果您在前面添加元素,列表可能会更快,但您无法确保这一点。另一方面,向量具有有效恒定的时间来附加和前置元素,但是相似大小的两个向量的合并无论如何都应该是线性的,并且与向量有关的常数更大。如果您现在正在执行的操作存在效率问题,我会尝试将聚合与最佳数据分区结合使用。