Java 检查RDD的相等性

Java 检查RDD的相等性,java,junit,equals,apache-spark,Java,Junit,Equals,Apache Spark,我在JUnit中进行了一些测试,需要检查两个Spark RDD的相等性 我想到的一种方法是: JavaRDD<SomeClass> expResult = ...; JavaRDD<SomeClass> result = ...; assertEquals(expResult.collect(), result.collect()); javarddexpresult=。。。; JavaRDD结果=。。。; assertEquals(expResult.collect

我在JUnit中进行了一些测试,需要检查两个Spark RDD的相等性

我想到的一种方法是:

JavaRDD<SomeClass> expResult = ...;
JavaRDD<SomeClass> result = ...;

assertEquals(expResult.collect(), result.collect());
javarddexpresult=。。。;
JavaRDD结果=。。。;
assertEquals(expResult.collect(),result.collect());

有比这更好的方法吗?

如果预期结果相当小,最好
收集
RDD数据并在本地进行比较(就像您编写的那样)

当需要在测试中使用足够大的数据集时,几乎没有其他可能性:

免责声明:我对Spark Java API不够熟悉,因此我将用Scala编写进一步的示例代码。我希望这不会是一个问题,因为它可以用Java重写,或者转换成几个从Java代码调用的实用函数

方法1:将RDD压缩在一起并逐项比较 只有在RDD中元素的顺序定义良好(即RDD已排序)的情况下,此方法才可用

diff
阵列将包含多达100个微分对。如果RDD足够大,并且您希望从
diff
本地获取所有项目,那么可以使用
ToLocalWriter
方法。最好不要使用
collect
方法,因为您可能会运行OOM

这种方法可能是最快的,因为它不需要洗牌,但只有在RDD中的分区顺序和分区中的项目顺序定义良好的情况下,才可以使用这种方法

方法2:联合组RDD 此方法可用于测试
结果
RDD是否包含指定的(可能是非唯一的)值,而没有任何特定顺序

  val diff = expResult.map(_ -> 1)
    .cogroup(result.map(_ -> 1))
    .collect { case (a, (i1, i2)) if i1.sum != i2.sum => a -> (i1.sum - i2.sum) }
    .take(100)
diff
数组将包含差异值以及金额之间的差异

例如:

  • 如果
    expResult
    包含某个值的单个实例,而
    result
    不包含该值,则数字将为
    +1
  • 如果
    result
    包含另一个值的3个实例,并且
    expResult
    仅为1,则该数字将为
    -2

此方法将比其他选项(即相互减去RDD)更快,因为它只需要一次洗牌。

在我的例子中,使用Spark转换为Java时,仅使用collect方法不起作用。assertEquals的结果总是错误的

所以这个测试:

assertEquals( 
  this.fooExpectedRddTest.collect(),
  this.fooServiceTest.getRdd().collect()
);
生成此结果:

FooServiceTest.getRdd:143 expected: 

scala.collection.convert.Wrappers$SeqWrapper<[
    {"a":1,"b":2,"c":1496405614}, 
    {"a":1,"b":3,"c":1496243614}, 
    {"a":2,"b":2,"c":1496416414}
]> 

but was: 

scala.collection.convert.Wrappers$SeqWrapper<[
    {"a":1,"b":2,"c":1496405614}, 
    {"a":1,"b":3,"c":1496243614}, 
    {"a":2,"b":2,"c":1496416414}
]>
FooServiceTest.getRdd:143预期值:
scala.collection.convert.Wrappers$SeqWrapper
但是:
scala.collection.convert.Wrappers$SeqWrapper
我处理这个问题的方法是把它们转换成更容易比较的东西

List<Tuple3<Integer,Integer,Double>> expectedList = this.fooExpectedRddTest.map(
        (Foo foo) -> {
            return new Tuple3<Integer,Integer,Double>(
                    foo.getA(),
                    foo.getB(),
                    foo.getC()
            );
        }
).collect();

List<Tuple3<Integer,Integer,Double>> receivedList = this.fooServiceTest.getRdd().map(
        (Foo foo) -> {
            return new Tuple3<Integer,Integer,Double>(
                    foo.getA(),
                    foo.getB(),
                    foo.getC()
            );
        }
).collect();

assertEquals(
    expectedList,
    receivedList
);
List expectedList=this.fooExpectedRDTest.map(
(福福)->{
返回新的Tuple3(
foo.getA(),
foo.getB(),
foo.getC()
);
}
).收集();
List receivedList=this.fooServiceTest.getRdd().map(
(福福)->{
返回新的Tuple3(
foo.getA(),
foo.getB(),
foo.getC()
);
}
).收集();
资产质量(
预期名单,
接收列表
);

我想现在我将继续使用
collect()
方法,因为我的数据非常小(尽管是
result.collect().removeAll(expResult.collect())
的形式,然后断言
result
为空,因为我发现这是检查两个列表是否相等的更好方法)。知道我未来的选择是非常好的,尽管我会退回更大的收藏品。
List<Tuple3<Integer,Integer,Double>> expectedList = this.fooExpectedRddTest.map(
        (Foo foo) -> {
            return new Tuple3<Integer,Integer,Double>(
                    foo.getA(),
                    foo.getB(),
                    foo.getC()
            );
        }
).collect();

List<Tuple3<Integer,Integer,Double>> receivedList = this.fooServiceTest.getRdd().map(
        (Foo foo) -> {
            return new Tuple3<Integer,Integer,Double>(
                    foo.getA(),
                    foo.getB(),
                    foo.getC()
            );
        }
).collect();

assertEquals(
    expectedList,
    receivedList
);