df.show()函数算法

先说结论:

show()和df里数据分区有关

假设:show(m),df 0号分区里数据量为n

  • 1.m <= n时,show取0号分区m条数据
  • 2.m > n时,show取0号分区n条数据,另外取1号分区m-n条数据(不够的话以此类推)

上代码验证:

1.8个分区

val df = Seq((5,5), (6,6), (7,7), (8,8), (1,1), (2,2), (3,3), (4,4)).toDF("col1", "col2")
// above sequence is defined out of order - to make behaviour visible

// see partition structure
df.rdd.glom().collect()
/* Array(Array([5,5]), Array([6,6]), Array([7,7]), Array([8,8]), Array([1,1]), Array([2,2]), Array([3,3]), Array([4,4])) */

df.show(4, false)
/*
+----+----+
|col1|col2|
+----+----+
|5   |5   |
|6   |6   |
|7   |7   |
|8   |8   |
+----+----+
only showing top 4 rows
*/

2.2个分区

// Now let's repartition df
val df2 = df.repartition(2)

// lets see the partition structure
df2.rdd.glom().collect()
/* Array(Array([5,5], [6,6], [7,7], [8,8], [1,1], [2,2], [3,3], [4,4]), Array()) */

// lets see output
df2.show(4,false)
/*
+----+----+
|col1|col2|
+----+----+
|5   |5   |
|6   |6   |
|7   |7   |
|8   |8   |
+----+----+
only showing top 4 rows
*/

3.3个分区

val df3 = df.repartition(3)

// lets see partition structures
df3.rdd.glom().collect()
/*
Array(Array([8,8], [1,1], [2,2]), Array([5,5], [6,6]), Array([7,7], [3,3], [4,4]))
*/

// And lets see the top 4 rows this time
df3.show(4, false)
/*
+----+----+
|col1|col2|
+----+----+
|8   |8   |
|1   |1   |
|2   |2   |
|5   |5   |
+----+----+
only showing top 4 rows
*/

源码:

在Spark 2+中,show()调用showString()将数据格式化为字符串,然后打印出来。showString()调用getRows()以字符串集合的形式获取dataset的顶行。getRows()调用take()来获取原始行,并将它们转换为字符串。take()只是简单地包装了head()head()调用limit()来构建并执行一个限制查询。limit()在逻辑计划的前面添加了一个Limit(n)节点,它实际上是一个GlobalLimit(n, LocalLimit(n))GlobalLimitLocalLimit都是OrderPreservingUnaryNode的子类,它们覆盖其maxRows (在GlobalLimit中)或maxRowsPerPartition (在LocalLimit中)方法。逻辑计划现在看起来像这样:

GlobalLimit n
+- LocalLimit n
   +- ...

这经过了Catalyst的分析和优化,其中如果树下的某些东西产生的行数少于限制,则会删除限制,并最终在执行策略中作为CollectLimitExec(m) (where m <= n),因此物理计划如下所示:

CollectLimit m
+- ...

CollectLimitExec执行它的子计划,然后检查RDD有多少个分区。如果没有,则返回一个空数据集。如果有,它会运行mapPartitionsInternal(_.take(m))来获取第一个m元素。如果不止一个,它使用mapPartitionsInternal(_.take(m))在RDD中的每个分区上应用take(m),构建一个将结果收集到单个分区中的shuffle RDD,然后再次应用take(m)

换句话说,这取决于(因为优化阶段),但在一般情况下,它采用每个分区的顶行的连接的顶行,因此涉及持有数据集的一部分的所有执行器。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值