如何解决Scala Spark在数据帧和数据集中以不同方式处理Double.NaN
在测试中,我试图将数据框/数据集转换为集合并进行比较。例如
actualResult.collect.toSet should be(expectedResult.collect.toSet)
我注意到一些有关Double.NaN
值的事实。
- 在Scala中,
Double.NaN == Double.NaN
返回false。 - 在火花
NaN == NaN
中为true。 (offical doc)
但是我无法弄清为什么数据框和数据集的行为不同。
import org.apache.spark.sql.SparkSession
object Main extends App {
val spark = SparkSession.builder().appName("Example").master("local").getOrCreate()
import spark.implicits._
val dataSet = spark.createDataset(Seq(Book("book 1",Double.NaN)))
// Compare Set(Book(book 1,NaN)) to itself
println(dataSet.collect.toSet == dataSet.collect.toSet) //false,why?
// Compare Set([book 1,NaN]) to itself
println(dataSet.toDF().collect.toSet == dataSet.toDF().collect.toSet) //true,why?
}
case class Book (title: String,price: Double)
这是我的问题。感谢任何见解。
- 它如何在代码中发生? (
equals
会被覆盖?等。) - 此设计背后的原因是什么?有没有更好的范式在测试中声明数据集/数据框?
解决方法
我想分享一些与此主题相关的观点。
- 执行
dataSet.collect.toSet
时,将其收集为 Set [Book] ,并在两组书籍对象之间进行比较。
使用个人(书本)对象均等方法进行比较,该方法是在书柜类中定义的。
这就是println(dataSet.collect.toSet == dataSet.collect.toSet)
由于Double.NaN == Double.NaN returns false
返回false的原因。
- 进行
dataSet.toDF().collect.toSet
操作时,您将其收集为设置[Row]
执行 toDF 时,spark会转换**(即序列化Book,然后反序列化为javaType字段 Row )**将Book类转换为 Row 在此过程中,它还会使用RowEncoders对字段进行一些转换。
使用以下RowEncoder.scala中的代码将所有Primitive字段转换为Java类型
def apply(schema: StructType): ExpressionEncoder[Row] = {
val cls = classOf[Row]
**val inputObject = BoundReference(0,ObjectType(cls),nullable = true)
val serializer = serializerFor(AssertNotNull(inputObject,Seq("top level row object")),schema)
val deserializer = deserializerFor(schema)**
new ExpressionEncoder[Row](
schema,flat = false,serializer.asInstanceOf[CreateNamedStruct].flatten,deserializer,ClassTag(cls))
}
如果您检查 Double.java和Float.java 方法的源代码是否相等。 NAN的比较将返回true。这就是为什么Row对象比较将返回true的原因。并且println(dataSet.toDF().collect.toSet == dataSet.toDF().collect.toSet)
是真的。
<li>If {@code d1} and {@code d2} both represent
* {@code Double.NaN},then the {@code equals} method
* returns {@code true},even though
* {@code Double.NaN==Double.NaN} has the value
* {@code false}.
* <li>If {@code d1} represents {@code +0.0} while
* {@code d2} represents {@code -0.0},or vice versa,* the {@code equal} test has the value {@code false},* even though {@code +0.0==-0.0} has the value {@code true}.
* </ul>
**对不起,如果我语法上错误。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。