我有一个以下列方式构建的广播变量
// Function
def loadMovieNames(sparkContext: SparkContext): Map[Int, String] = {
// Handle character encoding issues:
implicit val codec = Codec("UTF-8")
codec.onMalformedInput(CodingErrorAction.REPLACE)
codec.onUnmappableCharacter(CodingErrorAction.REPLACE)
// Create a Map of Ints to Strings, and populate it from u.item.
var movieNames: Map[Int, String] = Map()
val lines = sparkContext.textFile("s3a://bucket/movies.dat")
for (line <- lines) {
var fields = line.split("::")
if (fields.length > 1) {
movieNames += (fields(0).toInt -> fields(1))
}
}
return movieNames
}
// Main
val nameDict = loadMovieNames(spark.sparkContext)
val broadcastNames = spark.sparkContext.broadcast(nameDict)
以下是用于访问广播变量的主要代码。
val resultDF = recommendationsDF.sort($"score".desc).limit(30)
val check = (id1: Int, id2: Int) => if (id1 == movie) broadcastNames.value(id2) else broadcastNames.value(id1)
val getName = udf(check)
val results = resultDF.withColumn("movie", getName($"movieId1", $"movieId2"))
results.show(30)
但是当我稍后在main中尝试在广播变量中进行查找时,我得到以下异常。
Caused by: java.util.NoSuchElementException: key not found: 1196
at scala.collection.MapLike$class.default(MapLike.scala:228)
at scala.collection.AbstractMap.default(Map.scala:59)
at scala.collection.MapLike$class.apply(MapLike.scala:141)
at scala.collection.AbstractMap.apply(Map.scala:59)
at com.spark.movierec.MovieRecDF$$anonfun$5.apply(MovieRecDF.scala:144)
at com.spark.movierec.MovieRecDF$$anonfun$5.apply(MovieRecDF.scala:143)
当我最初遇到同样的问题时,我将Map转换为广播变量。在阅读了这个问题here的答案之后,我意识到这可能是关闭问题。但我仍然不确定如何解决这个问题。
答案 0 :(得分:3)
创建本地地图的一种方法是使用collectAsMap
:
val nameDict = sparkContext.broadcast(sparkContext
.textFile(path)
.map(_.split("::"))
.filter(_.size > 1)
.map(arr => (arr(0).toInt, arr(1)))
.collectAsMap())
您还应该考虑使用DataFrames
和广播连接来代替UDF和广播变量,但是应用程序的逻辑并不是那么清楚。