考虑 Azure Databricks 上的以下场景。
spark.table("table1").createOrReplaceTempView("test_view")
df = test_view.drop("col1")
spark.sql("DROP TABLE table1")
df1 =df.createOrReplaceTempView("test_view2")
df1.display()
在上面的代码中,操作仅在最后一行。即使在操作之前删除基础表并且 Spark 采用惰性求值概念,df 如何显示输出。
我本以为会看到一条错误,指出无法解析该表,但令我惊讶的是,显示屏显示了输出。
读完你的评论后,我意识到你的误解在哪里——让我们解决这个问题。
你是对的,火花遵循惰性评估 - 这只是意味着 - 在调用操作之前它不会“具体化”数据。基本上,只有在触发操作后,数据才会进入内存进行处理。
现在来看你的代码:
spark.table("table1").createOrReplaceTempView("test_view")
:这将创建(或替换)表table1
的临时视图(未具体化),您可以使用 Spark SQL 进行查询。df = test_view.drop("col1")
:这是一个错误的说法。临时视图只能使用 spark.sql()
进行查询,并且您将 test_view
视为不允许的数据框。您可以将第一条语句替换为 test_view = spark.table("table1")
以使该语句合法。现在,这是一个转变。所以,数据集还没有具体化。spark.sql("DROP TABLE table1")
:这将从 Spark 目录中删除表 table1
。df1 = df.createOrReplaceTempView("test_view2")
:这是法律声明,但df1
不是 df。它是一个 NoneType 对象,因为 createOrReplaceTempView()
不返回数据帧。将其替换为 df1 = df
,这也是不必要的,但为了跟上您的代码,我将使用它。df1.display()
:最后是一些行动时间。现在将要发生以下情况:
test_view = spark.table("table1")
:test_view
以数据帧格式从table1
获取数据副本。df = test_view.drop("col1")
:从 test_view 中删除 col1
,并返回数据帧的新副本。该副本现在存储在 df
数据框中。spark.sql("DROP TABLE table1")
:这会从 Spark 目录中删除 table1
。 注意: 现在您真正的疑问是,如果该表被删除,那么为什么会显示数据?请记住,在删除 df
后,test_view
数据框具有 col1
的副本 - 它本身就是 table1
的副本 - 因此这意味着数据仍然在内存中 - 在 df
和 test_view
中
数据框。df1 = df
-> df1.display()
:同样,df1
只是另一个副本并且在内存中,因此,它将显示输出而不会引发任何错误,因为它对已经存在的table1
没有任何直接依赖作为副本存储在 df
和 test_view
中,它们仍然在内存中,因此即使在 table1
被删除后我们也能够看到数据。我希望现在已经清楚了。