请注意:虽然这个问题提到了Spark(2.1)我认为这实际上是一个Scala(2.11)问题,任何精通Scala的开发者都能够回答它!
我有以下代码创建Spark Dataset(基本上是一个2D表)并逐行迭代它。如果特定行的username
列的值为“fizzbuzz”,那么我想设置一个在迭代器之外定义的变量,并在行迭代完成后使用该变量:
val myDataset = sqlContext
.read
.format("org.apache.spark.sql.cassandra")
.options(Map("table" -> "mytable", "keyspace" -> "mykeyspace"))
.load()
var foobar : String
myDataset.collect().foreach(rec =>
if(rec.getAs("username") == "fizzbuzz") {
foobar = rec.getAs("foobarval")
}
)
if(foobar == null) {
throw new Exception("The fizzbuzz user was not found.")
}
当我运行时,我得到以下异常:
error: class $iw needs to be abstract, since:
it has 2 unimplemented members.
/** As seen from class $iw, the missing signatures are as follows.
* For convenience, these are usable as stub implementations.
*/
def foobar=(x$1: String): Unit = ???
class $iw extends Serializable {
^
我得到这个的任何特殊原因?
答案 0 :(得分:3)
在方法或非抽象类中,您必须为每个变量定义一个值;在这里,您保留null
未定义。如果您将其定义为具有var foobar: String = null
的初始值:
foobar
但是:请注意您的代码都是非惯用代码(不遵循Scala和Spark的最佳做法)并且可能存在风险/缓慢:
collect
这样的可变值 - 不可变代码更易于推理,并且真正让您利用Scala的强大功能collect
,除非您确定它非常小,因为OutOfMemoryError
会收集来自工作节点的所有数据(其中有许多(可能)进入单个驱动程序节点,这将很慢并可能导致null
。NullPointerException
(因为它通常会导致意外的DataFrame.filter
)此代码的更惯用的版本将使用Option
来过滤相关记录,并可能import spark.implicits._
val foobar: Option[String] = myDataset
.filter($"username" === "fizzbuzz") // filter only relevant records
.take(1) // get first 1 record (if it exists) as an Array[Row]
.headOption // get the first item in the array, or None
.map(r => r.getAs[String]("foobarval")) // get the value of the column "foobarval", or None
if (foobar.isEmpty) {
throw new Exception("The fizzbuzz user was not found.")
}
来正确表示潜在的空值,例如:
$('label[for=Number_x0020__x0028_Or_x0020_Ran_e6c9be8f-bccc-474a-8b0a-e9a136acbca7_$RadioButtonChoiceFieldFillInRadio]')
.html('new label');
答案 1 :(得分:2)
foobar
变量:
var foobar: String = null
此外,这看起来并不正确:
foobar = rec.getAs("foobarval")
应该是:
foobar = rec.getAs[String]("foobarval")
总的来说,这不是一条路。它完全不受Spark执行模型的影响。我会过滤并改为:
myDataset.filter($"username" === "fizzbuzz").select("foobarval").take(1)
答案 2 :(得分:0)
您可能应该使用过滤器并选择数据框:
import spark.sqlContext.implicits._
val data = spark.sparkContext.parallelize(List(
"""{ "username": "none", "foobarval":"none" }""",
"""{ "username": "fizzbuzz", "foobarval":"expectedval" }"""))
val df = spark.read.json(data)
val foobar = df.filter($"username" === "fizzbuzz").select($"foobarval").collect.head.getString(0)