標籤:sql語句 spl map 應用 包含 必須 password 條件 初始化
一、DataFrame:有列名的RDD
首先,我們知道SparkSQL的目的是用sql語句去操作RDD,和Hive類似。SparkSQL的核心結構是DataFrame,如果我們知道RDD裡面的欄位,也知道裡面的資料類型,就好比關係型資料庫裡面的一張表。那麼我們就可以寫SQL,所以其實這兒我們是不能用物件導向的思維去編程的。我們最好的方式就是把抽象成為一張表,然後去用SQL語句去操作它。
DataFrame的儲存方式:它採用的儲存是類似於資料庫的表的形式進行儲存的。一個資料表有幾部分組成:1、資料,這個資料是一行一行進行儲存的,一條記錄就是一行,2、資料表的資料字典,包括表的名稱,表的欄位和欄位的類型等中繼資料資訊。那麼DataFrame也是按照行進行儲存的,這個類是Row,一行一行的進行資料存放區。一般情況下處理粒度是行粒度的,不需要對其行內資料進行操作。
二、SparkSQL的程式入口:
在Spark2.0之前,是有sqlContext和hiveContext的概念的,因為這兩個概念難以區分,Spark2.0之後統一稱為SparkSession,除此之外SparkSession還封裝了SparkConf和SparkContext。
值得注意的一點是:Hive有很多依賴包,所以這些依賴包沒有包含在預設的Spark包裡面。如果Hive依賴的包能在classpath找到,Spark將會自動載入它們。這些Hive依賴包必須複製到所有的工作節點上,因為它們為了能夠訪問儲存在Hive的資料,會調用Hive的序列化和還原序列化(SerDes)包。Hive的設定檔hive-site.xml、core-site.xml(security配置)和hdfs-site.xml(HDFS配置)是儲存在conf目錄下面。
當使用Hive時,必須初始化一個支援Hive的SparkSession,使用者即使沒有部署一個Hive的環境仍然可以使用Hive。當沒有配置hive-site.xml時,Spark會自動在當前應用目錄建立metastore_db和建立由spark.sql.warehouse.dir配置的目錄,如果沒有配置,預設是當前應用目錄下的spark-warehouse目錄。
注意:從Spark 2.0.0版本開始,hive-site.xml裡面的hive.metastore.warehouse.dir屬性已經被spark.sql.warehouse.dir替代,用於指定warehouse的預設資料路徑(必須有寫入權限)。
於是SparkSQL在與Hive有互動的情況下,需要指定支援Hive:
val conf = new SparkConf().setAppName(s"${this.getClass.getSimpleName}")val spark = SparkSession.builder().config(conf).config("spark.sql.warehouse.dir","hdfs://hadoop1:9000/user/hive/warehouse").enableHiveSupport().getOrCreate()
回到正題,程式入口:
1.6版本:
val conf=new SparkConf()conf.setAppName(s"${this.getClass.getSimpleName}").setMaster("local")val sc=new SparkContext(conf)val sqlContext = new SQLContext(sc)
2.0版本:
SparkSQL的程式入口縮減為一句
val sparkSession=SparkSession.builder().appName(s"${this.getClass.getSimpleName}").master("local").getOrCreate()
兩個版本一個獲得sqlContext(或者hiveContext),一個獲得sparkSession。
三、算了,還是放在一起寫吧。。
case class Person(var name:String,var age:Int)object Test { def main(args: Array[String]): Unit = { //1.6版本入口 val conf=new SparkConf() conf.setAppName(s"${this.getClass.getSimpleName}").setMaster("local") val sc=new SparkContext(conf) val sqlContext = new SQLContext(sc) //第一種建立DataFrame的方式:直接讀取列式儲存的格式,可以直接形成DataFrame(後續怎麼操作呢?) val df: DataFrame = sqlContext.read.json("")
//第二種建立DataFrame的方式:因為rdd沒有toDF()方法,需要進行隱式轉化,通過map後形成一個數組 import sqlContext.implicits._ val df: DataFrame = sc.textFile("C:\\Users\\wangyongxiang\\Desktop\\plan\\person.txt").map(_.split(",")).map(p => Person(p(0), p(1).trim.toInt)).toDF()
//第二種方法的另一種形態,用sqlContext或者sparkSession的createDataFrame(),其實和toDF()方法是雷同的 val rdd: RDD[Person] = sc.textFile("C:\\Users\\wangyongxiang\\Desktop\\plan\\person.txt") .map(_.split(",")).map(p => Person(p(0), p(1).trim.toInt)) val df: DataFrame = sqlContext.createDataFrame(rdd)
//第三種建立DataFrame:產生一個RowRDD,然後給出構造的描述 val rdd=sc.textFile("C:\\Users\\wangyongxiang\\Desktop\\plan\\person.txt") val rowRDD: RDD[Row] = rdd.map(_.split(",")).map(p=>Row(p(0),p(1).trim.toInt)) val schame=StructType( StructField("name",StringType,true):: StructField("age",IntegerType,true)::Nil ) val df: DataFrame = sqlContext.createDataFrame(rowRDD,schame)
//後續代碼,可以建立臨時視圖作為查詢,與mysql互操作要建立臨時視圖才能做查詢
//用hiveContext則直接在hive中建立表,然後將資料load到hive表中,可以直接進行條件查詢,無需建立臨時視圖,後面與hive整合會有說明 df.registerTempTable("person") sqlContext.sql("select * from person where age>21").show() //將處理後的資料用jdbc儲存到mysql資料庫中成為一張表,注意這裡要使用user而不能使用username,因為系統也有一個username,會覆蓋你的使用者名稱 val properties=new Properties() properties.put("user","root") properties.put("password","root") df.write.mode(SaveMode.Overwrite)jdbc("jdbc:mysql://localhost:3306/test","test",properties) }}
四、load和save操作。
object saveAndLoadTest { def main(args: Array[String]): Unit = { val conf =new SparkConf().setAppName("").setMaster("local") val sc=new SparkContext(conf) val sqlContext=new SQLContext(sc) //read,load:讀取 sqlContext.read.json("")// sqlContext.read.jdbc("url","table",properties) sqlContext.read.load("parquet路徑") sqlContext.read.format("json").load("路徑") val df: DataFrame = sqlContext.read.format("parquet").load("路徑") //write,save儲存 df.write.parquet("路徑.parquet") df.write.json("路徑.json")// df.write.jdbc("url","table",properties) df.write.format("parquet").save("路徑.parquet") df.write.format(("json")).save("路徑.json") //儲存模式可選擇覆蓋,追加等 df.write.mode(SaveMode.Overwrite).save("") }}
個人理解是read和load都是讀取的作用,write和save都是儲存的作用,通過上述的代碼,我們可以完成檔案格式轉換的工作,將效率低的一些格式轉化成parquet這種sparksql原生支援的檔案類型
Spark SQL讀寫方法