如何根据哈希映射过滤RDD?

时间:2017-04-02 11:54:16

标签: scala rdd orc

我是使用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是否会被拖曳到处理过的地方的群集?

2 个答案:

答案 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

请告诉我这是否足够清楚:)