下面是元组列表的数据结构,ot类型List [(String,String,Int)]
val data3 = (List( ("id1" , "a", 1), ("id1" , "a", 1), ("id1" , "a", 1) , ("id2" , "a", 1)) )
//> data3 : List[(String, String, Int)] = List((id1,a,1), (id1,a,1), (id1,a,1),
//| (id2,a,1))
我试图计算与每个id相关联的每个Int值的出现次数。因此,上述数据结构应转换为List((id1,a,3) , (id2,a,1))
这是我想出的,但我不确定如何在元组中对类似的项目进行分组:
data3.map( { case (id,name,num) => (id , name , num + 1)})
//> res0: List[(String, String, Int)] = List((id1,a,2), (id1,a,2), (id1,a,2), (i
//| d2,a,2))
在实践中,data3属于spark obj RDD类型,我在此示例中使用List进行测试,但同一解决方案应与RDD兼容。我使用List进行本地测试。
更新:根据maasg提供的以下代码:
val byKey = rdd.map({case (id1,id2,v) => (id1,id2)->v})
val byKeyGrouped = byKey.groupByKey
val result = byKeyGrouped.map{case ((id1,id2),values) => (id1,id2,values.sum)}
我需要稍微修改才能进入我期望的格式为
的格式.RDD[(String, Seq[(String, Int)])]
which corresponds to .RDD[(id, Seq[(name, count-of-names)])]
:
val byKey = rdd.map({case (id1,id2,v) => (id1,id2)->v})
val byKeyGrouped = byKey.groupByKey
val result = byKeyGrouped.map{case ((id1,id2),values) => ((id1),(id2,values.sum))}
val counted = result.groupedByKey
答案 0 :(得分:3)
在Spark中,您可以这样做:(使用Spark Shell来说明)
val l = List( ("id1" , "a", 1), ("id1" , "a", 1), ("id1" , "a", 1) , ("id2" , "a", 1))
val rdd = sc.parallelize(l)
val grouped = rdd.groupBy{case (id1,id2,v) => (id1,id2)}
val result = grouped.map{case ((id1,id2),values) => (id1,id2,value.foldLeft(0){case (cumm, tuple) => cumm + tuple._3})}
另一种选择是将rdd映射到PairRDD
并使用groupByKey
:
val byKey = rdd.map({case (id1,id2,v) => (id1,id2)->v})
val byKeyGrouped = byKey.groupByKey
val result = byKeyGrouped.map{case ((id1,id2),values) => (id1,id2,values.sum)}
选项2在处理大型集时是一个稍好的选项,因为它不会复制累积值中的id。
答案 1 :(得分:3)
当我使用scala-ide时,这似乎有效:
data3
.groupBy(tupl => (tupl._1, tupl._2))
.mapValues(v =>(v.head._1,v.head._2, v.map(_._3).sum))
.values.toList
结果与问题所要求的相同
res0:List [(String,String,Int)] = List((id1,a,3),(id2,a,1))
答案 2 :(得分:1)
您应该查看List.groupBy
。
您可以使用id作为键,然后使用地图中值的长度(即所有共享相同ID的项目)来了解计数。
答案 3 :(得分:1)
@vptheron有正确的想法。 可以在docs
中看到def groupBy [K](f:(A)⇒K):Map [K,List [A]]
根据某些鉴别器功能将此列表分区为列表映射。
注意:视图不会重新实现此方法。这意味着当应用于视图时,它将>始终强制视图并返回新列表。
K 鉴别器功能返回的键类型 f 鉴别器功能。
的返回强>
从键到列表的映射,使得以下不变量成立: (xs分区f)(k)= xs过滤器(x => f(x)== k) 也就是说,每个密钥k都绑定到那些元素x的列表,其中f(x)等于k。
因此,当与groupBy
一起使用时,类似下面的函数将为您提供一个键,其中键为ids。
(对不起,我无法访问Scala编译器,所以我无法测试)
def f(tupule: A) :String = {
return tupule._1
}
然后,您必须为List
中的每个id
迭代Map
,并总结整数出现次数。这很简单,但如果您仍然需要帮助,请在评论中提问。
答案 4 :(得分:0)
以下是最易读,最有效和可扩展的
data.map {
case (key1, key2, value) => ((key1, key2), value)
}
.reduceByKey(_ + _)
将提供RDD[(String, String, Int)]
。通过使用reduceByKey
,它意味着求和将是并列化的,即对于非常大的群组,它将被分发并且总和将在地图侧发生。考虑只有10个组但数十亿条记录的情况,使用.sum
将无法扩展,因为它只能分发到10个核心。
关于其他答案的更多说明:
此处不必使用head
:.mapValues(v =>(v.head._1,v.head._2, v.map(_._3).sum))
只能使用.mapValues(v =>(v_1, v._2, v.map(_._3).sum))
如果以上显示的foldLeft
显示.map(_._3).sum
val result = grouped.map{case ((id1,id2),values) => (id1,id2,value.foldLeft(0){case (cumm, tuple) => cumm + tuple._3})}
非常可怕