spark cross join消除重复

时间:2017-03-24 21:05:22

标签: scala apache-spark

我正在试图找出如何在给定两个数据集的情况下消除交叉连接中的重复。

例如客户端(clientDs)

clientDs = sc.parallelize(List('c1', 'c2', 'c3'))

clientMatrixDs = clientDs.join(clientDs)

clientProduct.show()

 -- output

 c1, c1
 c1, c2
 c1, c3
 c2, c1
 c2, c2
 c2, c3
 c3, c1
 c3, c2
 c3, c3

在这种情况下, (c1,c2)和(c2,c1)都是重复的,我需要重复它

我不知道该怎么做

在这里寻找一些想法。

2 个答案:

答案 0 :(得分:2)

在您的示例中,您有一堆Tuple2[String, String]个问题,问题是您希望Tuple2只有(a, b) == (b, a)所在的平等。这就是distinct不适合你的原因。因此,您必须提供自己的自定义相等。

问题是你不想覆盖Tuple2的{​​{1}}版本,因为这可能很危险,所以你可以在某个地方提供自定义等于:

equals

然后您可以在def customEquals(tuple1: (String, String), tuple2: (String, String)) = { tuple1 == tuple2 || (tuple1._1 == tuple2._2 && tuple1._2 == tuple2._1) } 中使用此功能来摆脱重复项的自定义定义:

filter

答案 1 :(得分:0)

RDD有一个方法distinct(),该方法可以作为等效文件使用,例如List。但是,我不知道它的表现。

修改

然而,自从(a, b) != (b, a)以来,这在scala中不起作用。所以你必须交换一些元素,以确保你没有得到任何双打。

如果您的类型有一些订购,您可以将所有配对映射到订购的等价物。例如,将(2, 1)映射到(1, 2),将(3, 4)映射到(3, 4)。然后,您可以使用distinct,这将删除所有重复项。

val distinctPairsRDD: RDD[(T, T)] = rdd.map{
  case (a, b) if a <= b => (a, b)
  case (a, b) => (b, a)
}.distinct()

如果您没有这样的排序,您可以用一些Set替换您的配对,这些配对是无序的。因此,您可以按照以下方式映射RDD

val distinctRDD: RDD[Set[T]] = rdd.map {
  case (a, b) => Set(a, b)
}.distinct()

然而,这将失去您的类型,因此您可能需要在此之后返回配对。要做到这一点,请记住Set本身没有重复项,因此如果您有一对具有相同元素的对,则它将被映射到只有一个元素的集合。

所以你必须做到以下几点:

val distinctPairs: RDD[(T, T)] = distinctRdd.collect {
  case Set(a) => (a, a)
  case Set(a, b) => (a, b)
}

collect可以替换为map,但如果稍后更改代码,可能会导致一些MatchError。这使得所有其他情况(如果碰巧有空集或具有多于两个元素的集合)被丢弃,因此请确保您在将来的更改(而不是RuntimeError或丢弃的元素)上更喜欢什么。

<强> TL; DR

尝试在你的对中订购元素,以获得单一性。如果这不起作用,请使用Set,但它会更复杂。