我有一个样本文件,我试图使用combineByKey
来查找给定字段的另一个字段的总数,以及另一个字段的计数和值列表。我试图了解combineByKey
,这与我使用aggregateByKey
从this question所理解的要求相同,现在我想了解combineByKey
。
我尝试了以下与aggregateByKey
相同的代码,但出现类型不匹配错误。我不确定createCombiner
或mergeValue
或mergeCombiner
的类型是否正确。请帮助我更好地了解combineByKey
。
样本数据:
44,8602,37.19
44,8331,99.19
44,1919,39.54
44,2682,41.88
44,7366,66.54
44,3405,81.09
44,9957,94.79
combineByKey
的代码:
val rdd = sc.textFile("file:///../customer-orders.csv_sample").map(x => x.split(",")).map(x => (x(0).toInt, (x(1).toInt, x(2).toFloat)))
def createCombiner = (tuple: (Seq[Int],Double, Int)) => (tuple,1)
def mergeValue = (acc: (Seq[Int],Double,Int),xs: (Int,Float)) => {
println(s"""mergeValue: (${acc._1} ++ ${Seq(xs._1)}, ${acc._2} +${xs._2},${acc._3} + 1)""")
(acc._1 ++ Seq(xs._1), acc._2 + xs._2, acc._3 + 1)
}
def mergeCombiner = (acc1: (Seq[Int],Double,Int), acc2: (Seq[Int],Double,Int)) => {
println(s"""mergeCombiner: (${acc1._1} ++ ${acc2._1}, ${acc1._2} +${acc2._2}, ${acc1._3} + ${acc2._3})""")
(acc1._1 ++ acc2._1, acc1._2 + acc2._2, acc1._3 + acc2._3)
}
rdd.combineByKey(createCombiner,mergeValue,mergeCombiner).collect().foreach(println)
错误消息:
error: type mismatch;
found : ((Seq[Int], Double, Int)) => ((Seq[Int], Double, Int), Int)
required: ((Int, Float)) => ?
rdd.combineByKey(createCombiner,mergeValue,mergeCombiner).collect().foreach(println)
^
预期结果是:
customerid, (orderids,..,..,....), totalamount, number of orderids
使用提供的样本数据将是:
(44,(List(8602, 8331, 1919, 2682, 7366, 3405, 9957),460.2200012207031,7))
不匹配指向createCombiner
。有人可以帮助我了解combineByKey
吗?
答案 0 :(得分:0)
我对Spark不熟悉。
希望这对您有所帮助。
val array = Array((44,8602,37.19),(44,8331,99.19),(44,1919,39.54),(44,2682,41.88),(44,7366,66.54),(44,3405,81.09),(44,9957,94.79))
array.groupBy(_._1).map(e => (e._1, e._2.map(_._2).toList, e._2.map(_._3).sum))
//res1: scala.collection.immutable.Iterable[(Int, List[Int], Double)] = List((44,List(8602, 8331, 1919, 2682, 7366, 3405, 9957),460.21999999999997))
我看到您的此错误是由于
def createCombiner =(元组:(Seq [Int],Double,Int))=>(元组,1)
我认为createCombiner
应该取一些Seq
的元组,并返回Int
和Seq
(groupby)的元组
def createCombiner =(元组:Seq [(Int,Int,Double)])=> tuple.groupBy(_._ 1)
希望这会有所帮助。
答案 1 :(得分:0)
这是CombineByKey的签名:
combineByKey[C](createCombiner: (V) ⇒ C, mergeValue: (C, V) ⇒ C, mergeCombiners: (C, C) ⇒ C): RDD[(K, C)]
mergeValue的类型为(C, V) => C
其中C应该为((Seq[Int],Double, Int), Int)
,而V应该为(Seq[Int],Double, Int)
您的mergeValue方法的类型为C (Seq[Int],Double,Int)
和V (Int,Float)
mergeCombiner的类型也不正确。
这应该是(C, C) => C
,其中C是((Seq[Int],Double, Int), Int)
答案 2 :(得分:0)
这里的问题是createCombiner
函数。查看combineByKey
:
combineByKey[C](createCombiner: (V) ⇒ C, mergeValue: (C, V) ⇒ C, mergeCombiners: (C, C) ⇒ C): RDD[(K, C)]
简单地说,C
是您要以((Seq[Int], Double, Int)
)结尾的格式,而V
是您要以((Int, Double)
)开头的格式。在这里,我将Float
更改为Double
,因为这是Spark中常用的方法。这意味着createCombiner
函数应如下所示:
def createCombiner = (tuple: (Int, Double)) => (Seq(tuple._1), tuple._2, 1)
mergeValue
和mergeCombiner
看起来都不错,但是,如果在集群上执行代码,则在Spark中将看不到任何打印语句(请参见:Spark losing println() on stdout)。