《零基础入门Spark》学习笔记 Day 06

数据源与数据格式

一、Driver端创建DataFrame

首先用Driver端数据结构创建RDD,然后再调用createDataFrame把RDD转化为DataFrame

对于大规模数据,优先使用并行集合(RDD)而非本地集合。在创建DataFrame前,确保数据已在Driver端内存中可管理。对于复杂数据结构,预先定义明确的schema能提高处理效率。

当从Pandas DataFrame转换时,注意数据大小,因为所有数据需要先加载到Driver内存中。大数据集应考虑分块处理或直接使用Spark数据源API读取。

二、文件系统创建DataFrame

Spark支持多种文件系统,常见的有HDFS、Amazon S3、本地文件系统等。无论哪种文件系统,Spark都要把通过SparkSession的read API来读取数据并创建DataFrame。

下面是千问的示例代码

java 复制代码
 // 初始化 SparkSession
        SparkSession spark = SparkSession.builder()
            .appName("FileSystemDataFrameDemo")
            .master("local[*]")
            .getOrCreate();

        // 设置日志级别(可选)
        spark.sparkContext().setLogLevel("WARN");

        try {
            // 示例1:从 CSV 文件读取
            Dataset<Row> csvDf = spark.read()
                .option("header", "true")
                .option("inferSchema", "true")
                .csv("data/users.csv");

            System.out.println("=== CSV DataFrame ===");
            csvDf.show();
            csvDf.printSchema();

            // 示例2:从 JSON 文件读取
            Dataset<Row> jsonDf = spark.read()
                .option("multiline", "true")
                .json("data/users.json");

            System.out.println("=== JSON DataFrame ===");
            jsonDf.show();

            // 示例3:从 Parquet 文件读取
            Dataset<Row> parquetDf = spark.read()
                .parquet("data/users.parquet");

            System.out.println("=== Parquet DataFrame ===");
            parquetDf.show();

            // 基本操作示例
            System.out.println("=== 基本操作 ===");
            csvDf.filter(csvDf.col("age").gt(25)).show();
            csvDf.groupBy("city").count().show();
            csvDf.createOrReplaceTempView("users");
            spark.sql("SELECT city, COUNT(*) as cnt FROM users GROUP BY city").show();

            // 写入文件示例
            csvDf.write()
                .mode(SaveMode.Overwrite)
                .parquet("output/users_parquet");

            csvDf.write()
                .option("header", "true")
                .mode(SaveMode.Overwrite)
                .csv("output/users_csv");

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            spark.stop();
        }

三、CSV创建DataFrame

常见的读取选项

选项 说明 示例值
header 是否包含表头 true/false
inferSchema 是否自动推断字段类型 true/false
delimiter 分隔符 , / \t / |
encoding 文件编码 UTF-8 / GBK
mode 错误处理模式 PERMISSIVE / DROPMALFORMED / FAILFAST
nullValue 空值表示 NULL / \N
escape 转义字符 \
quote 引号字符 "

四、Parquest/ORC创建DataFrame

ORC常见读取/写入选项

选项 说明 示例值
compression 压缩方式 NONE / SNAPPY / ZLIB / LZO
mergeSchema 合并多个文件的 schema true/false
filterPushdown 启用谓词下推优化 true/false
ignoreCorruptFiles 忽略损坏文件 true/false
orc.create.index 创建索引 true/false
orc.stripe.size 条带大小(字节) 67108864(默认 64MB)
orc.row.index.stride 行索引步长 10000
orc.bloom.filter.columns 布隆过滤器列 col1,col2
orc.bloom.filter.fpp 布隆过滤器误判率 0.0001

Parquest常见读取/写入选项

选项 说明 示例值
compression 压缩方式 snappy / gzip / lz4 / zstd / uncompressed
mergeSchema 合并多个文件的 schema true/false
filterPushdown 启用谓词下推优化 true/false
ignoreCorruptFiles 忽略损坏文件 true/false
recursiveFileLookup 递归查找子目录 true/false
parquet.enable.dictionary 启用字典编码 true/false
parquet.writer.version Parquet 写入版本 v1 / v2
parquet.block.size 块大小(字节) 134217728(默认 128MB)
parquet.row.group.size 行组大小(字节) 134217728(默认 128MB)

五、RDBMS创建DataFrame

以MYSQL为例,下面是千问的示例代码

