Spark SQL 下DateFrame的初步认识(2)

本文介绍如何使用Java和Scala进行RDD与DataFrame的转换及应用。包括Java中通过反射创建DataFrame并执行SQL查询,以及Scala环境下利用SparkShell执行SparkSQL命令的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1,使用Java和Scala实战RDD和DataFrame

1,Java 方式实战RDD与DataFrame的转换

 import java.util.List;


import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.Function;
import org.apache.spark.sql.DataFrame;
import org.apache.spark.sql.Row;
import org.apache.spark.sql.SQLContext;

public class RDD2DataFrameByReflect {
    public static void main(String[] args) {
        SparkConf conf = new SparkConf().setMaster("local").setAppName("RDD2DataFrameByReflect");
        JavaSparkContext sc = new JavaSparkContext(conf);

        SQLContext sqlContext = new SQLContext(sc);

        JavaRDD<String> lines = sc.textFile("C://Users//zpf//Desktop//Persons.txt");

        JavaRDD<Person> persons = lines.map(new Function<String, Person>() {

            @Override
            public Person call(String line) throws Exception {

                String[] splited = line.split(",");
                Person p = new Person();

                p.setId(Integer.valueOf(splited[0].trim()));
                p.setName(splited[1]);
                p.setAge(Integer.valueOf(splited[2].trim()));
                return p;
            }
        });

        DataFrame df = sqlContext.createDataFrame(persons, Person.class);

        df.registerTempTable("persons");

        DataFrame bigDatas = sqlContext.sql("select * from persons where age >= 6");

        //将DataFrame转化成RDD以方便后面输出数据使用
        JavaRDD<Row> bigDataRDD = bigDatas.javaRDD();

         JavaRDD<Person> result = bigDataRDD.map(new Function<Row, Person>() {

            @Override
            public Person call(Row row) throws Exception {
                Person p = new Person();
//DataFrame 转换成RDD时注意根据fieldName 获取对应的值  默认字母排序方式
                p.setId(row.getInt(1));
                p.setName(row.getString(2));

                p.setAge(row.getInt(0));

                return p;
            }
        });

        List<Person> PersonList =  result.collect();

        for(Person p : PersonList){
            System.out.println(p);
        }


    }
}




import scala.Serializable;

public class Person implements Serializable{

    private int id;
    private String name;
    private int age;

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "People [id=" + id + ", name=" + name + ", age=" + age + "]";
    }

}

**注意:JavaRDD和DataFrame互相转换注意事项:
1)反射的类必须是Pulic class
2)定义的类必须实现Serializable 接口
3)DataFrame 转换成RDD时注意根据fieldName 获取对应的值**

2,Scala运行实战

1,下述代码片段展示了可以在Spark Shell终端执行的Spark SQL命令


// 首先用已有的Spark Context对象创建SQLContext对象
val sqlContext = new org.apache.spark.sql.SQLContext(sc)

// 导入语句,可以隐式地将RDD转化成DataFrame
import sqlContext.implicits._

// 创建一个表示客户的自定义类
case class Customer(customer_id: Int, name: String, city: String, state: String, zip_code: String)

// 用数据集文本文件创建一个Customer对象的DataFrame
val dfCustomers = sc.textFile("data/customers.txt").map(_.split(",")).map(p => Customer(p(0).trim.toInt, p(1), p(2), p(3), p(4))).toDF()

// 将DataFrame注册为一个表
dfCustomers.registerTempTable("customers")

// 显示DataFrame的内容
dfCustomers.show()

// 打印DF模式
dfCustomers.printSchema()

// 选择客户名称列
dfCustomers.select("name").show()

// 选择客户名称和城市列
dfCustomers.select("name", "city").show()

// 根据id选择客户
dfCustomers.filter(dfCustomers("customer_id").equalTo(500)).show()

// 根据邮政编码统计客户数量
dfCustomers.groupBy("zip_code").count().show()

在上一示例中,模式是通过反射而得来的。我们也可以通过编程的方式指定数据集的模式。这种方法在由于数据的结构以字符串的形式编码而无法提前定义定制类的情况下非常实用。

如下代码示例展示了如何使用新的数据类型类StructType,StringType和StructField指定模式。

// 用编程的方式指定模式


// 用已有的Spark Context对象创建SQLContext对象
val sqlContext = new org.apache.spark.sql.SQLContext(sc)

// 创建RDD对象
val rddCustomers = sc.textFile("data/customers.txt")

// 用字符串编码模式
val schemaString = "customer_id name city state zip_code"

// 导入Spark SQL数据类型和Row
import org.apache.spark.sql._

import org.apache.spark.sql.types._;

// 用模式字符串生成模式对象
val schema = StructType(schemaString.split(" ").map(fieldName => StructField(fieldName, StringType, true)))

// 将RDD(rddCustomers)记录转化成Row。
val rowRDD = rddCustomers.map(_.split(",")).map(p => Row(p(0).trim,p(1),p(2),p(3),p(4)))

