预览

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的更多相关文章

  1. Spark(七)Spark内存调优

    一.概述 Spark 作为一个基于内存的分布式计算引擎,其内存管理模块在整个系统中扮演着非常重要的角色.理解 Spark 内存管理的基本原理,有助于更好地开发 Spark 应用程序和进行性能调优.本文 ...

  2. spark调优篇-spark on yarn web UI

    spark on yarn 的执行过程在 yarn RM 上无法直接查看,即 http://192.168.10.10:8088,这对于调试程序很不方便,所以需要手动配置 配置方法 1. 配置 spa ...

  3. spark调优篇-Spark ON Yarn 内存管理(汇总)

    本文旨在解析 spark on Yarn 的内存管理,使得 spark 调优思路更加清晰 内存相关参数 spark 是基于内存的计算,spark 调优大部分是针对内存的,了解 spark 内存参数有也 ...

  4. Apache Spark 2.0三种API的传说:RDD、DataFrame和Dataset

    Apache Spark吸引广大社区开发者的一个重要原因是:Apache Spark提供极其简单.易用的APIs,支持跨多种语言(比如:Scala.Java.Python和R)来操作大数据. 本文主要 ...

  5. [Spark SQL] SparkSession、DataFrame 和 DataSet 练习

    本課主題 DataSet 实战 DataSet 实战 SparkSession 是 SparkSQL 的入口,然后可以基于 sparkSession 来获取或者是读取源数据来生存 DataFrameR ...

  6. 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 ...

  7. spark结构化数据处理:Spark SQL、DataFrame和Dataset

    本文讲解Spark的结构化数据处理,主要包括:Spark SQL.DataFrame.Dataset以及Spark SQL服务等相关内容.本文主要讲解Spark 1.6.x的结构化数据处理相关东东,但 ...

  8. Spark学习之路(八)—— Spark SQL 之 DataFrame和Dataset

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

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

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

随机推荐

  1. Haar-like feature和Haar wavelet

    Haar-like features are digital image features used in object recognition. They owe their name to the ...

  2. SharePoint配置网站集的审核设置

    配置网站集的审核设置 您可以使用 Microsoft SharePoint Server 2010 的审核功能来跟踪哪些用户对网站集的网站.内容类型.列表.库.列表项和库文件执行了哪些操作.了解谁对哪 ...

  3. <select>标签默认值设置

    <td> <label>操作类型:</label> <select id="operation_type" class="com ...

  4. vs2015+opencv3.3.1 实现 c++ 双边滤波器(Bilateral Filter)

    #include <opencv2\highgui\highgui.hpp> #include <iostream> #include<vector> using ...

  5. 宏(使用注意事项、主要用途)------c++程序设计原理与实践(进阶篇)

    使用宏的时候一定要小心:在c中没有真正有效的方法来避免使用宏,但宏带有严重的副作用,因为宏不遵守通常的c(或c++)作用域和类型规则——它只是一种文本替换.   宏的使用注意事项: 所以宏名全部大写. ...

  6. ajax-3验证

    $("#formBtn").click(function () { // var regName =/^[\u4e00-\u9fa5]{2,10}$/;//姓名只能是汉字切2-10 ...

  7. 【BZOJ4555】[TJOI&HEOI2016]求和 斯特林数+NTT

    Description 在2016年,佳媛姐姐刚刚学习了第二类斯特林数,非常开心. 现在他想计算这样一个函数的值: S(i, j)表示第二类斯特林数,递推公式为: S(i, j) = j ∗ S(i ...

  8. centos7 yum安装配置redis

    1.设置Redis的仓库地址 yum install epel-release 2.安装redis yum install redis 修改配置文件,监听所有的IP地址 vim /etc/redis. ...

  9. .net core UseHttpsRedirection() 正式环境无效

    莫名其妙遇到这样的问题.这样的配置在本地可以,正式环境就不行了. ··· public void Configure(IApplicationBuilder app, Microsoft.AspNet ...

  10. PowerShell 如何 远程连接【转】

    转自: 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://bobzy.blog.51cto.com/2109336/1181249 ...