Spark SQL解決了什么問題
這個之前,先說下Hive,Hive有自己的語言Hive SQL(HQL),利用sql語句查詢,然后走的是MapReduce程序,提交到集群上運行.這樣的話有個很大的優勢,那就是它相比MapReduce節省了很多的代碼,很多..
但是也有個致命的缺陷,那就是MapReduce.(后面我想寫一篇MapReduce從仰望到失望,從失望到絕望...)? 前面也說過,MR相比Spark的RDD,性能速度正如官方所說的,有百倍之差..? 既然Spark這么強,那為何不出一個Spark SQL直接對應Hive呢,底層走的是Spark呢?? 于是就有了Spark SQL.它將Spark SQL轉換成RDD,然后提交到集群執行,執行效率也是MR和spark的差距。
Spark sql宏觀了解
Spark sql是Spark的一個組件,Spark sql自己也有兩個組件:DataFrame / DataSet.
Spark SQL是Spark用來處理結構化數據的一個模塊,它提供了一個編程抽象叫做DataFrame并且作為分布式SQL查詢引擎的作用.
從上圖可以看出,SparkSQL可以看做是一個轉換層,向下對接各種不同的結構化數據源,向上提供不同的數據訪問方式。
DataFrame / DataSet / RDD的關系
之前我們講,RDD是Spark的基石,因為其他的spark框架都是運行在Spark core上的.但是在我們Spark sql里面,就有點區別了.
在Spark sql中,DataSet是核心,沒有之一.但是DataSet僅限于Spark sql中,不能在其他框架中使用,所以RDD依舊還是spark的基石,依舊是核心.而DataFrame已經被DataSet替換了,DataFrame能實現的功能,DataSet都能實現,相反,DataFrame卻不能.
三者的關系如下:
RDD + schema(數據的結構信息) = DataFrame = DataSet[Row]
RDD 0.x版本發布,? DataFrame1.3版本發布, DataSet1.6版本發布.
RDD: 提供了很多實用簡單的API, www.lxweimin.com/p/a3a64f51ddf4 ,這是我之前寫的RDD的
DataFrame: DataFrame可以理解為一個傳統數據庫的二維表格,除了數據以外,還記錄著數據的結構信息,即schema.DataFrame API提供的是一套高層的關系操作,比函數式的RDD API要更加友好
DataSet: DataSet[Row] = Dataframe ;? 它是Dataframe API的一個擴展,是spark最新的數據抽象,也是Spark SQL中最核心的組件,它基本代替了Dataframe,也有完全代替Dataframe的趨勢.
注: RDD不支持spark sql的操作
RDD / DataSet / Dataframe之間的轉換
上面說到RDD不支持Spark sql的操作,但是Spark生態圈只提供了Spark core一個計算框架,且Spark生態圈都是基于Spark core進行計算的,所以Spark core對接Spark sql的方式就是:將RDD轉換為DataSet? /? Dataframe,且三者之間支持互相轉換!
轉換之前先聊一下DataFrame支持兩種查詢方式:一種是DSL風格,另外一種是SQL風格,dataFrame支持兩者查詢風格
DSL: 你需要引入? import spark.implicit._? 這個隱式轉換,可以將DataFrame隱式轉換成RDD。
SQL: 你需要將DataFrame注冊成一張表格,且需要通過sparkSession.sql 方法來運行你的SQL語句
用Spark-shell來操作Spark SQL,spark作為SparkSession的變量名,sc作為SparkContext的變量名.
將文件中的數據轉換成DataSet? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //先case一個類? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? case class person(name:String,age:Int)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //將文件里面的數據轉換成DataSet? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? val peopleDF2 =spark.sparkContext.textFile("../examples/src/main/resources/people.txt").map(_.split(",")).map(para=> Person(para(0).trim,para(1).trim.toInt)).toDF? ? ? ? ? ? ? ? ? ? //制成一張person的表? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? peopleDF2.createOrReplaceTempView("persons")? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //查詢? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? val teen =spark.sql("select * from persons where age between 13 and 30")? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //因為DataFrame=DataSet[row],所以要訪問row對象中的每一個元素,可以通過這種row[0]角標的方式來訪問,上面是通過反射獲取schema????????????????????????????????????????????????????????????????????????????????????? teen.map(row => "name:" + row(0)).show
//將RDD轉換成DataFrame? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? var peopleRDD = sc.textFile("../examples/src/main/resources/people.txt")? ? ? ? ? ? ? ? ? ? ? ? peopleRDD.collect? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //以”,”切割,得到一個Array,然后再用map對里面的每一個元素都進行轉換,最后用toDF方法給這兩個起名字? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? val peopleDF =peopleRDD.map(_.split(",")).map(para=>(para(0).trim(),para(1).trim().toInt)).toDF("name","age")
//將 DataFrame轉換成RDD? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? val aa = peopleDF.rdd??????????? //對,沒錯,就是一行!一個方法搞定?????????????????????
//將RDD轉換成DataSet? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? case class person(name:String,age:Int)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //先定義一個case實例,最后是直接toDS就ok了? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? val peopleDF= peopleRDD.map(_.split(",")).map(para=>person(para(0).trim(),para(1).trim().toInt)).toDS
//將DataSet轉換成RDD??????????????????????????????????????????????????????????????????????????????????????????????????????????????????? val bb = peopleDF.rdd ? ? ?? //和上面一樣,一個方法搞定
//將DataFrame轉換成DataSet? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? peopleDF.as[person]?????????? as那個case的類
將DataSet轉換成DataFrame? ? ? ? ? ? ? ???????????????????????????????????????????????????????????????????????????????? PeopleDS.toDF?????????????????? 用的toDF方法
Spark SQL鏈接Hive
Spark SQL和Hive的連接有兩種,一種是Spark內置的Hive,一種是Spark連接外部的Hive.
內置Hive: 內置Hive和Spark會完美地兼容,但是我用的都是外置的Hive
外置Hive: 這是Spark連接Hive的主要模式; 實現方式:
1. 需要將hive-site.xml 拷貝到spark的conf目錄下。
2. 如果hive的metestore使用的是mysql數據庫,那么需要將mysql的jdbc驅動包放到spark的jars目錄下。
3. 用bin/spark-shell打開時候,第一次需要在后面加--confspark.sql.warehouse.dir=hdfs:hadoop101:9000/spark_warehouse