这是我计算均方根误差的函数。但是,由于错误Type mismatch issue (expected: Double, actual: Unit)
,无法编译最后一行。我尝试了很多不同的方法来解决这个问题,但仍然没有成功。有什么想法吗?
def calculateRMSE(output: DStream[(Double, Double)]): Double = {
val summse = output.foreachRDD { rdd =>
rdd.map {
case pair: (Double, Double) =>
val err = math.abs(pair._1 - pair._2);
err*err
}.reduce(_ + _)
}
// math.sqrt(summse) HOW TO APPLY SQRT HERE?
}
答案 0 :(得分:2)
正如伊莱亚指出的那样,foreach
(和foreachRDD
)不会返回值;它们仅用于副作用。如果您想要返回某些内容,则需要map
。基于你的第二个解决方案:
val rmse = output.map(rdd => new RegressionMetrics(rdd).rootMeanSquaredError)
如果你为它做一点功能看起来更好:
val getRmse = (rdd: RDD) => new RegressionMetrics(rdd).rootMeanSquaredError
val rmse = output.map(getRmse)
忽略空的RDD,
val rmse = output.filter(_.nonEmpty).map(getRmse)
这是与for-comprehension完全相同的序列。它只是map,flatMap和filter的语法糖,但我认为在我第一次学习Scala时更容易理解:
val rmse = for {
rdd <- output
if (rdd.nonEmpty)
} yield new RegressionMetrics(rdd).rootMeanSquaredError
这是一个总结错误的函数,就像你的第一次尝试一样:
def calculateRmse(output: DStream[(Double, Double)]): Double = {
val getRmse = (rdd: RDD) => new RegressionMetrics(rdd).rootMeanSquaredError
output.filter(_.nonEmpty).map(getRmse).reduce(_+_)
}
编译器对nonEmpty
的抱怨实际上是DStream的filter
方法的问题。而不是在DStream中对RDD进行操作,filter
正在对DStream的类型参数给出的双精度(Double, Double)
对进行操作。
我不太了解Spark说它是缺陷,但这很奇怪。 Filter
和集合上的大多数其他操作通常是defined in terms of foreach,但DStream在不遵循相同约定的情况下实现这些函数;其弃用的方法foreach
和当前的foreachRDD
都在流的RDD上运行,但是its other higher-order methods don't。
所以我的方法不起作用。 DStream可能有一个很奇怪的原因(性能相关?)这可能是使用foreach
做错的方法:
def calculateRmse(ds: DStream[(Double, Double)]): Double = {
var totalError: Double = 0
def getRmse(rdd:RDD[(Double, Double)]): Double = new RegressionMetrics(rdd).rootMeanSquaredError
ds.foreachRDD((rdd:RDD[(Double, Double)]) => if (!rdd.isEmpty) totalError += getRmse(rdd))
totalError
}
但它有效!
答案 1 :(得分:0)
我成功完成了以下任务:
import org.apache.spark.mllib.evaluation.RegressionMetrics
output.foreachRDD { rdd =>
if (!rdd.isEmpty)
{
val metrics = new RegressionMetrics(rdd)
val rmse = metrics.rootMeanSquaredError
println("RMSE: " + rmse)
}
}