我对spark和scala都比较新。 我试图在spark上使用scala实现协同过滤。 以下是代码
import org.apache.spark.mllib.recommendation.ALS
import org.apache.spark.mllib.recommendation.Rating
val data = sc.textFile("/user/amohammed/CB/input-cb.txt")
val distinctUsers = data.map(x => x.split(",")(0)).distinct().map(x => x.toInt)
val distinctKeywords = data.map(x => x.split(",")(1)).distinct().map(x => x.toInt)
val ratings = data.map(_.split(',') match {
case Array(user, item, rate) => Rating(user.toInt,item.toInt, rate.toDouble)
})
val model = ALS.train(ratings, 1, 20, 0.01)
val keywords = distinctKeywords collect
distinctUsers.map(x => {(x, keywords.map(y => model.predict(x,y)))}).collect()
抛出 scala.MatchError:null org.apache.spark.rdd.PairRDDFunctions.lookup(PairRDDFunctions.scala:571)在最后一行 如果我将distinctUsers rdd收集到一个数组中并执行相同的代码,那么Thw代码工作正常:
val users = distinctUsers collect
users.map(x => {(x, keywords.map(y => model.predict(x, y)))})
在处理RDD时,我在哪里弄错了?
Spark版本:1.0.0 Scala版本:2.10.4
答案 0 :(得分:1)
在堆栈跟踪中进一步回调,MatrixFactorizationModel来源的第43行说:
val userVector = new DoubleMatrix(userFeatures.lookup(user).head)
请注意userFeatures
的{{1}}字段本身就是另一个RDD;我相信当匿名功能块关闭model
时,它没有正确序列化,因此它上面的model
方法失败了。我也尝试将lookup
和model
放入广播变量中,但这也不起作用。
不要回到Scala集合并失去Spark的好处,最好坚持使用RDD并利用其他方法来转换它们。
我从这开始:
keywords
然后,我们不是逐个计算每个预测,而是可以获得所有可能的用户 - 关键字对的笛卡尔乘积作为RDD,并使用MatrixFactorizationModel中的另一个val ratings = data.map(_.split(',') match {
case Array(user, keyword, rate) => Rating(user.toInt, keyword.toInt, rate.toDouble)
})
// instead of parsing the original RDD's strings three separate times,
// you can map the "user" and "product" fields of the Rating case class
val distinctUsers = ratings.map(_.user).distinct()
val distinctKeywords = ratings.map(_.product).distinct()
val model = ALS.train(ratings, 1, 20, 0.01)
方法,该方法采用这样的对的RDD作为其论点。
predict
现在val userKeywords = distinctUsers.cartesian(distinctKeywords)
val predictions = model.predict(userKeywords).map { case Rating(user, keyword, rate) =>
(user, Map(keyword -> rate))
}.reduceByKey { _ ++ _ }
为每个用户提供了一个不可变的映射,可以查询特定关键字的预测评级。如果您在原始示例中特别需要数组,则可以执行以下操作:
predictions
警告:我使用Spark 1.0.1测试了这个,因为它是我安装的,但它也应该与1.0.0一起使用。