首先,为标题道歉,我不确定如何雄辩地描述这一点。
我有一个spark作业,它将日志解析为JSON,然后使用spark-sql将特定列转换为ORC并写入各种路径。例如:
val logs = sc.textFile("s3://raw/logs")
val jsonRows = logs.mapPartitions(partition => {
partition.map(log => {
logToJson.parse(log)
}
}
jsonRows.foreach(r => {
val contentPath = "s3://content/events/"
val userPath = "s3://users/events/"
val contentDf = sqlSession.read.schema(contentSchema).json(r)
val userDf = sqlSession.read.schema(userSchema).json(r)
val userDfFiltered = userDf.select("*").where(userDf("type").isin("users")
// Save Data
val contentWriter = contentDf.write.mode("append").format("orc")
eventWriter.save(contentPath)
val userWriter = userDf.write.mode("append").format("orc")
userWriter.save(userPath)
当我写这篇文章时,我希望解析会发生一次,然后它会写入相应的位置。但是,似乎它正在执行文件中的所有代码两次 - 一次用于content
,一次用于users
。这是预期的吗?我希望我不会最终从S3传输数据并解析两次,因为这是最大的瓶颈。我附加了一个来自Spark UI的图像,以显示单个流窗口的任务重复。感谢您的任何帮助,您可以提供!
答案 0 :(得分:0)
好的,这种嵌套的DF是不行的。 Seq
旨在成为 big 数据集的数据结构,这些数据集不符合常规数据结构(例如List
或DataFrame
)并且需要以分布式方式处理。 不是只是另一种数组。你在这里尝试做的是创建一个DataFrames
每个日志行,这没什么意义。
根据您在此处发布的(不完整)代码,我想从您的原始输入(日志)中创建两个新的val logs = sc.textFile("s3://raw/logs")
val contentPath = "s3://content/events/"
val userPath = "s3://users/events/"
val jsonRows = logs
.mapPartitions(partition => {
partition.map(log => logToJson.parse(log))
}
.toDF()
.cache() // Or use persist() if dataset is larger than will fit in memory
jsonRows
.write
.format("orc")
.save(contentPath)
jsonRows
.filter(col("type").isin("users"))
.write
.format("orc")
.save(userPath)
,然后您希望将其存储在两个不同的位置。像这样:
var pippo = "pippo";
var arr = ['BUTTON','BADGE','CHECKBOX'];
if(arr.indexOf(pippo) > -1){
console.log("contained!");
}
else{
console.log("not contained!");
}
希望这有帮助。