究竟是什么.select()呢?

时间:2017-12-22 00:38:15

标签: apache-spark pyspark

使用.select()时,我遇到了令人惊讶的行为:

>>> my_df.show()
+---+---+---+
|  a|  b|  c|
+---+---+---+
|  1|  3|  5|
|  2|  4|  6|
+---+---+---+

>>> a_c = s_df.select(col("a"), col("c")) # removing column b
>>> a_c.show()
+---+---+
|  a|  c|
+---+---+
|  1|  5|
|  2|  6|
+---+---+

>>> a_c.filter(col("b") == 3).show() # I can still filter on "b"!
+---+---+
|  a|  c|
+---+---+
|  1|  5|
+---+---+

这种行为令我疑惑......我的以下观点是否正确?

DataFrames只是视图,简单的DataFrame就是它自己的视图。在我的情况下,a_c只是my_df的视图。

当我创建a_c时,没有创建新数据,a_c只是指向my_df指向的相同数据。

如果有其他相关信息,请添加!

2 个答案:

答案 0 :(得分:6)

由于Spark的懒惰性质,这种情况正在发生。它是聪明的"足以推动过滤器向下,使其发生在较低的水平 - 在过滤器*之前。所以,因为这一切都发生在同一stage的执行中,并且仍然可以解决。事实上,您可以在explain

中看到这一点
== Physical Plan ==
*Project [a#0, c#2]
+- *Filter (b#1 = 3) <---Filter before Project
   +- LocalTableScan [A#0, B#1, C#2]

您可以强制进行随机播放和新阶段,然后查看您的过滤器失败。甚至在编译时捕获它。这是一个例子:

a_c.groupBy("a","c").count.filter(col("b") === 3)

*还有一个投影修剪,如果它意识到它在任何时候都不需要该列,则将选择推送到数据库层。但是我相信过滤器会导致它需要&#34;需要&#34;它并没有修剪......但我没有测试过。

答案 1 :(得分:1)

让我们从一些基础知识开始。这将使您的理解变得容易。      RDD :Spark核心的基础是名为RDD的数据结构              懒洋洋地评价。通过延迟评估,我们指的是RDD计算              当动作发生时(比如在RDD中调用计数或在数据集中显示)。

数据集或数据框(数据集[行])也在核心使用RDD。

这意味着只有在触发动作(显示)时才会实现每个转换(如过滤器)。

所以你的问题     &#34;当我创建a_c时,没有创建新数据,a_c只是指向my_df指向的相同数据。&#34;
因为没有实现的数据。我们必须意识到它将它带入记忆中。您的过滤器适用于初始数据帧。 使a_c.filter(col("b") == 3).show()抛出运行时异常的唯一方法是使用dataframe.cache缓存中间数据帧。 所以火花将会引发'#34;主要&#34; org.apache.spark.sql.AnalysisException:无法解析列名 例如。

val a_c = s_df.select(col("a"), col("c")).cache
         a_c.filter(col("b") == 3).show()
  

所以火花会抛出#34;主要&#34; org.apache.spark.sql.AnalysisException:不能            解析列名。