Spark 数据源:高效读写多种格式

Spark 数据源:高效读写多种格式

Spark 提供了统一的数据源 API,支持读写多种数据格式,包括列式存储(Parquet/ORC)、文本格式(JSON/CSV)、二进制格式(Avro)以及关系型数据库(JDBC)等。重点掌握 Parquet 和 ORC 这两种高效的列式存储格式。

一、核心数据源概览

格式类型特点适用场景
Parquet列式Spark 默认格式,高效压缩,支持谓词下推大数据分析首选
ORC列式Hive 优化格式,ACID 支持,高效压缩Hive 生态系统
JSON行式易读,支持复杂结构半结构化数据交换
CSV行式通用表格格式表格数据交换
Avro行式二进制,Schema 演化支持数据序列化
JDBC关系型连接传统数据库数据库集成
Hive列式/行式数据仓库集成数仓分析

二、列式存储重点:Parquet & ORC

1. Parquet - Spark 默认存储格式

特点:

  • 列式存储:只读取需要的列
  • 高效压缩:同列数据类型一致,压缩率高
  • 谓词下推:过滤条件下推到存储层
  • Schema 演化:支持添加/重命名列

读写操作:

# 读取 Parquet
df = spark.read.parquet("hdfs:///data/parquet/")

# 写入 Parquet(推荐 Snappy 压缩)
(df.write
 .option("compression", "snappy")
 .parquet("hdfs:///output/parquet/"))

# 分区写入(提高查询性能)
(df.write
 .partitionBy("year", "month")
 .parquet("hdfs:///partitioned_data/"))

2. ORC - Hive 优化格式

特点:

  • 更高压缩率(相比 Parquet)
  • 内置索引(轻量级索引)
  • ACID 事务支持(Hive 3+)
  • 向量化读取优化

读写操作:

# 读取 ORC
df = spark.read.orc("hdfs:///data/orc/")

# 写入 ORC(推荐 Zlib 压缩)
(df.write
 .option("compression", "zlib")
 .orc("hdfs:///output/orc/"))

# 分桶写入(优化 JOIN 性能)
(df.write
 .bucketBy(128, "user_id")
 .sortBy("timestamp")
 .saveAsTable("bucketed_table"))

3. 列式存储最佳实践

  1. 分区策略:按时间(年/月/日)或类别分区
  2. 压缩选择
    • Parquet:Snappy(平衡速度/压缩率)
    • ORC:Zlib(高压缩率)
  3. 列裁剪:只选择需要的列
  4. 谓词下推:在读取时应用过滤条件
    spark.read.parquet("...").filter("age > 30")  # 自动下推
    

三、其他数据源操作

1. JSON(半结构化数据)

# 读取 JSON
df_json = spark.read.json("data.json")

# 多行 JSON
spark.read.option("multiLine", True).json("complex.json")

# 写入 JSON(不推荐大数据集)
df.write.json("output.json")

2. CSV(表格数据)

# 读取 CSV
df_csv = (spark.read
          .option("header", True)
          .option("delimiter", ";")
          .option("inferSchema", True)  # 谨慎使用
          .csv("data.csv"))

# 指定 Schema 读取(推荐)
from pyspark.sql.types import *
schema = StructType([
    StructField("name", StringType()),
    StructField("age", IntegerType())
])
df_safe = spark.read.schema(schema).csv("data.csv")

# 写入 CSV
df.write.option("header", True).csv("output.csv")

3. JDBC(关系数据库)

# 读取 PostgreSQL
jdbc_df = (spark.read
           .format("jdbc")
           .option("url", "jdbc:postgresql://localhost/mydb")
           .option("dbtable", "employees")
           .option("user", "user")
           .option("password", "pass")
           .option("fetchsize", "10000")  # 分批读取
           .load())

# 写入 MySQL(覆盖模式)
(df.write
 .format("jdbc")
 .option("url", "jdbc:mysql://localhost/test")
 .option("dbtable", "new_data")
 .option("user", "user")
 .option("password", "pass")
 .mode("overwrite")
 .save())

4. Hive 集成

