一、创建DataFrame和Dataset

1.1 创建DataFrame

Spark 中所有功能的入口点是 SparkSession,可以使用 SparkSession.builder() 创建。创建后应用程序就可以从现有 RDD,Hive 表或 Spark 数据源创建 DataFrame。示例如下:

val spark = SparkSession.builder().appName("Spark-SQL").master("local[2]").getOrCreate()
val df = spark.read.json("/usr/file/json/emp.json")
df.show()

// 建议在进行 spark SQL 编程前导入下面的隐式转换,因为 DataFrames 和 dataSets 中很多操作都依赖了隐式转换
import spark.implicits._

可以使用 spark-shell 进行测试,需要注意的是 spark-shell 启动后会自动创建一个名为 sparkSparkSession,在命令行中可以直接引用即可:

1.2 创建Dataset

Spark 支持由内部数据集和外部数据集来创建 DataSet,其创建方式分别如下:

1. 由外部数据集创建

// 1.需要导入隐式转换
import spark.implicits._

// 2.创建 case class,等价于 Java Bean
case class Emp(ename: String, comm: Double, deptno: Long, empno: Long,
               hiredate: String, job: String, mgr: Long, sal: Double)

// 3.由外部数据集创建 Datasets
val ds = spark.read.json("/usr/file/emp.json").as[Emp]
ds.show()

2. 由内部数据集创建

// 1.需要导入隐式转换
import spark.implicits._

// 2.创建 case class,等价于 Java Bean
case class Emp(ename: String, comm: Double, deptno: Long, empno: Long,
               hiredate: String, job: String, mgr: Long, sal: Double)

// 3.由内部数据集创建 Datasets
val caseClassDS = Seq(Emp("ALLEN", 300.0, 30, 7499, "1981-02-20 00:00:00", "SALESMAN", 7698, 1600.0),
                      Emp("JONES", 300.0, 30, 7499, "1981-02-20 00:00:00", "SALESMAN", 7698, 1600.0))
                    .toDS()
caseClassDS.show()

1.3 由RDD创建DataFrame

Spark 支持两种方式把 RDD 转换为 DataFrame,分别是使用反射推断和指定 Schema 转换:

1. 使用反射推断

// 1.导入隐式转换
import spark.implicits._

// 2.创建部门类
case class Dept(deptno: Long, dname: String, loc: String)

// 3.创建 RDD 并转换为 dataSet
val rddToDS = spark.sparkContext
  .textFile("/usr/file/dept.txt")
  .map(_.split("\t"))
  .map(line => Dept(line(0).trim.toLong, line(1), line(2)))
  .toDS()  // 如果调用 toDF() 则转换为 dataFrame 

2. 以编程方式指定Schema

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

// 1.定义每个列的列类型
val fields = Array(StructField("deptno", LongType, nullable = true),
                   StructField("dname", StringType, nullable = true),
                   StructField("loc", StringType, nullable = true))

// 2.创建 schema
val schema = StructType(fields)

// 3.创建 RDD
val deptRDD = spark.sparkContext.textFile("/usr/file/dept.txt")
val rowRDD = deptRDD.map(_.split("\t")).map(line => Row(line(0).toLong, line(1), line(2)))

// 4.将 RDD 转换为 dataFrame
val deptDF = spark.createDataFrame(rowRDD, schema)
deptDF.show()

1.4 DataFrames与Datasets互相转换

Spark 提供了非常简单的转换方法用于 DataFrame 与 Dataset 间的互相转换,示例如下:

# DataFrames转Datasets
scala> df.as[Emp]
res1: org.apache.spark.sql.Dataset[Emp] = [COMM: double, DEPTNO: bigint ... 6 more fields]

# Datasets转DataFrames
scala> ds.toDF()
res2: org.apache.spark.sql.DataFrame = [COMM: double, DEPTNO: bigint ... 6 more fields]

二、Columns列操作

2.1 引用列

Spark 支持多种方法来构造和引用列,最简单的是使用 col()column() 函数。

col("colName")
column("colName")