// 将模式应用于RDD对象。
val dfCustomers = sqlContext.createDataFrame(rowRDD, schema)

// 将DataFrame注册为表
dfCustomers.registerTempTable("customers")

// 用sqlContext对象提供的sql方法执行SQL语句。
val custNames = sqlContext.sql("SELECT name FROM customers")

// SQL查询的返回结果为DataFrame对象,支持所有通用的RDD操作。
// 可以按照顺序访问结果行的各个列。
custNames.map(t => "Name: " + t(0)).collect().foreach(println)

// 用sqlContext对象提供的sql方法执行SQL语句。
val customersByCity = sqlContext.sql("SELECT name,zip_code FROM customers ORDER BY zip_code")

// SQL查询的返回结果为DataFrame对象,支持所有通用的RDD操作。
// 可以按照顺序访问结果行的各个列。
customersByCity.map(t => t(0) + "," + t(1)).collect().foreach(println)

除了文本文件之外,也可以从其他数据源中加载数据,如JSON数据文件,Hive表,甚至可以通过JDBC数据源加载关系型数据库表中的数据。

如上所示,Spark SQL提供了十分友好的SQL接口,可以与来自多种不同数据源的数据进行交互,而且所采用的语法也是团队熟知的SQL查询语法。这对于非技术类的项目成员,如数据分析师以及数据库管理员来说,非常实用。

### Spark SQLDataFrame 的关系及使用方法 #### 关系分析 Spark SQLApache Spark 中的一个模块,用于处理结构化数据。它提供了一个编程抽象称为 DataFrame,并作为分布式 SQL 查询引擎的作用[^1]。DataFrame 是一种以表格形式存储的数据结构,类似于传统数据库中的表或者 Pandas 中的 DataFrame。然而,Spark DataFrame 是分布式的,能够在大规模集群上进行高效的并行计算。 Spark SQL 提供了两种主要的方式来操作数据:一是通过 DataFrame API 进行编程式操作;二是通过标准的 SQL 查询语言来进行声明式操作[^2]。这两种方式最终都会被 Catalyst 优化器编译成底层的 RDD 操作,从而保证性能最优。 --- #### 使用方法对比 ##### 1. **DataFrame API** 通过 DataFrame API 可以编写更加灵活和强大的代码逻辑。以下是其特点: - 支持链式调用,便于构建复杂的 ETL 流程。 - 自动利用 Catalyst 优化器对查询计划进行优化。 - 数据不可变且延迟执行,适合批处理场景。 下面是一个简单的例子展示了如何使用 DataFrame API 来完成 WordCount: ```python from pyspark.sql import SparkSession from pyspark.sql.functions import col, split, explode if __name__ == "__main__": spark = SparkSession.builder \ .appName("WordCount") \ .master("local[*]") \ .getOrCreate() # 加载文本文件到 DataFrame df = spark.read.text("/path/to/input/file") # 将每行拆分为单词列表 words_df = df.select(explode(split(col("value"), "\\s+")).alias("word")) # 对每个单词计数 result_df = words_df.groupBy("word").count().orderBy(col("count").desc()) # 展示结果 result_df.show(truncate=False) spark.stop() ``` 此代码片段说明了如何通过 DataFrame API 实现分词、聚合以及排序功能[^4]。 --- ##### 2. **SQL 风格** 对于熟悉 SQL 的用户来说,可以直接注册临时视图并通过 SQL 查询来获取所需的结果。这种方式的优点在于语法简单直观,易于维护。 继续以上述 WordCount 为例,可以改写为如下 SQL 形式: ```python from pyspark.sql import SparkSession if __name__ == "__main__": spark = SparkSession.builder \ .appName("WordCount_SQL") \ .master("local[*]") \ .getOrCreate() # 加载文本文件到 DataFrame 并创建临时视图 df = spark.read.text("/path/to/input/file") df.createOrReplaceTempView("lines") # 执行 SQL 查询统计单词频率 word_count_df = spark.sql(""" SELECT word, COUNT(*) AS count FROM ( SELECT EXPLODE(SPLIT(value, '\\s+')) AS word FROM lines ) GROUP BY word ORDER BY count DESC """) # 显示前几条记录 word_count_df.show(truncate=False) spark.stop() ``` 上述代码同样实现了基于 SQL 的 WordCount 功能[^5]。 --- #### 联系与区别 | 特性 | DataFrame API | SQL 风格 | |---------------------|---------------------------------------|---------------------------------------| | 编程模型 | 基于 Python 或 Scala 的函数式编程 | 类似传统的 SQL 查询 | | 学习曲线 | 较陡峭 | 如果已有 SQL 基础,则较为平缓 | | 性能 | 同样由 Catalyst 优化 | 同样由 Catalyst 优化 | | 灵活性 | 更加灵活,适用于复杂业务逻辑 | 主要针对固定模式的查询需求 | 两者的核心差异体现在表达方式的不同:前者更适合开发者习惯,而后者则更贴近分析师的需求[^3]。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值