SparkSQL-数据提取和保存

SparkSQL 提供了多种灵活的方式来提取和保存数据,支持各种数据源和格式。以下是全面的操作方法:

 一、数据提取(读取)

1. 基本读取方法

// 通用读取模板
val df = spark.read
  .format("数据源格式")  // json, csv, parquet, jdbc等
  .option("选项键", "选项值")  // 数据源特定选项
  .load("数据路径")

2. 常见数据源读取示例

(1) JSON 文件

val jsonDF = spark.read
  .json("path/to/file.json")  // 简洁写法

// 或完整写法
val jsonDF = spark.read
  .format("json")
  .option("multiLine", true)  // 处理多行JSON
  .option("mode", "PERMISSIVE")  // 解析模式(PERMISSIVE/DROPMALFORMED/FAILFAST)
  .load("path/to/file.json")

(2) CSV 文件

val csvDF = spark.read
  .option("header", "true")  // 使用首行作为列名
  .option("inferSchema", "true")  // 自动推断列类型
  .option("delimiter", ",")  // 指定分隔符
  .option("nullValue", "NA")  // 指定空值表示
  .csv("path/to/file.csv")

(3) Parquet 文件

val parquetDF = spark.read
  .parquet("path/to/file.parquet")  // 简洁写法

// 或指定schema
val schema = new StructType()
  .add("name", StringType)
  .add("age", IntegerType)

val parquetDF = spark.read
  .schema(schema)
  .parquet("path/to/file.parquet")

(4) JDBC 数据库

val jdbcDF = spark.read
  .format("jdbc")
  .option("url", "jdbc:mysql://host:port/db")
  .option("dbtable", "table_name")
  .option("user", "username")
  .option("password", "password")
  .option("fetchSize", "10000")  // 每次读取行数
  .load()

3. 高级读取技巧

 (1) 分区发现(针对分区存储)
 

spark.read.parquet("path/to/partitioned_table")
  .where($"year" === 2023 && $"month" === 12)  // 分区裁剪

(2) 读取目录下所有文件

spark.read.json("path/to/directory/*.json")

(3) 读取压缩文件

spark.read
  .option("compression", "gzip")  // 支持gzip, bzip2, snappy等
  .csv("path/to/file.csv.gz")

二、数据保存(写入)

1. 基本保存方法

// 通用保存模板
df.write
  .format("数据格式")
  .option("选项键", "选项值")
  .mode("保存模式")  // append/overwrite/ignore/error
  .save("保存路径")

2. 常见数据源保存示例

(1) 保存为JSON

df.write
  .mode("overwrite")
  .json("output/path")

// 控制输出
df.write
  .option("compression", "gzip")
  .option("dateFormat", "yyyy-MM-dd")
  .json("output/path")

 (2) 保存为CSV
 

df.write
  .option("header", "true")
  .option("delimiter", "|")
  .mode("append")
  .csv("output/path")

 (3) 保存为Parquet

df.write
  .partitionBy("year", "month")  // 按列分区存储
  .mode("overwrite")
  .parquet("output/path")

(4) 保存到JDBC数据库

df.write
  .format("jdbc")
  .option("url", "jdbc:mysql://host:port/db")
  .option("dbtable", "new_table")
  .option("user", "username")
  .option("password", "password")
  .option("batchsize", 10000)  // 批量写入大小
  .mode("append")  // 表不存在会自动创建
  .save()

 3. 高级保存技巧

(1) 分区写入
 

df.write
  .partitionBy("department")  // 按部门分区
  .parquet("output/path")

(2) 分桶写入
 

df.write
  .bucketBy(50, "user_id")  // 50个桶,按user_id分桶
  .sortBy("create_time")  // 桶内排序
  .saveAsTable("bucketed_table")  // 保存为Hive表

(3) 控制文件数量

df.coalesce(5)  // 减少到5个分区
  .write.parquet("output/path")

// 或
df.repartition(10, $"department")  // 按部门重新分区
  .write.parquet("output/path")

 (4) 保存为Hive表

df.write
  .saveAsTable("database.table_name")  // 内部表

df.write
  .option("path", "/hdfs/path")
  .saveAsTable("database.external_table")  // 外部表

三、特殊场景处理

1. 处理复杂数据类型

// 写入嵌套结构
df.withColumn("json_col", to_json(struct($"name", $"age")))
  .write.json("output/path")

// 读取时解析
spark.read
  .option("multiLine", true)
  .json("path/to/complex.json")

2. 增量写入

// 使用Delta Lake格式实现ACID
df.write
  .format("delta")
  .mode("append")
  .save("/delta/table")

// 或使用Hive分区实现增量
df.write
  .partitionBy("dt")
  .mode("append")
  .parquet("/data/table/dt=20230101")

3. 数据验证后写入

val validatedDF = df.filter($"age".isNotNull && $"age" > 0)

validatedDF.write
  .mode("overwrite")
  .parquet("output/path")

四、性能优化建议

1. 读取优化:
   使用`schema`选项避免推断开销
   对分区数据使用分区发现
   JDBC读取使用`partitionColumn`并行读取

2. 写入优化:
   控制输出文件数量(`coalesce`/`repartition`)
   对大表使用分区/分桶
   JDBC写入使用合适的`batchsize`

3. 格式选择:
   分析型查询优先选择Parquet/ORC
   行级操作考虑Avro
   临时数据可使用Delta Lake

4. 通用建议:
   监控写入任务避免小文件问题
   定期压缩小文件(`OPTIMIZE`命令)
   考虑使用缓存加速重复读取

你可能感兴趣的:(ajax,前端,javascript)