// 对于 Scala 语言而言,还可以使用$"myColumn"和'myColumn 这两种语法糖进行引用。
df.select($"ename", $"job").show()
df.select('ename, 'job).show()

2.2 新增列

// 基于已有列值新增列
df.withColumn("upSal",$"sal"+1000)
// 基于固定值新增列
df.withColumn("intCol",lit(1000))

2.3 删除列

// 支持删除多个列
df.drop("comm","job").show()

2.4 重命名列

df.withColumnRenamed("comm", "common").show()

需要说明的是新增,删除,重命名列都会产生新的 DataFrame,原来的 DataFrame 不会被改变。

三、使用Structured API进行基本查询

// 1.查询员工姓名及工作
df.select($"ename", $"job").show()

// 2.filter 查询工资大于 2000 的员工信息
df.filter($"sal" > 2000).show()

// 3.orderBy 按照部门编号降序,工资升序进行查询
df.orderBy(desc("deptno"), asc("sal")).show()

// 4.limit 查询工资最高的 3 名员工的信息
df.orderBy(desc("sal")).limit(3).show()

// 5.distinct 查询所有部门编号
df.select("deptno").distinct().show()

// 6.groupBy 分组统计部门人数
df.groupBy("deptno").count().show()

四、使用Spark SQL进行基本查询

4.1 Spark SQL基本使用

// 1.首先需要将 DataFrame 注册为临时视图
df.createOrReplaceTempView("emp")

// 2.查询员工姓名及工作
spark.sql("SELECT ename,job FROM emp").show()

// 3.查询工资大于 2000 的员工信息
spark.sql("SELECT * FROM emp where sal > 2000").show()

// 4.orderBy 按照部门编号降序,工资升序进行查询
spark.sql("SELECT * FROM emp ORDER BY deptno DESC,sal ASC").show()

// 5.limit  查询工资最高的 3 名员工的信息
spark.sql("SELECT * FROM emp ORDER BY sal DESC LIMIT 3").show()

// 6.distinct 查询所有部门编号
spark.sql("SELECT DISTINCT(deptno) FROM emp").show()

// 7.分组统计部门人数
spark.sql("SELECT deptno,count(ename) FROM emp group by deptno").show()

4.2 全局临时视图

上面使用 createOrReplaceTempView 创建的是会话临时视图,它的生命周期仅限于会话范围,会随会话的结束而结束。

你也可以使用 createGlobalTempView 创建全局临时视图,全局临时视图可以在所有会话之间共享,并直到整个 Spark 应用程序终止后才会消失。全局临时视图被定义在内置的 global_temp 数据库下,需要使用限定名称进行引用,如 SELECT * FROM global_temp.view1

// 注册为全局临时视图
df.createGlobalTempView("gemp")

// 使用限定名称进行引用
spark.sql("SELECT ename,job FROM global_temp.gemp").show()

参考资料

Spark SQL, DataFrames and Datasets Guide > Getting Started

更多大数据系列文章可以参见 GitHub 开源项目大数据入门指南

