我在scala中使用了spark,而且我的RDD中充满了tuple2,其中包含一个复杂的对象作为键和一个double。目标是在对象相同的情况下添加双精度(频率)。
为此我已将我的对象定义如下:
case class SimpleCoocurrence(word:String, word_pos:String, cooc:String, cooc_pos:String, distance:Double) extends Ordered[SimpleCoocurrence]{
def compare(that: SimpleCoocurrence) = {
if(this.word.equals(that.word)&&this.word_pos.equals(that.word_pos)
&&this.cooc.equals(that.cooc)&&this.cooc_pos.equals(that.cooc_pos))
0
else
this.toString.compareTo(that.toString)
}
}
现在我尝试使用reduceBykey:
val coocRDD = sc.parallelize(coocList)
println(coocRDD.count)
coocRDD.map(tup=>tup).reduceByKey(_+_)
println(coocRDD.count)
但是,结果显示处理reducebykey之前和之后的RDD包含完全相同数量的元素。
如何使用tuple2 [SimpleCoocurrence,Double]执行reduceByKey? 实现Ordered trait是告诉Spark如何比较我的对象的好方法吗? 我应该只使用tuple2 [String,Double]吗?
THX,
答案 0 :(得分:5)
reduceByKey
不使用排序,而是hashCode
和equals
来确定哪些键是相同的。特别是,hashPartitioner
将通过散列对密钥进行分组,使用相同hashCode的密钥落在同一分区上,以便在每个分区上进一步减少。
案例类的默认实现为equals
和hashCode
。可能使用的测试数据具有不同的字段distance:Double
值,使每个实例成为唯一对象。使用它作为键将导致只有相同的对象被缩减为一个。
解决这个问题的一种方法是为case class
定义一个键,并为对象定义一个加法方法,如下所示:
case class SimpleCoocurrence(word:String, word_pos:String, cooc:String, cooc_pos:String, distance:Double) extends Serializable {
val key = word + word_pos + cooc + cooc_pos
}
object SimpleCoocurrence {
val add: (SimpleCoocurrence, SimpleCoocurrence) => SimpleCoocurrence = ???
}
val coocList:List[SimpleCoocurrence] = ???
val coocRDD = sc.parallelize(coocList)
val coocByKey = coocRDD.keyBy(_.key)
val addedCooc = coocByKey.reduceByKey(SimpleCoocurrence.add)
(*)代码作为指导示例提供 - 未编译或测试。
答案 1 :(得分:0)
首先,我愚蠢......
接下来,如果有人遇到同样的问题,并希望使用复杂的scala对象作为Spark上的reduceByKey的键:
Spark知道如何比较两个对象,即使它们没有实现Ordered。所以上面的代码实际上是fonctionnal。
唯一的问题是......我之前和之后都在打印相同的RDD。当我写这篇文章时,它实际上运作良好。
val coocRDD = sc.parallelize(coocList)
println(coocRDD.count)
val newRDD = coocRDD.map(tup=>tup).reduceByKey(_+_)
println(newRDD.count)
答案 2 :(得分:0)
您没有存储reduceByKey的结果。试试这个:
val coocRDD = sc.parallelize(coocList)
println(coocRDD.count)
val result = coocRDD.map(tup=>tup).reduceByKey(_+_)
println(result.count)