Spark SQL - 隐式创建模式和以编程方式创建模式之间的确切区别

Posted

技术标签:

【中文标题】Spark SQL - 隐式创建模式和以编程方式创建模式之间的确切区别【英文标题】:Spark SQL - Exact difference between Creating schema implicitly & Programmatically 【发布时间】:2016-01-30 20:47:24 【问题描述】:

我试图了解确切的区别以及可以在隐式创建架构和以编程方式创建架构之间的特定场景中使用哪种方法。

在 Databricks 网站上,信息并没有那么详细和解释性。

我们可以看到,当使用反射(隐式 RDD 到 DF)方式时,我们可以通过使用 Map 函数从文本文件中选择特定列来创建案例类。

并且在程序化风格中 - 我们正在加载数据集一个文本文件(类似于反射)

Creating a SchemaString(String) = "知道文件我们可以指定我们需要的列"(类似于反射方式中的case类)

导入 ROW API - 这将再次映射到架构字符串中使用的特定列和数据类型(类似于案例类)

然后我们创建 DataFrame & 之后一切都一样.. 那么这两种方法的确切区别是什么。

http://spark.apache.org/docs/1.5.2/sql-programming-guide.html#inferring-the-schema-using-reflection

http://spark.apache.org/docs/1.5.2/sql-programming-guide.html#programmatically-specifying-the-schema

请解释...

【问题讨论】:

【参考方案1】:

生成的架构是相同的,所以从这个角度来看,没有区别。在这两种情况下,您都在为数据提供模式,但在一种情况下,您是从案例类中进行的,在另一种情况下,您可以使用集合,因为模式是作为 StructType(Array[StructField]) 构建的。 所以它基本上是元组和集合之间的选择。在我看来,最大的区别是案例类必须在代码中,而以编程方式指定架构可以在运行时完成,因此您可以,例如,基于您正在阅读的另一个 DataFrame 构建架构在运行时。 例如,我编写了一个通用工具来“嵌套”数据,从 CSV 读取数据,并将一组前缀字段转换为结构数组。 由于该工具是通用的,并且模式仅在运行时才知道,因此我使用了编程方法。 另一方面,使用反射对其进行编码通常更容易,因为您不必处理所有 StructField 对象,因为它们是从 hive 元存储派生的,它们的数据类型必须映射到您的 scala 类型。

【讨论】:

有点清楚,但如果你发布一个两者之间差异的例子会很棒。【参考方案2】:

以编程方式指定架构 当无法提前定义案例类时(例如,记录的结构被编码为字符串,或者将解析文本数据集并为不同的用户投射不同的字段),可以通过三个步骤以编程方式创建 DataFrame .

从原始 RDD 创建一个 RDD of Rows; 创建由 StructType 表示的模式,该模式与步骤 1 中创建的 RDD 中的 Rows 结构相匹配。 通过 SQLContext 提供的 createDataFrame 方法将 schema 应用到 Rows 的 RDD。

例如:

// sc is an existing SparkContext.
val sqlContext = new org.apache.spark.sql.SQLContext(sc)

// Create an RDD
val people = sc.textFile("examples/src/main/resources/people.txt")

// The schema is encoded in a string
val schemaString = "name age"

// Import Row.
import org.apache.spark.sql.Row;

// Import Spark SQL data types
import org.apache.spark.sql.types.StructType,StructField,StringType;

// Generate the schema based on the string of schema
val schema =
  StructType(
    schemaString.split(" ").map(fieldName => StructField(fieldName, StringType, true)))

// Convert records of the RDD (people) to Rows.
val rowRDD = people.map(_.split(",")).map(p => Row(p(0), p(1).trim))

// Apply the schema to the RDD.
val peopleDataFrame = sqlContext.createDataFrame(rowRDD, schema)

// Register the DataFrames as a table.
peopleDataFrame.registerTempTable("people")

使用反射推断架构 Spark SQL 的 Scala 接口支持自动将包含案例类的 RDD 转换为 DataFrame。案例类定义表的模式。案例类的参数名称使用反射读取并成为列的名称。案例类也可以嵌套或包含复杂类型,例如序列或数组。这个 RDD 可以隐式转换为 DataFrame,然后注册为表。表可以在后续的 SQL 语句中使用。

例如:

// sc is an existing SparkContext.
val sqlContext = new org.apache.spark.sql.SQLContext(sc)
// this is used to implicitly convert an RDD to a DataFrame.
import sqlContext.implicits._

// Define the schema using a case class.
// Note: Case classes in Scala 2.10 can support only up to 22 fields. To work around this limit,
// you can use custom classes that implement the Product interface.
case class Person(name: String, age: Int)

// Create an RDD of Person objects and register it as a table.
val people = sc.textFile("examples/src/main/resources/people.txt").map(_.split(",")).map(p => Person(p(0), p(1).trim.toInt)).toDF()
people.registerTempTable("people")

【讨论】:

以上是关于Spark SQL - 隐式创建模式和以编程方式创建模式之间的确切区别的主要内容,如果未能解决你的问题,请参考以下文章

JSF 2.0 在整个会话中从浏览器和以编程方式设置区域设置 [重复]

oracle游标的使用

Oracle 游标简介

对故事板和以编程方式推送 ios Objective C 感到困惑

在scala中使用spark sql解决特定需求

Spark3.3.0的DataFrame及Spark SQL编程的性能对比单机模式下