我目前正在使用Apache Spark进行流式项目。我有2个数据源,第一个是从Kafka获得新闻数据。该数据总是每次都在更新。第二个,我得到masterWord字典。此变量包含单词的数据帧和单词的唯一关键字。
我想处理新闻数据,然后通过将数据与masterWord词典进行匹配,将其从单词Seq转换为words_id的Seq。但是,在我的UDF中访问masterWord数据框时遇到问题。当我尝试访问UDF中的数据框时,Spark返回此错误
由以下原因导致:org.apache.spark.SparkException:由于阶段失败而导致作业中止:阶段4.0中的任务0失败了1次,最近一次失败:丢失了任务0.0 i n阶段4.0(TID 4,本地主机,执行程序驱动程序):java.lang.NullPointerException
为什么不能在UDF中访问数据框?
从另一个数据框中获取价值的最佳实践是什么?
这是我的代码
// read data stream from Kafka
val kafka = spark.readStream
.format("kafka")
.option("kafka.bootstrap.servers", PropertiesLoader.kafkaBrokerUrl)
.option("subscribe", PropertiesLoader.kafkaTopic)
.option("startingOffsets", "earliest")
.option("maxOffsetsPerTrigger", "100")
.load()
// Transform data stream to Dataframe
val kafkaDF = kafka.selectExpr("CAST(value AS STRING)").as[(String)]
.select(from_json($"value", ColsArtifact.rawSchema).as("data"))
.select("data.*")
.withColumn("raw_text", concat(col("title"), lit(" "), col("text"))) // add column aggregate title and text
// read master word dictionary
val readConfig = ReadConfig(Map("uri" -> "mongodb://10.252.37.112/prayuga", "database" -> "prayuga", "collection" -> "master_word_2"))
var masterWord = MongoSpark.load(spark, readConfig)
// call UDF
val aggregateDF = kafkaDF.withColumn("text_aggregate", aggregateMongo(col("text_selected")))
// UDF
val aggregateMongo = udf((content: Seq[String]) => {
masterWord.show()
...
// code for query masterWord whether var content exist or not in masterWord dictionary
})
答案 0 :(得分:0)
数据帧位于spark上下文中,并且仅在驱动程序内部可用 每个任务都可以看到数据的一部分(分区),并且可以使用该部分。如果要使数据帧中的数据在udf内部可用,则必须将其序列化到主数据库,然后可以将其广播(或将其作为参数传递,本质上是一样的)到udf,在这种情况下,Spark会将整个内容发送到正在运行的udf的每个实例
答案 1 :(得分:0)
如果要在UDF中使用DataFrame,则必须创建Broadcast
:
import spark.implicits._
val df_name =Seq("Raphael").toDF("name")
val bc_df_name: Broadcast[DataFrame] = spark.sparkContext.broadcast(df_name)
// use df_name inside udf
val udf_doSomething = udf(() => bc_df_name.value.as[String].first())
Seq(1,2,3)
.toDF("i")
.withColumn("test",udf_doSomething())
.show()
给予
+---+-------+
| i| test|
+---+-------+
| 1|Raphael|
| 2|Raphael|
| 3|Raphael|
+---+-------+
这至少在local
模式下有效,请确保它是否也适用于群集。无论如何,我都不推荐这种方法,最好在驱动程序上的scala数据结构(例如,collect
)中转换(Map
)数据帧的内容并广播此变量,或者改用联接。 / p>