在 Spark 中,创建 DataFrame 和 Dataset 有多种方式,以下是最常用的方法(示例以 Scala/Python 为主):
一、创建 DataFrame
1. 从结构化文件创建(最常用)
# Python (PySpark)
# JSON 文件
df_json = spark.read.json("path/to/file.json")
# CSV 文件(带选项)
df_csv = (spark.read
.option("header", "true")
.option("inferSchema", "true")
.csv("path/to/file.csv"))
# Parquet 文件
df_parquet = spark.read.parquet("path/to/file.parquet")
// Scala
// JSON
val dfJson = spark.read.json("path/to/file.json")
// CSV(带选项)
val dfCsv = spark.read
.option("header", "true")
.option("inferSchema", "true")
.csv("path/to/file.csv")
// Parquet
val dfParquet = spark.read.parquet("path/to/file.parquet")
2. 从 RDD 创建
# Python
from pyspark.sql import Row
# 创建 RDD
rdd = sc.parallelize([("Alice", 34), ("Bob", 45)])
# 方法1:指定列名
df1 = rdd.toDF(["name", "age"])
# 方法2:使用 Row 对象
rows = rdd.map(lambda x: Row(name=x[0], age=x[1]))
df2 = spark.createDataFrame(rows)
// Scala
import spark.implicits._
// 创建 RDD
val rdd = sc.parallelize(Seq(("Alice", 34), ("Bob", 45)))
// 方法1:直接转 DataFrame(指定列名)
val df1 = rdd.toDF("name", "age")
// 方法2:通过 case class
case class Person(name: String, age: Int)
val df2 = rdd.map(p => Person(p._1, p._2)).toDF()
3. 从 Pandas DataFrame 创建(仅 PySpark)
import pandas as pd
pandas_df = pd.DataFrame({"id": [1, 2], "value": ["A", "B"]})
spark_df = spark.createDataFrame(pandas_df)
4. 从 Hive 表创建
# Python
df_hive = spark.sql("SELECT * FROM my_hive_table")
# 或
df_hive = spark.table("my_hive_table")
// Scala
val dfHive = spark.sql("SELECT * FROM my_hive_table")
// 或
val dfHive = spark.table("my_hive_table")
5. 从 JDBC 数据库创建
# Python
jdbc_df = (spark.read
.format("jdbc")
.option("url", "jdbc:postgresql:dbserver")
.option("dbtable", "schema.tablename")
.option("user", "username")
.option("password", "password")
.load())
6. 编程方式创建(测试用)
# Python
from pyspark.sql.types import *
schema = StructType([
StructField("id", IntegerType(), True),
StructField("name", StringType(), True)
])
data = [(1, "Alice"), (2, "Bob")]
df = spark.createDataFrame(data, schema)
二、创建 Dataset(仅 Scala/Java)
1. 从集合创建
case class Person(name: String, age: Int)
// 方法1:使用 createDataset
val ds1 = spark.createDataset(Seq(
Person("Alice", 34),
Person("Bob", 45)
))
// 方法2:隐式转换
import spark.implicits._
val ds2 = Seq(Person("Alice", 34), Person("Bob", 45)).toDS()
2. 从 DataFrame 转换(添加类型信息)
val df = spark.read.json("people.json") // DataFrame = Dataset[Row]
val ds = df.as[Person] // 转换为 Dataset[Person]
3. 从 RDD 创建
val rdd = sc.parallelize(Seq(Person("Alice", 34), Person("Bob", 45)))
val ds = spark.createDataset(rdd)
三、关键注意事项
-
Schema 处理:
- 文件读取时使用
inferSchema=true
自动推断(可能不准确) - 显式定义 Schema 可提高性能和准确性
from pyspark.sql.types import * schema = StructType([ StructField("name", StringType()), StructField("age", IntegerType()) ]) df = spark.read.schema(schema).json("data.json")
- 文件读取时使用
-
性能优化:
- Parquet/ORC 格式比 JSON/CSV 性能更好
- 批量数据优先使用
spark.read
而非createDataFrame
-
类型安全:
- Dataset 仅在 JVM 语言(Scala/Java)中支持类型安全
- PySpark/R 的 DataFrame 本质是
Dataset[Row]
-
数据源选项:
# 示例:读取 CSV 的更多选项 df = (spark.read .option("delimiter", ";") .option("quote", "'") .option("escape", "\\") .option("nullValue", "NA") .csv("file.csv"))
四、创建方式对比
数据源 | DataFrame 支持 | Dataset 支持 | 适用场景 |
---|---|---|---|
JSON/CSV/Parquet 文件 | ✓ | ✓ (转换后) | 大数据文件导入 |
RDD | ✓ | ✓ | 从现有 RDD 转换 |
Hive 表 | ✓ | ✓ (转换后) | 数据仓库集成 |
JDBC 数据库 | ✓ | ✗ | 关系型数据库查询 |
Pandas DataFrame | ✓ (PySpark) | ✗ | 与 Python 生态集成 |
内存集合 | ✓ | ✓ | 测试和小数据 |
五、最佳实践
-
生产环境:
- 优先使用 Parquet/ORC 文件格式
- 显式定义 Schema 避免推断开销
- 批量数据使用
spark.read
直接读取
-
开发测试:
- 小数据集用
spark.createDataFrame()
- 使用
case class
创建类型安全的 Dataset(Scala)
- 小数据集用
-
类型转换:
// Scala 示例:DataFrame → Dataset val ds: Dataset[Person] = df.as[Person] // Dataset → DataFrame val df: DataFrame = ds.toDF()
-
错误处理:
- 文件不存在时使用
spark.read.option("pathGlobFilter", "*.parquet")
- 模式不匹配时使用
.option("mode", "DROPMALFORMED")
- 文件不存在时使用
通过灵活组合这些方法,可以在 Spark 中高效地创建和转换结构化数据集,充分利用 DataFrame/Dataset API 的性能优势和易用性。