我在Spark DataFrame上应用了许多转换(过滤器,groupBy,join)。我想在每次转换后在DataFrame中获得行数。
我目前正在使用每次转换后的功能count()来计算行数,但这每次都会触发未真正优化的操作。
我想知道是否有什么方法可以知道行数而不必触发原始作业之外的其他动作。
答案 0 :(得分:2)
每个操作员本身都有几个指标。这些指标在spark UI的“ SQL”标签中可见。
如果不使用SQL,我们可以在执行后重新检查数据帧的查询执行对象,以访问指标(内部累加器)。
示例:df.queryExecution.executedPlan.metrics
将给出DAG中最高节点的度量。
答案 1 :(得分:1)
您可以为每个阶段使用一个累加器,并在每个阶段之后在地图中递增该累加器。然后,在您执行操作后最后,您将对所有阶段都有一个计数。
val filterCounter = spark.sparkContext.longAccumulator("filter-counter")
val groupByCounter = spark.sparkContext.longAccumulator("group-counter")
val joinCounter = spark.sparkContext.longAccumulator("join-counter")
myDataFrame
.filter(col("x") === lit(3))
.map(x => {
filterCounter.add(1)
x
}) .groupBy(col("x"))
.agg(max("y"))
.map(x => {
groupByCounter.add(1)
x
})
.join(myOtherDataframe, col("x") === col("y"))
.map(x => {
joinCounter.add(1)
x
})
.count()
print(s"count for filter = ${filterCounter.value}")
print(s"count for group by = ${groupByCounter.value}")
print(s"count for join = ${joinCounter.value}")
答案 2 :(得分:0)
在Apache Spark上获得了更多经验以补充randal的答案后,回到这个问题。
您还可以使用UDF递增计数器。
val filterCounter = spark.sparkContext.longAccumulator("filter-counter")
val groupByCounter = spark.sparkContext.longAccumulator("group-counter")
val joinCounter = spark.sparkContext.longAccumulator("join-counter")
def countUdf(acc: LongAccumulator): UserDefinedFunction = udf { (x: Int) =>
acc.add(1)
x
}
myDataFrame
.filter(col("x") === lit(3))
.withColumn("x", countUdf(filterCounter)(col("x")))
.groupBy(col("x"))
.agg(max("y"))
.withColumn("x", countUdf(groupByCounter)(col("x")))
.join(myOtherDataframe, col("x") === col("y"))
.withColumn("x", countUdf(joinCounter)(col("x")))
.count()
print(s"count for filter = ${filterCounter.value}")
print(s"count for group by = ${groupByCounter.value}")
print(s"count for join = ${joinCounter.value}")
这应该更有效,因为spark只需要对UDF中使用的列进行反序列化,但是必须谨慎使用,因为催化剂可以更轻松地对操作进行重新排序(例如在调用udf之前推动过滤器)>