首页 > 解决方案 > 如何获取(派生的)Spark DataFrame 的查询逻辑的 SQL 表示?

问题描述

可以将原始 SQL 字符串转换为 DataFrame。但是否也有可能反过来,即获取(派生的)Spark DataFrame 的查询逻辑的 SQL 表示?

// Source data
val a = Seq(7, 8, 9, 7, 8, 7).toDF("foo")

// Query using DataFrame functions
val b = a.groupBy($"foo").agg(count("*") as "occurrences").orderBy($"occurrences")
b.show()

// Convert a SQL string into a DataFrame
val sqlString = "SELECT foo, count(*) as occurrences FROM a GROUP BY foo ORDER BY occurrences"
a.createOrReplaceTempView("a")
val c = currentSparkSession.sql(sqlString)
c.show()

// "Convert" a DataFrame into a SQL string
b.toSQLString() // Error: This function does not exist.

标签: scalaapache-sparkapache-spark-sql

解决方案


不可能将 DataFrame “转换”为 SQL 字符串,因为 Spark 不知道如何编写 SQL 查询,它也不需要。

我发现回忆一下 Spark 如何处理 Dataframe 代码或 SQL 查询很有用。这是由 Spark 的Catalyst Optimizer完成的,它经历了四个转型阶段,如下所示:

在此处输入图像描述

在第一阶段(分析)中,Spark SQL 引擎为 SQL 或 Dataframe 查询生成抽象语法树 ( AST )。该树是 Catalyst 中的主要数据类型(请参阅白皮书Spark SQL:Spark 中的关系数据处理中的第 4.1 节),它用于创建逻辑计划并最终创建物理计划。如果您使用explainSpark 提供的 API,您将获得这些计划的表示。

虽然我很清楚“一个人可以将原始 SQL 字符串转换为 DataFrame”是什么意思,但我想这有助于更精确。我们不会SQL 字符串(因此您自己在该词周围加上引号)转换为 Dataframe,但您应用了您的 SQL 知识,因为这是一种可以被Spark解析以理解您的意图的语法。此外,您不能只键入任何 SQL 查询,因为在与目录进行比较时,这仍然可能在分析阶段失败。因此,SQL 字符串只是关于 Spark 允许您如何给出指令的协议。然后,这个 SQL 查询被解析,转换成一个 AST(如上所述),并在经历了其他三个阶段之后,最终形成一个基于 RDD 的代码。此 SQL 执行的结果通过sqlAPI 返回一个 Dataframe,而您可以使用df.rdd.

总的来说,Spark 不需要将任何代码,特别是任何 Dataframe 代码编写成 SQL 语法,然后您就可以从 Spark 中脱离出来。AST 是内部抽象,Spark 不需要先将 Dataframe 代码转换为 SQL 查询,而是直接将 Dataframe 代码转换为 AST。


推荐阅读