2.Spark SQL、Dataset、DataFrame 初步

1.概述

Spark SQL 是用于结构化数据处理的 Spark 模块。

  1. Spark SQL API 提供了有关数据结构和正在执行的计算的更多信息。
  2. 在内部,Spark SQL 使用这些额外的信息来执行额外的优化。
  3. 与 Spark SQL 交互的方式有多种,包括 SQL 和 Dataset API。
  4. 计算结果时,使用相同的执行引擎,与您用于表达计算的 API/语言无关。

1.1.SQL

Spark SQL 的一种用途是执行 SQL 查询。
从另一种编程语言中运行 SQL 时,结果将作为Dataset/DataFrame返回。

1.2.Datasets 和 DataFrames

Dataset 是数据的分布式集合。
Dataset 是 Spark 1.6 中添加的一个新接口,它提供了 RDD 的优势(强类型化、使用强大 lambda 函数的能力)以及 Spark SQL 优化执行引擎的优势。可以从 JVM 对象构造数据集,然后使用功能转换(map、flatMap、filter等)进行操作。
DataFrame 是以命名列组织的数据集(Dataset<Row>)。
它在概念上等同于关系数据库中的表或 R/Python 中的数据框,但在底层进行了更丰富的优化。DataFrames 可以从多种来源构建,例如:结构化数据文件、Hive 中的表、外部数据库或现有 RDD。
我们将 Dataset<Row> 称为 DataFrames。

2.入门

2.1.创建 DataFrame

Dataset<Row> df = spark.read().json("examples/src/main/resources/people.json");

2.2.无类型数据集操作(又名 DataFrame 操作)

// Print the schema in a tree format
df.printSchema();

// Select only the "name" column
df.select("name").show();

// Select everybody, but increment the age by 1
df.select(col("name"), col("age").plus(1)).show();

// Select people older than 21
df.filter(col("age").gt(21)).show();

// Count people by age
df.groupBy("age").count().show();

有关可以对数据集执行的操作类型的完整列表,请参阅API 文档

2.3.以编程方式运行 SQL 查询

df.createOrReplaceTempView("people");

Dataset<Row> sqlDF = spark.sql("SELECT * FROM people");

2.4.创建 Dataset

使用专门的编码器来序列化对象,允许 Spark 执行许多操作(如过滤、排序和散列),而无需将字节反序列化回对象。

// Create an instance of a Bean class
Person person = new Person();
person.setName("Andy");
person.setAge(32);

// Encoders are created for Java beans
Encoder<Person> personEncoder = Encoders.bean(Person.class);
Dataset<Person> javaBeanDS = spark.createDataset(
  Collections.singletonList(person),
  personEncoder
);

// Encoders for most common types are provided in class Encoders
Encoder<Long> longEncoder = Encoders.LONG();
Dataset<Long> primitiveDS = spark.createDataset(Arrays.asList(1L, 2L, 3L), longEncoder);
Dataset<Long> transformedDS = primitiveDS.map(
    (MapFunction<Long, Long>) value -> value + 1L,
    longEncoder);
transformedDS.collect(); 

// DataFrames can be converted to a Dataset by providing a class. Mapping based on name
String path = "examples/src/main/resources/people.json";
Dataset<Person> peopleDS = spark.read().json(path).as(personEncoder);

2.5.与 RDD 互操作

Spark SQL 支持两种不同的方法将现有 RDD 转换为数据集:

  • 第一种方法使用反射来推断包含特定类型对象的 RDD 的模式。
  • 第二种创建数据集的方法是通过一个编程接口,它允许您构建一个模式,然后将其应用到现有的 RDD。

2.5.1.使用反射推断模式

Spark SQL 支持自动将 JavaBean的 RDD 转换为 DataFrame。使用BeanInfo反射获得的 定义表的架构。

// Create an RDD of Person objects from a text file
JavaRDD<Person> peopleRDD = spark.read()
  .textFile("examples/src/main/resources/people.txt")
  .javaRDD()
  .map(line -> {
    String[] parts = line.split(",");
    Person person = new Person();
    person.setName(parts[0]);
    person.setAge(Integer.parseInt(parts[1].trim()));
    return person;
  });

// Apply a schema to an RDD of JavaBeans to get a DataFrame
Dataset<Row> peopleDF = spark.createDataFrame(peopleRDD, Person.class);
// Register the DataFrame as a temporary view
peopleDF.createOrReplaceTempView("people");

// SQL statements can be run by using the sql methods provided by spark
Dataset<Row> teenagersDF = spark.sql("SELECT name FROM people WHERE age BETWEEN 13 AND 19");

// The columns of a row in the result can be accessed by field index
Encoder<String> stringEncoder = Encoders.STRING();
Dataset<String> teenagerNamesByIndexDF = teenagersDF.map(
    (MapFunction<Row, String>) row -> "Name: " + row.getString(0),
    stringEncoder);

// or by field name
Dataset<String> teenagerNamesByFieldDF = teenagersDF.map(
    (MapFunction<Row, String>) row -> "Name: " + row.<String>getAs("name"),
    stringEncoder);

2.5.2.以编程方式指定架构

Dataset<Row>可以通过三个步骤以编程方式创建。

  1. 从原始 RDD创建一个RDD<Row>;
  2. 创建和步骤 1 中创建的 RDD<Row> 相匹配的由 StructTypes 表示的 schema。
  3. 将该 schema 应用于 createDataFrame 方法 。
// Create an RDD
JavaRDD<String> peopleRDD = spark.sparkContext()
  .textFile("examples/src/main/resources/people.txt", 1)
  .toJavaRDD();

// The schema is encoded in a string
String schemaString = "name age";

// Generate the schema based on the string of schema
List<StructField> fields = new ArrayList<>();
for (String fieldName : schemaString.split(" ")) {
  StructField field = DataTypes.createStructField(fieldName, DataTypes.StringType, true);
  fields.add(field);
}
StructType schema = DataTypes.createStructType(fields);

// Convert records of the RDD (people) to Rows
JavaRDD<Row> rowRDD = peopleRDD.map((Function<String, Row>) record -> {
  String[] attributes = record.split(",");
  return RowFactory.create(attributes[0], attributes[1].trim());
});

// Apply the schema to the RDD
Dataset<Row> peopleDataFrame = spark.createDataFrame(rowRDD, schema);

// Creates a temporary view using the DataFrame
peopleDataFrame.createOrReplaceTempView("people");

// SQL can be run over a temporary view created using DataFrames
Dataset<Row> results = spark.sql("SELECT name FROM people");

// The results of SQL queries are DataFrames and support all the normal RDD operations
// The columns of a row in the result can be accessed by field index or by field name
Dataset<String> namesDS = results.map(
    (MapFunction<Row, String>) row -> "Name: " + row.getString(0),
    Encoders.STRING());

3.标量函数

标量函数是每行返回单个值的函数,与聚合函数相反,聚合函数返回一组行的值。Spark SQL 支持多种内置标量函数。它还支持用户定义的标量函数。

4.聚合函数

聚合函数是在一组行上返回单个值的函数。内置聚合函数提供了常用的聚合,如count()、count_distinct()、avg()、max()、min()等。用户不限于预定义的聚合函数,可以创建自己的聚合函数。有关用户定义的聚合函数的更多详细信息,请参阅 用户定义的聚合函数的文档。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值