java 复制代码
SparkSession spark = SparkSession.builder()
            .appName("JdbcToDataFrameDemo")
            .master("local[*]")
            .getOrCreate();

        spark.sparkContext().setLogLevel("WARN");

        // 配置 JDBC 连接属性
        Properties connectionProperties = new Properties();
        connectionProperties.put("user", USER);
        connectionProperties.put("password", PASSWORD);
        connectionProperties.put("driver", DRIVER);
        // 优化:设置 fetchsize 避免内存溢出
        connectionProperties.put("fetchSize", "1000"); 

        try {
            // === 1. 读取数据 ===

            // 方法 1:直接读取整张表
            System.out.println("=== 方法 1:读取整张表 ===");
            Dataset<Row> df1 = spark.read()
                .jdbc(URL, TABLE, connectionProperties);
            df1.show();
            df1.printSchema();

            // 方法 2:读取查询结果(子查询)
            System.out.println("=== 方法 2:读取查询结果 ===");
            String subQuery = "(SELECT id, name, salary FROM " + TABLE + " WHERE salary > 15000) AS high_salary_emp";
            Dataset<Row> df2 = spark.read()
                .jdbc(URL, subQuery, connectionProperties);
            df2.show();

            // 方法 3:分区读取(推荐用于大表,提高并行度)
            System.out.println("=== 方法 3:分区读取 ===");
            Dataset<Row> df3 = spark.read()
                .jdbc(URL, TABLE, "id", 1, 100, 4, connectionProperties);
                // 参数说明:column, lowerBound, upperBound, numPartitions
            System.out.println("分区数:" + df3.rdd().getNumPartitions());
            df3.show();

            // 方法 4:使用 DataFrameReader 选项配置
            System.out.println("=== 方法 4:选项配置读取 ===");
            Dataset<Row> df4 = spark.read()
                .format("jdbc")
                .option("url", URL)
                .option("dbtable", TABLE)
                .option("user", USER)
                .option("password", PASSWORD)
                .option("driver", DRIVER)
                .option("fetchSize", "1000")
                .option("partitionColumn", "id")
                .option("lowerBound", "1")
                .option("upperBound", "100")
                .option("numPartitions", "4")
                .load();
            df4.show();

            // === 2. 数据处理 ===
            System.out.println("=== 数据处理 ===");
            df4.filter(df4.col("age").gt(30))
               .groupBy("department")
               .agg(
                   org.apache.spark.sql.functions.avg("salary").alias("avg_salary"),
                   org.apache.spark.sql.functions.count("id").alias("count")
               )
               .show();

            // === 3. 写入数据回数据库 ===
            
            // 准备写入的数据
            Dataset<Row> newData = spark.createDataFrame(
                java.util.Arrays.asList(
                    new org.apache.spark.sql.Row[]{
                        org.apache.spark.sql.RowFactory.create(9, "新员工", 25, "技术部", 14000.00, java.sql.Date.valueOf("2023-01-01"))
                    }
                ),
                df4.schema()
            );

            // 写入模式:Append, Overwrite, Ignore, ErrorIfExists
            System.out.println("=== 写入数据库 (Append) ===");
            newData.write()
                .mode(SaveMode.Append)
                .jdbc(URL, TABLE, connectionProperties);

            // 批量写入优化
            System.out.println("=== 写入数据库 (带批量配置) ===");
            newData.write()
                .mode(SaveMode.Append)
                .option("batchsize", "1000")      // 每次提交记录数
                .option("isolationLevel", "NONE") // 事务隔离级别
                .option("numPartitions", "1")     // 写入并发度
                .jdbc(URL, TABLE + "_backup", connectionProperties); // 写入新表

            // === 4. 统计信息 ===
            System.out.println("=== 统计信息 ===");
            System.out.println("总行数:" + df4.count());

        } catch (Exception e) {
            System.err.println("发生错误:" + e.getMessage());
            e.printStackTrace();
        } finally {
            spark.stop();
        }
相关推荐
海海不瞌睡(捏捏王子)2 小时前
《计算机网络》再学习
网络·学习·计算机网络
幸福在路上wellbeing2 小时前
Kotlin 核心学习大纲(Android 开发)
android·学习·kotlin
D愿你归来仍是少年2 小时前
Apache Spark 第 8 章:Structured Streaming 流处理
大数据·spark·apache
xiaoxiaoxiaolll2 小时前
《自然·通讯》最新:集成光子学中的极简无线收发器,为6G终端低成本高速互联铺路
学习
知识分享小能手2 小时前
MongoDB入门学习教程,从入门到精通,MongoDB索引(5)
数据库·学习·mongodb
中屹指纹浏览器2 小时前
2026多账号运维中的指纹标准化治理与平台风控适配研究
经验分享·笔记
NULL指向我2 小时前
信号处理学习笔记4:动态调整系数的一阶低通滤波
笔记·学习·信号处理
繁星星繁2 小时前
Python基础语法(一)
c++·笔记·python
前端飞行手册2 小时前
electron应用开发模板,集成多种解决方案
前端·javascript·学习·electron·前端框架·vue