val d = sc.makeRDD(Array(1,2,3,4,5,1,3,5))
val dd = d.map(x=>(x,1)) //构造pair RDD, dd:RDD[(Int,Int)]
val dg = dd.groupByKey() //dg :RDD[(Int, Iterable[Int])]
val dgc = dg.collectAsMap //dgc:Map[Int, Iterable[Int]]
val dgci = dgc.foreach(println(_))
//output
(2,CompactBuffer(1))
(5,CompactBuffer(1, 1))
(4,CompactBuffer(1))
(1,CompactBuffer(1, 1))
(3,CompactBuffer(1, 1))
val dk = dd.countByKey() //dk: Map[Int, Long]
dk.foreach(println(_))
(5,2) //key为5出现了2次
(1,2) //key为1出现了2次
(2,1) //key为2出现了1次
(3,2) //key为3出现了2次
val dv = dd.countByValue() // dv: Map[(Int, Int),Long]
dv.foreach(println(_))
//output
((5,1),2)
((3,1),2)
((4,1),1)
((1,1),2)
((2,1),1)
spark aggregateByKey
aggregateByKey
该函数和aggregate
类似,但操作的RDD是Pair类型的。
aggregateByKey
函数对PairRDD中相同Key的值进行聚合操作,在聚合过程中同样使用了一个中立的初始值。和aggregate函数类似,aggregateByKey返回值的类型不需要和RDD中value的类型一致。因为aggregateByKey是对相同Key中的值进行聚合操作,所以aggregateByKey函数最终返回的类型还是Pair RDD,对应的结果是Key和聚合好的值;而aggregate
函数直接是返回非RDD的结果,这点需要注意。在实现过程中,定义了三个aggregateByKey
函数原型,但最终调用的aggregateByKey
函数都一致。
var data = sc.parallelize(List((1,3),(1,2),(1, 4),(2,3)))
def seq(a:Int, b:Int) : Int ={
println("seq: " + a + "\t " + b)
math.max(a,b)
}
// seq: (a: Int, b: Int)Int
def comb(a:Int, b:Int) : Int ={
println("comb: " + a + "\t " + b)
a + b
}
// comb: (a: Int, b: Int)Int
data.aggregateByKey(1)(seq, comb).collect
//output
seq: 1 3
seq: 1 2
seq: 1 4
seq: 1 3
comb: 3 2
comb: 5 4
res62: Array[(Int, Int)] = Array((1,9), (2,3))
如果不另外写函数:
var d = sc.parallelize(List((1,3),(1,2),(1, 4),(2,3)))
d.aggregateByKey(1)(
(a,b)=>{
println("seq:"+a+"\t"+b);math.max(a,b)
}
,
(a,b)=>{
println("combine:"+a+"\t"+b);
a+b
}
).collect().foreach(println(_))
//output
seq: 1 3
seq: 1 2
seq: 1 4
seq: 1 3
comb: 3 2
comb: 5 4
Array[(Int, Int)] = Array((1,9), (2,3))
//Exercise 3
val rdd = sc.parallelize(List(
(("a"), 1.0),
(("a"), 3.0),
(("a"), 2.0)
))
val rdda = rdd.aggregateByKey("b")(
{case (aggr , value) =>
aggr + String.valueOf(value)},
(aggr1, aggr2) => aggr1 +"c"+ aggr2)
rdda.collect().foreach(println(_))
//output
(a,b1.0cb3.0cb2.0)
(b,b4.0)
2016.01.06更新:
aggregateByKey还是不太懂,以下的例子可以加深理解:
aggregateByKey是先用一个初始值对pariRDD的value进行处理,得到新的value,再进行combine
val rdd = sc.parallelize(List(
(("a"), 1.0),
(("a"), 3.0),
(("a"), 2.0)
))
val rdda = rdd.aggregateByKey("b")(
{case (aggr , value) =>
println(aggr + String.valueOf(value))
aggr + String.valueOf(value)},
(aggr1, aggr2) =>{
println(aggr1 +" c "+ aggr2)
aggr1 +" c "+ aggr2
}
)
rdda.collect().foreach(println(_))
//这里的初始值是"b",所以第一个函数中的aggr是b,value是pairRDD中的value
将b与value相加组成新的value,此时的pairRDD为:
RDD[("a","b1.0"),("a","b2.0"),("a","b3.0")]
然后进行第二个combine函数:
根据key,对aggr1和aggr2通过combine函数进行合并:aggr1+" c "+aggr2
所以,先是(b1.0,b2.0)=>b1.0 c b2.0
然后(b1.0 c b2.0,b3.0)=>b1.0 c b2.0 c b3.0
b2.0
b1.0
b3.0
b1.0 c b3.0
b1.0 c b3.0 c b2.0
(a,b1.0 c b3.0 c b2.0)
val rdd = sc.parallelize(List(
(("a"), 1.0),
(("a"), 3.0),
(("a"), 2.0),
(("b"),4.0)
))
val reduceByKey = rdd.reduceByKey((a , b) => a+b)
//reduceByKey:RDD[(String,Double)]
reduceByKey.collect().foreach(println(_))