第九章 Spark SQL

Spark SQL提供三大功能:

1、可以从各种结构化数据源(例如JSON、Hive、Parquet等)中读取数据

2、Spark SQL不仅支持在Spark程序内使用SQL语句进行数据查询,也支持外部工具链接SQL进行查询。

3、支持SQL与常规python/java/scala代码高度整合,包括连接RDD与SQL表、公开的自定义SQL函数接口。

SchemaRDD

用来存放ROw对象的RDD,每个ROW对象代表一行记录。SchemaRDD还包含记录的结构信息(即数据字段)。SchemaRDD支持SQL查询。

一、连接Spark SQL

引入Spark SQL 需要添加一些额外依赖,这种分离机制使得Spark内核的编译无需依赖大量额外的包

Apache Hive 是 Hadoop上的SQL搜索引擎,Spark SQL编译时可以包含Hive支持,也可以不包含。Hive支持的Spark SQL支持:Hive表访问,UDF(用户自定义函数)、SerDe(序列化格式和反序列化格式)以及Hive查询语言。

初始化Spark SQL
Scala中SQL的import生命
// 导入Spark SQL
import org.apache.spark.sql.hive.HiveContext
// 如果不能使用hive依赖的话
import org.apache.spark.sql.SQLContext

在创建出HiveContext的实例之后,需要加入必要的隐式转换。

//在Scala中SQL需要导入隐式转换支持
//创建Spark SQL 的HiveContext
val hiveCtx = ...
//导入隐式转换支持
import hiveCtx._

添加好import 声明后,需要创建一个HiveContext对象。如果无法引入Hive依赖,就创建出一个SQLContext对象作为SQL的上下文环境。这两个类都需要传入一个SparkContext对象作为运行的基础。

//在Scala中创建SQL上下文环境
val sc = new SparkContext(...)
val hiveCtx = new HiveContext(sc)
基本查询示例
//从JSON中读取数据
val input = hiveCtx.jsonFile(inputFile)
//注册输入的数据为tweets
input.registerTempTable("tweets")
//依据retweetCount(转发计数)选出推文
val topTweets = hiveCtx.sql("SELECT text,retweetCount FROM tweets ORDER BY retweetCount LIMIT 10")
SchemaRDD(DATAFrame)

1、读取数据和执行操作都会返回SchemaRDD,SchemaRDD是一个由Row对象组成的RDD,附带包含每列数据类型的结构信息。

2、SchemaRDD是RDD,可以对其应用已有的RDD转换操作,比如map()和filter()

3、可以把SchemaRDD注册为临时表,使用HiveContext.sql或SQLContext.sql对其进行查询。可以通过ScheamRDD的registerTempTable进行注册。

4、SchemaRDD可以存储的数据类型

Spark SQL/HiveQL类型Scala类型Python类型
TINYINTByteint/Long(-128 ~ 127)
SMALLINTShortint/long(-32768 ~ 32767)
INTIntint/Long
BIGINTLonglong
FLOATFloatfloat
DOUBLEDoublefloat
DECIMALscala.math.BigDecimaldecimal.Decimal
STRINGStringstring
BINARYArray[Byte]bytearray
BOOLEANBooleanbool
TIMESTAMPjava.sql.TimeStampdate.datetime
ARRAYSeqlist、tuple或array
MAPMapdict
STRUCTRowRow
COL1_TYPE,…>

COL1_TYPE,…>为结构体,在Spark SQL中直接被表示为其他的Row对象。所有这些复杂类型都可以互相嵌套。

Row对象可以使用get函数,将给定序号,返回一个Object类型并转化

//在Scala中访问topTweet这个SchemaRDD中的text列
val topTweetText = topTweets.map(row => row.getString())
缓存

为了节省内存,SQL使用hiveCtx.cacheTable(“tableName”)方法, 缓存数据。缓存下来的表只会在驱动器程序的生命周期保留在内存中,如果驱动器进程退出吗,就需要重新缓存数据。

命令:CACHE TABLEtablename 缓存表格/ UNCACHE TABLEtablename 删除已有缓存

读取和存储数据

SQL 在读取数据时,可以只读取需要数据

Apache Hive

当从Hive中读取数据时,Spark SQL支持任何Hive支持的存储格式(SerDe),包括文本文件、RCFiles、ORC、Parquet、Avro以及Protocol Buffer。

使用scala从Hive读取
import org.apache.spark.sql.hive.HiveContext

