我有一个(非常大,想想10e7行)DataFrame,我从中根据某些属性过滤元素
val res = data.filter(data(FieldNames.myValue) === 2).select(pk.name, FieldName.myValue)
我的DataFrame有n个分区data.rdd.getNumPartitions
现在我想知道我的行来自哪个分区。我知道我可以用这样的东西遍历所有分区
val temp = res.first() //or foreach, this is just an example
data.foreachPartition(f => {
f.exists(row => row.get(0)==temp.get(0))
//my code here
}) //compare PKs
或data.rdd.mapPartitionsWithIndex((idx, f) => ...)
然而,如果我的结果和我的DataFrame变大,这似乎过分,也不是很有效。
在我执行过滤器() - 操作后,是否有Spark方式执行此操作?
或者,有没有办法重写/替换filter() - 语句,以便它返回行的原点?
我还可以在我的DataFrame中保存分区位置并在重新分区时更新它,但我宁愿以火花方式进行
(我发现的唯一类似问题是here,问题和评论都没有帮助。我还发现this可能相似但不一样)
提前感谢您的任何帮助/指示,如果我错过了一个类似于我的问题,我会道歉。
答案 0 :(得分:0)
分区数/计数不稳定,因为Spark将执行自动扩展&减少分区。这意味着输入分区计数可能与输入文件计数不同,例如。
这些情况下的一般模式是根据每个输入文件中的数据创建某种类型的复合键。如果密钥很大,您可以散列它以减小大小。如果您不太关心碰撞,请使用Murmur3
。如果您担心碰撞,请使用MD5
,这仍然非常快。
如果您拥有的唯一唯一功能是输入文件的路径,则必须将文件路径添加为区分列。这是一种方法:
val paths = Seq(...)
val df = paths
.map { path =>
sqlContext.read.parquet(path)
.withColumn("path", lit(path))
}
.reduceLeft(_ unionAll _)
这个想法很简单:一次读取一个输入文件,添加一个与之关联的唯一列,然后使用UNION ALL
将它们组合在一起。