我是使用spark和scala的新手,但我必须解决以下问题: 我有一个包含行的ORC文件,我必须检查来自哈希映射的某个条件。
我以这种方式构建带有120,000个条目的哈希映射(文件名,时间戳)(getTimestamp返回Option[Long]
类型):
val tgzFilesRDD = sc.textFile("...")
val fileNameTimestampRDD = tgzFilesRDD.map(itr => {
(itr, getTimestamp(itr))
})
val fileNameTimestamp = fileNameTimestampRDD.collect.toMap
用这样的600万个条目检索RDD:
val sessionDataDF = sqlContext.read.orc("...")
case class SessionEvent(archiveName: String, eventTimestamp: Long)
val sessionEventsRDD = sessionDataDF.as[SessionEvent].rdd
并进行检查:
val sessionEventsToReport = sessionEventsRDD.filter(se => {
val timestampFromFile = fileNameTimestamp.getOrElse(se.archiveName, None)
se.eventTimestamp < timestampFromFile.getOrElse[Long](Long.MaxValue)
})
这是正确且高效的方式吗?是否建议使用缓存?
地图fileNameTimestamp
是否会被拖曳到处理过的地方的群集?
答案 0 :(得分:1)
fileNameTimestamp将针对每个任务进行序列化,并且对于120,000个条目,它可能非常昂贵。您应该广播大型对象并引用广播变量:
val fileNameTimestampBC = sc.broadcast(fileNameTimestampRDD.collect.toMap)
现在,只有其中一个对象将被发送给每个工作人员。也没有必要下拉到RDD API,因为Dataset API有一个过滤方法:
val sessionEvents = sessionDataDF.as[SessionEvent]
val sessionEventsToReport = sessionEvents.filter(se => {
val timestampFromFile = fileNameTimestampBC.value.getOrElse(se.archiveName, None)
se.eventTimestamp < timestampFromFile.getOrElse[Long](Long.MaxValue)
})
答案 1 :(得分:0)
您在fileNameTimestamp
地图上的collect
地图存在于Spark主节点上。为了在查询中有效地引用,工作节点需要有权访问它。这是由broadcasting完成的。
实质上,您重新发现了Broadcast Hash Join:您将使用tgzFilesRDD加入sessionEventsRDD以获取对可选时间戳的访问权限,然后相应地进行过滤。
使用RDD时,您需要显式编写加入策略的代码。 Dataframes / Datasets API有一个查询优化器,可以为您做出选择。您还可以明确要求API在幕后使用上述广播连接技术。您可以找到两种方法的示例here。
请告诉我这是否足够清楚:)