我想编写自己的JavaPairRDD Key类并实现自己的连接逻辑。所以我需要重写密钥类的equals()和hashCode()方法,或者重写其他方法。 例如: 您知道JavaPairRDD.join(JavaPairRDD)非常简单,就在StringKey1.equals(StringKey2)匹配时。 但对我来说,我希望即使key1只是key2的子串也匹配。因此,我认为我必须编写一个包装类来告诉Spark,只要它们与我的逻辑匹配就应该将它们视为同一个键,并加入它们。例如,“ab”应与“abc”连接。
答案 0 :(得分:1)
您需要覆盖equals
和hashCode
。但是,您需要尝试显式转换other
对象,因为模式匹配不起作用。我仍在试图弄清楚为什么匹配单独失败(我猜测序列化)。还要记住,如果关键对象真的不匹配,那么在最终输出中会覆盖另一个...这可能不是你想要的。
case class Foo(x: String) {
override def equals(other: Any) = {
Option(other).map(_.asInstanceOf[Foo]).getOrElse(null)
match
{
case f : Foo =>
x contains(f.x)
case _ => false
}
}
override def hashCode() = 1
}
sc.parallelize(List((Foo("abcdefg"),1))).join(sc.parallelize(List((Foo("abcdef"),1)))).collect
答案 1 :(得分:1)
攻击equals
和hashCode
的语义以强制火花加入不相等的东西是一个坏主意。
Spark依赖于密钥的hashCode
来对集群上的数据进行分区。强制一个常量hashCode将强制数据转到单个分区,从而消除了在集群上分配计算的可能性。这意味着计算可以/应该在一个节点中完成,可能使用适当的单节点技术。
使用Spark可以解决此问题,采用不同的方法:
val data1 = List("abcd" -> 4, "defghy" -> 6 , "wxxyyy" -> 3, "az" -> 24)
val data2 = List("ab" -> 2, "fghz" -> 3 , "y" -> 1, "a" -> 2)
val base = sparkContext.parallelize(data1)
val jn = sparkContext.parallelize(data2)
val cartesian = base.cartesian(jn)
val joined = cartesian.collect{case ((k1,v1),(k2,v2)) if (k1.contains(k2)) => (k1,(v1,v2))}
joined.collect
这导致:
res6: Array[(String, (Int, Int))] = Array((abcd,(4,2)), (defghy,(6,1)), (wxxyyy,(3,1)), (az,(24,2)))