val hiveCtx = new HiveContext(sc)
val rows = hiveCtx.sql(SELECT key, value FROM mytable)
val keys = rows.map(row => row.getInt(0))
Parquet

Parquet可以高效存储具有嵌套字段的记录。Parquet常在Hadoop生态圈中被使用,他也支持Spark SQL的全部数据类型。

//python中的Parquet数据读取
# 从一个有name和favouriteAnimal字段的Parquet文件中读取数据
rows = hiveCtx.parquetFile(parquetFile)
names = rows.map(lambda row: row.name)
print "Everyone"
print names.collect(
#Python中的Parquet数据查询
# 寻找熊猫爱好者
tbl = rows.registerTempTable("people")
pandaFriends = hiveCtx.sql("SELECT name FROM people WHERE favouriteAnimal =
\"panda\"")
print "Panda friends"
print pandaFriends.map(lambda row: row.name).collect()
#Python中Parquet文件保存
pandaFriends.saveAsParquetFile("hdfs://...")
JSON
#Scala中读取JSON数据
val input = hiveCtx.jsonFile(inputFile)

#用SQL查询嵌套数据以及数组元素
select hashtagEntities[0].text from tweets LIMIT 1;
基于RDD

DATAFrame可以基于RDD创建

//在Scala中基于case class 创建SchemaRDD
case class HappyPerson(handle: String, favouriteBeverage: String)
...
// 创建了一个人的对象,并且把它转成SchemaRDD
val happyPeopleRDD = sc.parallelize(List(HappyPerson("holden", "coffee")))
// 注意:此处发生了隐式转换
// 该转换等价于sqlCtx.createSchemaRDD(happyPeopleRDD)
happyPeopleRDD.registerTempTable("happy_people")
JDBC/ODBC 服务器

Spark SQL 也提供JDBC链接支持

使用Beeline

在Beeline客户端中,你可以使用标准的HiveQL命令来创建、列举以及查询数据表。

# 读取数据表
> CREATE TABLE IF NOT EXISTS mytable (key INT, value STRING)
ROW FORMAT DELIMITED FIELDS TERMINATED BY‘,’;
> LOAD DATA LOCAL INPATH‘learning-spark-examples/files/int_string.csv’
INTO TABLE mytable
#列举数据表
> SHOW TABLES;
mytable
Time taken: 0.052 second
Spark SQL shell执行EXPLAIN
spark-sql> EXPLAIN SELECT * FROM mytable where key = 1;
== Physical Plan ==
Filter (key#16 = 1)
HiveTableScan [key#16,value#17], (MetastoreRelation default, mytable, None), None
Time taken: 0.551 seconds
用户自定义函数

用户自定义函数,也叫做UDF,可以让用户注册自定义函数,并在SQL中调用。

Spark SQL UDF

可以使用Spark支持的编程语言编写好函数,然后通过Spark SQL内建的方法传递进来,非常便捷的注册UDF,scala和python中,可以利用语言原生的函数和lambda语法支持,在Java中,需要扩展对应的UDF类。

//Scala版本的字符串长度UDF
registerFunction("strLenScala", (_: String).length)
val tweetLength = hiveCtx.sql("SELECT strLenScala('tweet') FROM tweets LIMIT 10")

Spark SQL 也支持 Hive UDF,标准的Hive UDF已经自动包含在Spark SQL中。如需支持自定义Hive UDF,需要确保UDF的JAR包已经包含在应用中。

如果使用Hive UDF,应该使用Hive Context,调用hiveCtx.sql(“CREATE TEMPORARY FUNCTION name AS class.function”)

Spark SQL性能

谓词下推 可以让Spark 如果低层数据存储支持只读取一个范围内的记录,SQL将查询中的一部分工作“下移”到查询引擎上,从而大大减少需要读取的数据。

选项默认值用途
spark.sql.codegenfalse设为true时,会把查询语句编译为Java二进制代码,提高大型查询的性能,但小效果查询时会变慢
spark.sql.inMemoryColummarStorage.compressedfalse自动对内存中的列式存储进行压缩
spark.sql.inMemoryColumnarStorage.batchSize1000列式存储的每个批处理的大小
spark.sql.parquet.compression.codecsnappy使用哪种编码器,选项包括:uncompress/snappy/gzip/lzo
//在scala中打开codegen选项的代码
conf.set("spark.sql.codegen","true")
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值