# 启用 Hive 支持
spark = SparkSession.builder.appName("HiveExample").enableHiveSupport().getOrCreate()

# 读取 Hive 表
hive_df = spark.sql("SELECT * FROM my_hive_table")

# 写入 Hive 表
df.write.saveAsTable("new_hive_table")  # 内部表

# 外部表(保留数据文件)
df.write.option("path", "/hdfs/path").saveAsTable("external_table")

5. Avro(二进制序列化)

# 需要添加包:--packages org.apache.spark:spark-avro_2.12:3.3.0
df_avro = spark.read.format("avro").load("data.avro")
df.write.format("avro").save("output.avro")

四、高级技巧与优化

1. 数据源混合读写

# 从 CSV 读取,转换后写入 Parquet
(spark.read.csv("input.csv")
     .filter("value > 100")
     .write.parquet("output.parquet"))

2. 并行读取数据库

# 分区读取大表
jdbc_df = (spark.read
           .format("jdbc")
           .option("url", "jdbc:postgresql://localhost/db")
           .option("dbtable", "big_table")
           .option("user", "user")
           .option("password", "pass")
           .option("numPartitions", "10")  # 并行度
           .option("partitionColumn", "id")
           .option("lowerBound", "1")
           .option("upperBound", "1000000")
           .load())

3. Schema 合并(Parquet)

# 启用 Schema 合并
spark.conf.set("spark.sql.parquet.mergeSchema", "true")

# 读取多个 Parquet 文件(不同 Schema)
merged_df = spark.read.parquet("data/year=2022/*", "data/year=2023/*")

4. 数据湖格式支持

# Delta Lake(ACID 事务支持)
df.write.format("delta").save("/delta/table")

# Iceberg 表
df.writeTo("catalog.db.table").using("iceberg").create()

五、数据源选择指南

场景推荐格式原因
大数据分析ParquetSpark 默认优化,高效压缩
Hive 集成ORCHive 原生支持,ACID 特性
数据交换JSON/CSV通用性强,易读
实时采集AvroSchema 演化支持
数据库同步JDBC直接连接关系数据库
数仓建设Hive/Delta支持 ACID,版本控制

六、性能优化总结

  1. 列式存储优先:Parquet/ORC 比行式格式快 10-100 倍
  2. 分区分桶:加速数据裁剪和 JOIN 操作
  3. 压缩选择
    • 速度优先:Snappy
    • 空间优先:Zlib/Gzip
  4. 谓词下推:在读取时过滤数据
  5. 列裁剪:只读取需要的列
  6. 并行读取:数据库大表使用分区读取

七、完整示例:端到端 ETL

# 1. 从 JDBC 读取
source_df = (spark.read
             .format("jdbc")
             .option("url", "jdbc:mysql://prod-db/sales")
             .option("dbtable", "transactions")
             .option("user", "etl_user")
             .option("password", "secure_pass")
             .load())

# 2. 数据处理
processed_df = (source_df
                .filter("amount > 100")
                .withColumn("date", to_date("timestamp"))
                .select("id", "product_id", "amount", "date"))

# 3. 分区写入 Parquet
(processed_df.write
 .partitionBy("date")
 .option("compression", "snappy")
 .parquet("hdfs:///data/sales/parquet/"))

# 4. 注册为 Hive 表
spark.sql("""
CREATE EXTERNAL TABLE sales_data (
    id BIGINT,
    product_id INT,
    amount DECIMAL(10,2)
)
PARTITIONED BY (date DATE)
STORED AS PARQUET
LOCATION 'hdfs:///data/sales/parquet/'
""")

总结

Spark 数据源核心要点:

  1. 首选列式存储:Parquet 为默认选择,ORC 用于 Hive 集成
  2. 统一 API 接口spark.readdataframe.write 支持所有格式
  3. 优化关键:分区、压缩、谓词下推、列裁剪
  4. 格式转换:轻松实现数据管道(如 CSV → Parquet → Hive)
  5. 生态集成:无缝连接数据库、数据湖和数据仓库

掌握这些数据源操作技巧,能够大幅提升 Spark 数据处理的效率和可靠性,构建高性能的数据管道。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值