【导读:数据是二十一世纪的石油,蕴含巨大价值,这是·情报通·大数据技术系列第[82]篇文章,欢迎阅读和收藏】
1 背景介绍
SparkSQL 引入了一种新的 RDD —— SchemaRDD , SchemaRDD 由行对象( Row )以及描述行对象中每列数据类型的 Schema 组成; SchemaRDD 很像传统数据库中的表。 SchemaRDD 可以通过 RDD 、 Parquet 文件、 JSON 文件、或者通过使用 hiveql 查询 hive 数据来建立。 SchemaRDD 除了可以和 RDD 一样操作外,还可以通过 registerTempTable 注册成临时表,然后通过 SQL 语句进行操作。
值得注意的是:
l Spark1.1 使用 registerTempTable 代替 1.0 版本的 registerAsTable
l Spark1.1 在 hiveContext 中, hql() 将被弃用, sql() 将代替 hql() 来提交查询语句,统一了接口。
l 使用 registerTempTable 注册表是一个临时表,生命周期只在所定义的 sqlContext 或 hiveContext 实例之中。换而言之,在一个 sqlContext (或 hiveContext )中 registerTempTable 的表不能在另一个 sqlContext (或 hiveContext )中使用。
l Spark1.1 提供了语法解析器选项 spark.sql.dialect ,就目前而言, Spark1.1 提供了两种语法解析器: sql 语法解析器和 hiveql 语法解析器。
l sqlContext 现在只支持 sql 语法解析器( SQL-92 语法)
l hiveContext 现在支持 sql 语法解析器和 hivesql 语法解析器,默认为 hivesql 语法解析器,用户可以通过配置切换成 sql 语法解析器,来运行 hiveql 不支持的语法,如 select 1 。
切换可以通过下列方式完成:
l 在 sqlContexet 中使用 setconf 配置 spark.sql.dialect
l 在 hiveContexet 中使用 setconf 配置 spark.sql.dialect
l 在 sql 命令中使用 set spark.sql.dialect=value
SparkSQL1.1 对数据的查询分成了 2 个分支: sqlContext 和 hiveContext 。至于两者之间的关系, hiveSQL 继承了 sqlContext ,所以拥有 sqlontext 的特性之外,还拥有自身的特性(最大的特性就是支持 hive )。
2 sqlContext
2.1 使用 Case Class 定义 RDD
对于 Case Class 方式,首先要定义 Case Class ,在 RDD 的 Transform 过程中使用 Case Class 可以隐式转化成 SchemaRDD ,然后再使用 registerTempTable 注册成表。注册成表后就可以在 sqlContext 对表进行操作,如 select 、 insert 、 join 等。注意, case class 可以是嵌套的,也可以使用类似 Sequences 或 Arrays 之类复杂的数据类型。
应用案例:
scala> val sqlContext = new org.apache.spark.sql.SQLContext(sc)
scala> import sqlContext.implicits._
scala> case class Person(name:String,age:Int)
scala> val people=sc.textFile("hdfs://cloud25:9000/data/people.txt").map(_.split(",")).map(p=>Person(p(0),p(1).trim.toInt)).toDF()
scala> teenagers.map(t => "Name: " + t(0)).collect().foreach(println)
2.2 Parquest 应用案例
sqlContext 可以读取 parquet 文件,由于 parquet 文件中保留了 schema 的信息,所以不需要使用 case class 来隐式转换。 sqlContext 读入 parquet 文件后直接转换成 SchemaRDD ,也可以将 SchemaRDD 保存成 parquet 文件格式。
应用案例:
scala> import sqlContext.implicits._
scala> sqlContext.setConf("spark.sql.parquet.binaryAsString", "true") // 解决文件中 parquet 中 binary 字段的问题
scala> val wikiData = sqlContext.parquetFile("hdfs://cloud25:9000/data/wiki_parquet").toDF()
scala> wikiData.count()
scala> wikiData.registerTempTable("wikidata")
scala> val countResult = sqlContext.sql("SELECT COUNT(*) FROM wikiData").collect()
scala> val queryResult= sqlContext.sql("SELECT username, COUNT(*) AS cnt FROM wikiData WHERE username <> '' GROUP BY username ORDER BY cnt DESC LIMIT 10")
scala> queryResult.collect().foreach(println)
2.3 Join 应用案例
sqlContext 可以从多个种类的 SchemaRDD 中执行 join 操作
应用案例:
scala> val sqlContext = new org.apache.spark.sql.SQLContext(sc)
scala> import sqlContext.implicits._
scala> case class Person(name:String,age:Int)
scala> val people=sc.textFile("hdfs://cloud25:9000/data/people.txt").map(_.split(",")).map(p=>Person(p(0),p(1).trim.toInt)).toDF()
scala> people.saveAsParquetFile("hdfs://cloud25:9000/data/people.parquet")
scala> val parquetFile = sqlContext.parquetFile("hdfs://cloud25:9000/data/people.parquet")
scala> people.registerTempTable("people")
scala> parquetFile.registerTempTable("parquetFile")
scala> val jointbls = sqlContext.sql("SELECT people.name FROM people join parquetFile where people.name=parquetFile.name")
scala> jointbls.collect.foreach(println)
3 hiveContext
SparkSQL 1.4.1 版本,可以动过两种方式与 hive 集成,第一种是使用已经部署好的 metastore ,如果使用这种方式需要在 spark 中添加 hive 的相关配置,第二种 : 如果没有配置相关的信息, hiveContext 会在当前目录自己创建 metadata_db 以及 warehouse
配置过程
以下配置流程仅仅针对描述中的第一种情况(使用已有 metastore )
l 后台启动 metasore 服务
l 创建 /opt/cloud/spark-1.4.1-bin-hadoop2.6/conf/hive-site.xml 文件,并编辑内容如下:
hive.metastore.uris
thrift://cloud25:9083
Thrift URI for the remote metastore. Used by metastore client to connect to remote metastore.
启动 spark-shell:
./spark-shell --master=spark://cloud25:7077 --executor-memory=2g
应用案例:
l 使用已有 metastore 的代码
scala> val hiveContext = new org.apache.spark.sql.hive.HiveContext(sc)
scala> hiveContext.sql("select count(*) from SOGOUQ1 where S_SEQ=1 and C_SEQ=2").collect.foreach(println)
scala> hiveContext.sql("select count(*) from SOGOUQ1 where S_SEQ=1 and C_SEQ=2 and WEBSITE like '%baidu%'").collect.foreach(println)
scala> hiveContext.sql("select WEBSESSION,count(WEBSESSION) as cw from SOGOUQ1 group by WEBSESSION order by cw desc limit 10").collect.foreach(println)
l 独立维护 metastore 的代码
scala> val hiveContext = new org.apache.spark.sql.hive.HiveContext(sc)
scala> hiveContext.sql("CREATE TABLE IF NOT EXISTS src (key INT, value STRING)")