Spark 系列(九)—— Spark SQL 之 Structured API的更多相关文章

  1. Spark学习之路(九)—— Spark SQL 之 Structured API

    一.创建DataFrame和Dataset 1.1 创建DataFrame Spark中所有功能的入口点是SparkSession,可以使用SparkSession.builder()创建.创建后应用 ...

  2. Spark系列(九)DAGScheduler工作原理

    以wordcount为示例进行深入分析 1  33  ) { 46        logInfo("Submitting " + tasks.size + " missi ...

  3. Spark系列—01 Spark集群的安装

    一.概述 关于Spark是什么.为什么学习Spark等等,在这就不说了,直接看这个:http://spark.apache.org, 我就直接说一下Spark的一些优势: 1.快 与Hadoop的Ma ...

  4. Spark系列—02 Spark程序牛刀小试

    一.执行第一个Spark程序 1.执行程序 我们执行一下Spark自带的一个例子,利用蒙特·卡罗算法求PI: 启动Spark集群后,可以在集群的任何一台机器上执行一下命令: /home/spark/s ...

  5. Spark SQL 编程API入门系列之Spark SQL支持的API

    不多说,直接上干货! Spark SQL支持的API SQL DataFrame(推荐方式,也能执行SQL) Dataset(还在发展) SQL SQL 支持basic SQL syntax/Hive ...

  6. Spark 系列(八)—— Spark SQL 之 DataFrame 和 Dataset

    一.Spark SQL简介 Spark SQL 是 Spark 中的一个子模块,主要用于操作结构化数据.它具有以下特点: 能够将 SQL 查询与 Spark 程序无缝混合,允许您使用 SQL 或 Da ...

  7. 小白学习Spark系列四:RDD踩坑总结(scala+spark2.1 sql常用方法)

    初次尝试用 Spark+scala 完成项目的重构,由于两者之前都没接触过,所以边学边用的过程大多艰难.首先面临的是如何快速上手,然后是代码调优.性能调优.本章主要记录自己在项目中遇到的问题以及解决方 ...

  8. Spark SQL概念学习系列之Spark SQL概述

    很多人一个误区,Spark SQL重点不是在SQL啊,而是在结构化数据处理! Spark SQL结构化数据处理 概要: 01 Spark SQL概述 02 Spark SQL基本原理 03 Spark ...

  9. Spark SQL概念学习系列之Spark SQL的简介(一)

    Spark SQL提供在大数据上的SQL查询功能,类似于Shark在整个生态系统的角色,它们可以统称为SQL on Spark. 之前,Shark的查询编译和优化器依赖于Hive,使得Shark不得不 ...

随机推荐

  1. scrapy 发post请求

    可以使用 yield scrapy.FormRequest(url, formdata, callback)方法发送POST请求. 如果希望程序执行一开始就发送POST请求,可以重写Spider类的s ...

  2. JVM结构的简单梳理

    #cnblogs_post_body img { width: 500px; height: auto; } JVM是什么 JVM的基本特性 JVM的流程结构 1. Java编译(Java Compi ...

  3. 跨站脚本攻击(存储型xss)笔记(二)

    测试目标字段:页面下方的红色框位置. 由于编辑状态是编辑器,所以有可能出现跨站! 我插了个input然而并没有当代码执行 可能有些测试人员就认为被过滤掉了,因为尝试了各种尖括号.js事件.转义.编码等 ...

  4. 【CYH-02】NOIp考砸后虐题赛:成绩:题解

    这道题挺送水了吧... 两种做法. 其实空间都不需要那么大,我来提交界面一看一堆MLE的,于是还是良心的放开了时限. 这么简单,就不做解释了. 下面放出几种代码. 代码: 两个数组: #include ...

  5. Button事件的三种实现方法

    onclick事件的定义方法,分为三种,分别为在xml中进行指定方法:在Actitivy中new出一个OnClickListenner():实现OnClickListener接口三种方式. 1.在xm ...

  6. 我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=3cp8ng15g94wc

    我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=3cp8ng15g94wc

  7. Hadoop值Partition分区

    分区操作 为什么要分区? 要求将统计结果按照条件输出到不同文件中(分区).比如:将统计结果按 照手机归属地不同省份输出到不同文件中(分区) 默认 partition 分区 /** 源码中:numRed ...

  8. c实现生产者消费者问题。 windows下。

    #include <stdio.h>#include <windows.h> #define P(S) WaitForSingleObject(S,INFINITE)//定义W ...

  9. jquery:为动态加载的元素绑定事件

    最近在做项目的时候发现的一个问题,通过ajax动态加载出来的一个button值绑定不了点击事件.我使用的是datatables这款表单插件,表单内容是通过ajax动态渲染出来的. 解决方案: 通过Go ...

  10. ArcGIS API For JavaScript 开发(一)环境搭建

    标签:B/S结构开发,Asp.Net开发,WebGIS开发 前言:为什么写这个,一是学习:二是分享,共同进步,毕竟也是在这个园子里学到了很多: (一)环境搭建 集成开发环境:VS2013 Ultima ...