spark第七篇:Spark SQL, DataFrame and Dataset Guide
预览
Spark SQL是用来处理结构化数据的Spark模块。有几种与Spark SQL进行交互的方式,包括SQL和Dataset API。
本指南中的所有例子都可以在spark-shell,pyspark shell或者spark R shell中执行。
SQL
Spark SQL的一个用途是执行SQL查询。Spark SQL还可以从现有的Hive中读取数据,本文下面有讲如何配置此功能。运行SQL时,结果会以Dataset/DataFrame返回。You can also interact with the SQL interface using the command-line or over JDBC/ODBC.
Dataset和DataFrame
Dataset是分布式数据集。Dataset是Spark1.6.0中添加的一个新接口,既提供了RDD的优点(强类型,支持lambda表达式),又提供了Spark SQL优化执行引擎的优点。
DataFrame可以从各种来源构建,如结构化数据文件,Hive中的表,外部数据库或者现有的RDD。DataFrame API适用于Scala,Java,Python和R。在Scala和Java中,DataFrame is represented by a Dataset of Rows。在Java API中,DataFrame被表示成Dataset<Row>。
Getting Started
Starting Point:SparkSession
Java API
编程入口是SparkSession类,在spark-sql-xxx.jar中,全类名是org.apache.spark.sql.SparkSession。用SparkSession.builder()方法来创建一个Builder实例(SparkSession内部类),进而调用其多个方法来创建SparkSession实例:
public static void main(String[] args) {
SparkSession spark = SparkSession.builder()
.master("local")
.appName("Java Spark SQL basic example")
.enableHiveSupport()
.getOrCreate();
}
SparkSession类是从Spark2.0.0之后才有的,内置了对Hive的支持,包括用HiveSQL查询、使用Hive UDF以及从Hive表中读取数据。只需调用Builder实例的enableHiveSupport()方法启用Hive支持即可。
创建DataFrame
利用SparkSession实例,可以通过现有的RDD,或者从Hive表,或者从其他数据源来创建DataFrame。
下面例子中,通过JSON文件创建了一个DataFrame:
public static void main(String[] args) {
SparkSession spark = SparkSession.builder()
.master("local")
.appName("Java Spark SQL basic example")
.enableHiveSupport()
.getOrCreate();
Dataset<Row> df = spark.read().json("d:/people.json");
// Displays the content of the DataFrame to stdout
df.show();
}
如上,用Dataset<Row>来表示DataFrame,其中Row全类名是org.apache.spark.sql.Row,在spark-catalyst-xxx.jar中。
通过调用SparkSession实例的read()方法获取DataFrameReader实例,通过该实例的各种方法来读取数据源生成DataFrame实例,如json(path)读取json文件,csv(path)读取csv文件,text(path)读取text文件,jdbc()方法读取关系型数据库的表,orc()方法读取ORC文件(启用hive支持后才能调用),parquet()方法读取Parquet文件。
上例中调用了Dataset<Row>对象的show()方法,该方法会在控制台以表格的形式(带表头的)打印出Dataset对象前20条记录,也就是表格前20行记录。每个单元格内容右对齐,且最多展示20个字符(索引在20及20之后的字符不展示)。
下面是使用Dataset处理结构化数据的例子:
public static void main(String[] args) {
SparkSession spark = SparkSession.builder()
.master("local")
.appName("Java Spark SQL basic example")
.enableHiveSupport()
.getOrCreate();
Dataset<Row> df = spark.read().json("d:/people.json");
// Displays the content of the DataFrame to stdout
df.show();
df.printSchema();
// root
// |-- age: long (nullable = true)
// |-- name: string (nullable = true) // Select only the "name" column
df.select(col("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();
}
注意上例需要引入org.apache.spark.sql.functions.col,在spark-sql-xxx.jar中。
完整的代码示例参见spark-2.2.0-bin-hadoop2.7.tgz解压缩后的examples目录中的JavaSparkSQLExample.java。
上例中使用了Dataset<Row>的以下实例方法:
printSchema():在控制台打印出表头,亦即列名。
select(Column col1, Column col2, ...):传入一个或多个Column对象,返回一个新的Dataset<Row>对象,该对象只包含查询的列。Column是spark-sql jar包中的类,全类名是org.apache.spark.sql.Column,可以通过调用functions.col(String colName)来生成Column实例,其中functions可以省略。
filter(Column condition):返回一个新的Dataset<Row>对象,该对象只包含符合筛选条件的记录。传入的Column对象的作用相当于where条件,例如col("age").lt(18)。
groupBy(Column col1, Column col2, ...):传入要分组的列,返回一个RelationalGroupedDataset对象。
除了简单的列引用和表达式之外,Dataset还有丰富的函数库,包括字符串操作、时间函数及常见的数学运算等。具体可以查看org.apache.spark.sql.functions中的方法。
与数据库交互
Spark SQL也可以通过JDBC与数据库交互。使用DataFrameReader的load()方法或者jdbc()方法。使用load()方法时,需要使用 option()方法或者options()方法指定连接数据库的用户名、密码等属性。而使用jdbc()方法时,只需在properties参数中指定就好了。常用的属性有:
user:数据库用户名
password:user用户对应的密码
url:JDBC URL,如 jdbc:postgresql://192.168.56.11/postgres 其中postgres是库名
driver:驱动类,如 org.postgresql.Driver
dbtable:表名。可以是数据库中现成的表名,如test,也可以是子查询名,如(select * from a inner join b on a.agentNo = b.agentNo) r
fetchsize:The JDBC fetch size, which determines how many rows to fetch per round trip. This can help performance on JDBC drivers which default to low fetch size (eg. Oracle with 10 rows). 仅在读的时候设置。
batchsize:The JDBC batch size, which determines how many rows to insert per round trip. This can help performance on JDBC drivers. 仅在写的时候设置,默认是1000。
isolationLevel:当前连接的事务隔离级别,仅在写的时候设置,默认是READ_UNCOMMITTED。
truncate:当使用SaveMode.Overwrite保存模式时,是否使用truncate表或者删除重建表。默认是false,值为true时表示会使用truncate表,这样比删除重建更快些。仅在写的时候设置。
partitionColumn、lowerBound、upperBound、numPartitions:这4个属性要么都指定,要么都不指定。仅在读的时候设置。分区时设置。
java代码示例:
public static void main(String[] args) {
SparkSession spark = SparkSession.builder()
.appName("heihei")
.master("local[*]")
.enableHiveSupport()
.getOrCreate();
DataFrameReader reader = spark.read();
Properties properties = new Properties();
properties.put("user", "postgres");
properties.put("password", "123456");
properties.put("driver", "org.postgresql.Driver");
properties.put("fetchsize", "10000");
// 从test1表按照一定条件读取数据
String jdbcUrl = "jdbc:postgresql://192.168.56.11/postgres";
Dataset<Row> df = reader.jdbc(jdbcUrl, "(select * from test where age <= 60 order by age desc)t", properties);
DataFrameWriter writer = df.write();
properties.put("truncate", "true");
properties.put("batchsize", "10000");
// 写数据到test2表
writer.mode(SaveMode.Overwrite).jdbc(jdbcUrl, "public.test2", properties);
}
运行SQL查询
SparkSession实例的sql()方法可以运行SQL查询,结果以Dataset<Row>形式返回。sql语句中from关键字后面跟的是临时视图名,临时视图可以通过调用Dataset<Row>实例的 createTempView(String viewName)、createOrReplaceTempView(String viewName)方法来创建(这两个方法都是从2.0.0版本开始才有),通过这两个方法创建的临时视图是SparkSession范围的,如果创建它的SparkSession终止,那么该视图将会消失。同样的,如果在另一个SparkSession中执行该视图的SQL查询,会抛 org.apache.spark.sql.AnalysisException: Table or view not found 异常。如果想在另一个SparkSession中也能正确的执行该视图的SQL查询,则需要创建一个全局临时视图,可以通过调用Dataset<Row>实例的 createGlobalTempView(String viewName)、createOrReplaceGlobalTempView(String viewName)方法创建,前一个方法从2.1.0版本开始才有,后一个方法从2.2.0版本开始才有。全局临时视图和系统保存的数据库global_temp绑定,我们必须使用限定名来引用它,例如,select * from global_temp.view1。
java语言示例:
public static void main(String[] args) {
SparkSession spark = SparkSession.builder()
.master("local")
.appName("Java Spark SQL basic example")
.enableHiveSupport()
.getOrCreate(); Dataset<Row> df = spark.read().json("d:/people.json"); // Displays the content of the DataFrame to stdout
df.show(); // Creates a local temporary view using the given name.
// The lifetime of this temporary view is tied to the [[SparkSession]] that was used to create this Dataset.
df.createOrReplaceTempView("people"); spark.sql("select * from people where age > 20").show(); // Creates a global temporary view using the given name. The lifetime of this temporary view is tied to this Spark application.
df.createOrReplaceGlobalTempView("people"); // Global temporary view is cross-session
spark.newSession().sql("select * from global_temp.people where age > 20").show();
}
利用SparkSession的createDataset()及createDataFrame()的多个重载方法可把RDD、List 转为Dataset<T>、DataFrame(Dataset<Row>)。
聚合
Spark SQL为操作DataFrame内置了很多函数,诸如functions.count(),functions.countDistinct(),functions.avg(),functions.max(),functions.min(),functions.sum()等常用聚合函数,具体可以查看org.apache.spark.sql.functions,在spark-sql-xxx.jar中。
数据源
Spark SQL可以通过DataFrame接口在各种数据源上进行操作。DataFrame可以使用关系转换进行操作???,也可以用来创建临时视图。将DataFrame注册为临时视图允许你对其数据运行SQL查询。本节介绍使用Spark Data Sources加载和保存数据的常用方法。
加载和保存的常用方法
用DataFrameReader的load(String path)方法加载数据,用DataFrameWriter的save(String path)方法保存数据。
注意load()方法默认是加载parquet文件的,在加载其他格式的文件时,需要在load前先调用format(String source)方法指定源数据格式。同理,save()方法也是默认写成parquet文件,如果要写成其他格式的文件,需要在save()前调用format(String source)指定文件格式。对于常用的数据格式,如json、csv、txt等,Spark提供了优化的方法来替代load()、save()方法,如DataFrameReader和DataFrameWriter的json()、parquet()、jdbc()、orc()、csv()、text()。实际上,观察源码可发现,DataFrameReader的json()就是format("json").load(),DataFrameWriter的json()就是format("json").save()。DataFrameReader的jdbc()就是format("jdbc").load(),DataFrameWriter的jdbc()就是format("jdbc").save(),等等,其他方法也是这样,都等于format().load()/save()。此外,数据源和数据最终保存的地方可以不一样,如数据源是json文件,但是数据最终保存到文本文件中,等等。
Java代码
public static void main(String[] args) {
SparkSession spark = SparkSession.builder()
.master("local")
.appName("Java Spark SQL basic example")
.enableHiveSupport()
.getOrCreate();
Dataset<Row> peopleDF = spark.read().json("d:/people.json");
peopleDF.select("name").write().text("d:/people.text");
}
直接在文件上运行SQL
除了用DataFrameReader的各种方法将文件内容读取到DataFrame中查询外,你还可以直接对文件进行SQL查询。
Java代码
public static void main(String[] args) {
SparkSession spark = SparkSession.builder()
.master("local")
.appName("Java Spark SQL basic example")
.enableHiveSupport()
.getOrCreate();
Dataset<Row> sqlDF = spark.sql("SELECT * FROM json.`d:/people.json`");
sqlDF.show();
}
select * from json.`d:/people.json` 有2个注意点:
1、需要在文件前面用关键字指定文件格式,如json、csv等
2、文件名不是用单引号包裹,而是用tab键上面的那个键对应的标点符号包裹
保存模式
DataFrameWriter的save(String path)方法,默认保存模式是SaveMode.ErrorIfExists,这种模式下,当path已存在时,会报错。其他模式有SaveMode.Append、SaveMode.Overwrite、SaveMode.Ignore。可以用DataFrameWriter的mode(SaveMode saveMode)方法指定。
保存到持久化表
也可以使用DataFrameWriter的saveAsTable(String tableName)方法将DataFrame作为持久表保存。此时,hive的部署不是必需的。可以使用SparkSession的table(String tableName)方法读取该表数据到DataFrame中。
假如部署了hive,且在项目的resources目录(本地开发时)或SPARK_HOME的conf目录(实际生产时)中引入了hive-site.xml文件,则spark会把元数据放在hive的metastore中,把数据放在hdfs中。
假如没有部署hive,则spark会把元数据放在本地文件系统metastore_db目录中,把数据放在本地文件系统spark-warehouse目录中(由spark.sql.warehouse.dir指定,默认值是spark应用启动目录中的spark-warehouse目录,可以通过spark.conf()修改)。
假如是文件源,则在调用saveAsTable()前可以调用option("path", "/some/path")指定表数据路径(注意,不是元数据路径)。
Starting from Spark 2.1, persistent datasource tables have per-partition metadata stored in the Hive metastore. This brings several benefits:
①Since the metastore can return only necessary partitions for a query, discovering all the partitions on the first query to the table is no longer needed.
②Hive DDLs such as ALTER TABLE PARTITION ... SET LOCATION are now available for tables created with the Datasource API.
Note that partition information is not gathered by default when creating external datasource tables (those with a path option). To sync the partition information in the metastore, you can invoke MSCK REPAIR TABLE.
分桶、排序、分区
假如是文件源,则在输出的时候可以分桶、排序、分区。非文件源不支持分桶、排序、分区操作,否则会报
Exception in thread "dag-scheduler-event-loop" java.lang.StackOverflowError
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1427)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
java代码示例:
public static void main(String[] args) {
System.setProperty("hadoop.home.dir", "D:/Users/KOUSHENGRUI976/winutils-master/winutils-master/hadoop-2.6.4");
SparkSession spark = SparkSession.builder()
.appName("heihei")
.master("local[*]")
.enableHiveSupport()
.getOrCreate();
DataFrameReader reader = spark.read();
Dataset<Row> df = reader.json("d:/data");
spark.sql("drop table if exists people"); DataFrameWriter<Row> writer = df.write();
writer.mode(SaveMode.Overwrite)
.format("json")
.bucketBy(5, "name")
.sortBy("age")
.partitionBy("province")
.saveAsTable("people");
}
需要注意的是:bucketBy()及sortBy()不能和save()、json()、parquet()、text()、csv()、orc()不能与共用,否则会报org.apache.spark.sql.AnalysisException: 'save' does not support bucketing right now。partitionBy()无所谓。
hive tables
saprk.sql()支持任何hive语句,如
spark.sql("create table if not exists pokes (foo int, bar string)");
spark.sql("load data local inpath 'd:/data/kv1.txt' overwrite into table pokes");
java代码示例:
public static void main(String[] args) {
SparkSession spark = SparkSession.builder()
.appName("heihei").master("local[*]")
.enableHiveSupport()
.getOrCreate();
spark.sql("use default");
spark.sql("create table if not exists tests (id string, name string, password string) stored as textfile");
Dataset<Row> df = spark.read().json("d:/2.json");
df.createOrReplaceTempView("tt");
spark.sql("insert into table tests select * from tt"); // 从hive表中读取数据
spark.sql("select * from tests").write().mode(SaveMode.Overwrite).json("d:/3.json");
}
模拟场景,读取1.json文件,内容是两行json字符串
用json()方法读取
spark第七篇:Spark SQL, DataFrame and Dataset Guide的更多相关文章
- Spark(七)Spark内存调优
一.概述 Spark 作为一个基于内存的分布式计算引擎,其内存管理模块在整个系统中扮演着非常重要的角色.理解 Spark 内存管理的基本原理,有助于更好地开发 Spark 应用程序和进行性能调优.本文 ...
- spark调优篇-spark on yarn web UI
spark on yarn 的执行过程在 yarn RM 上无法直接查看,即 http://192.168.10.10:8088,这对于调试程序很不方便,所以需要手动配置 配置方法 1. 配置 spa ...
- spark调优篇-Spark ON Yarn 内存管理(汇总)
本文旨在解析 spark on Yarn 的内存管理,使得 spark 调优思路更加清晰 内存相关参数 spark 是基于内存的计算,spark 调优大部分是针对内存的,了解 spark 内存参数有也 ...
- Apache Spark 2.0三种API的传说:RDD、DataFrame和Dataset
Apache Spark吸引广大社区开发者的一个重要原因是:Apache Spark提供极其简单.易用的APIs,支持跨多种语言(比如:Scala.Java.Python和R)来操作大数据. 本文主要 ...
- [Spark SQL] SparkSession、DataFrame 和 DataSet 练习
本課主題 DataSet 实战 DataSet 实战 SparkSession 是 SparkSQL 的入口,然后可以基于 sparkSession 来获取或者是读取源数据来生存 DataFrameR ...
- APACHE SPARK 2.0 API IMPROVEMENTS: RDD, DATAFRAME, DATASET AND SQL
What’s New, What’s Changed and How to get Started. Are you ready for Apache Spark 2.0? If you are ju ...
- spark结构化数据处理:Spark SQL、DataFrame和Dataset
本文讲解Spark的结构化数据处理,主要包括:Spark SQL.DataFrame.Dataset以及Spark SQL服务等相关内容.本文主要讲解Spark 1.6.x的结构化数据处理相关东东,但 ...
- Spark学习之路(八)—— Spark SQL 之 DataFrame和Dataset
一.Spark SQL简介 Spark SQL是Spark中的一个子模块,主要用于操作结构化数据.它具有以下特点: 能够将SQL查询与Spark程序无缝混合,允许您使用SQL或DataFrame AP ...
- Spark 系列(八)—— Spark SQL 之 DataFrame 和 Dataset
一.Spark SQL简介 Spark SQL 是 Spark 中的一个子模块,主要用于操作结构化数据.它具有以下特点: 能够将 SQL 查询与 Spark 程序无缝混合,允许您使用 SQL 或 Da ...
随机推荐
- mysql_5.6内存过高问题解决
MySQL 5.6安装完之后,每过一段时间就会莫名其妙挂掉.而且还很难启动.非要重启服务器,才能拉起mysql. 后来分析是由于mysql启动后内存过高,跑一段时间就会由于内存不足而被杀死. 今天分析 ...
- Maven类包冲突终极三大解决技巧 mvn dependency:tree
Maven对于新手来说是<步步惊心>,因为它包罗万象,博大精深,因为当你初来乍到时,你就像一个进入森林的陌生访客一样迷茫. Maven对于老手来说是<真爱配方>,因为它无所不能 ...
- (十)ASP.NET自定义用户控件(3)
using HX.DHL.EIP.Services.Def.Localization; using HX.DHL.EIP.Web.Framework; using System; using Syst ...
- WPF 控件库——带有惯性的ScrollViewer
WPF 控件库系列博文地址: WPF 控件库——仿制Chrome的ColorPicker WPF 控件库——仿制Windows10的进度条 WPF 控件库——轮播控件 WPF 控件库——带有惯性的Sc ...
- ZED 常用资料汇总
Calibration file Location: /usr/local/zed/settings/SN10027507.conf I suggest the calibration file sh ...
- 关于spring xml文件中的xmlns,xsi:schemaLocation
链接:https://blog.csdn.net/u010571844/article/details/50767151 使用spring也有一段时间了,配置文件也见了不少了,但是发现配置文件的bea ...
- Jmeter_Beanshell_使用Java处理JSON块
版权声明:本文为博主原创文章,转载请注明出处. [环境] ①Jmeter版本:3.2,JDK:1.8 ②前置条件:将json.jar包置于..\apache-jmeter-3.2\lib\下,并将该j ...
- leecode刷题(6)-- 两个数组的交集II
leecode刷题(6)-- 两个数组的交集II 两个数组的交集II 描述: 给定两个数组,编写一个函数来计算它们的交集. 示例: 输入: nums1 = [1,2,2,1], nums2 = [2, ...
- Ubuntu 安装后的配置及美化(一)
Ubuntu 安装后的配置及美化(一) 记录一下 完成后的主界面. 配置 1.更新源为阿里云 找到 软件和更新 选项,更新源为阿里云的源. 在 其他软件 中将 Canonical合作伙伴 打上勾. 然 ...
- 【ARC062F】 Painting Graphs with AtCoDeer 点双连通分量+polya定理
Description 给定一张N点M边的无向图,每条边要染一个编号在1到K的颜色. 你可以对一张染色了的图进行若干次操作,每次操作形如,在图中选择一个简单环(即不经过相同点的环),并且将其颜色逆时针 ...