好程式設計師大資料學習路線分享SparkSQl

好程式設計師IT發表於2019-08-14

  好程式設計師大資料學習路線分享SparkSQl,Spark SQL Spark 用來處理結構化資料的一個模組,它提供了一個程式設計抽象叫做 DataFrame 並且作為分散式 SQL 查詢引擎的作用。 SparkSql 中返回的資料型別是 DataFrame

1.1.1.     為什麼要學習 Spark SQL

我們已經學習了Hive ,它是將 Hive SQL 轉換成 MapReduce 然後提交到叢集上執行,大大簡化了編寫 MapReduce 的程式的複雜性 ,由於MapReduce這種計算模型執行效率比較慢。所有Spark SQL的應運而生,它是將Spark SQL轉換成RDD,然後提交到叢集執行,執行效率非常快!

HIVE:簡化編寫MapReduce的程式的複雜性

Spark SQL轉換成RDD: 替代 MapReduce, 提高效率

 

Spark1.0 版本開始就推出了 SparkSQL ,最早是叫 Shark

1 、記憶體列儲存 -- 可以大大最佳化記憶體使用效率,減少了記憶體消耗,避免了 gc 對大量資料的效能開銷

2 、位元組碼生成技術( byte-code generation -- 可以使用動態位元組碼生成技術來最佳化效能

3 Scala 程式碼的最佳化

 

   結構化資料是指任何有結構資訊的資料。所謂結構資訊,就是每條記錄共用的已知的欄位集合。 當資料符合   這樣的條件時, Spark SQL  就會使得針對這些資料的讀取和查詢變得更加簡單高效。具體 來說, Spark SQL  提供了以下三大功能(見圖  9-1 )。

(1) Spark SQL  可以從各種結構化資料來源(例如  JSON Hive Parquet  等)中讀取資料。

(2) Spark SQL  不僅支援在  Spark  程式內使用  SQL  語句進行資料查詢,也支援從類似商業 智慧軟體  Tableau  這樣的外部工具中透過標準資料庫聯結器( JDBC/ODBC )連線  Spark SQL  進行查詢。

(3)  當在  Spark  程式內使用  Spark SQL  時, Spark SQL  支援  SQL  與常規的  Python/Java/Scala  程式碼高度整合,包括連線  RDD  與  SQL  表、公開的自定義  SQL  函式介面等。這樣一來, 許多工作都更容易實現了。

為了實現這些功能, Spark SQL  提供了一種特殊的  RDD ,叫作  SchemaRDD SchemaRDD  是存放  Row  物件的  RDD ,每個  Row  物件代表一行記錄。 SchemaRDD  還包含記錄的結構信 息(即資料欄位)。 SchemaRDD  看起來和普通的  RDD  很像,但是在內部, SchemaRDD  可 以利用結構資訊更加高效地儲存資料 。此外, SchemaRDD  還支援  RDD  上所沒有的一些新 操作,比如執行  SQL  查詢。 SchemaRDD  可以從外部資料來源建立,也可以從查詢結果或普 通  RDD  中建立。

 

什麼是 DataFrames

( SparkSql 中返回的資料型別 它在概念上等同於關聯式資料庫中的表 , 但在查詢上進行了最佳化 )

RDD 類似, DataFrame 也是一個分散式資料容器。然而 DataFrame 更像傳統資料庫的二維表格,除了資料以外,還 記錄 資料的結構資訊,即 schema

 

1.1.1.     建立 DataFrames

 在Spark SQL中SQLContext是建立DataFrames和執行SQL的入口,在spark-1.6.1中已經內建了一個 sqlContext

 

1.在本地建立一個檔案,有三列,分別是id、name、age,用空格分隔,然後上傳到hdfs上

hdfs dfs -put person.txt /

 

2.在spark shell執行下面命令,讀取資料,將每一行的資料使用列分隔符分割

val lineRDD = sc.textFile("hdfs://node01:9000/person.txt").map(_.split(" "))

 

3. 定義 case class (相當於表的 schema

case class Person(id:Int, name:String, age:Int)

 

4. RDD case class 關聯

val personRDD = lineRDD.map(x => Person(x(0).toInt, x(1), x(2).toInt))

  ( 裡面的資料是在 Array )

5. RDD 轉換成 DataFrame

val personDF = personRDD.toDF

 

6.對DataFrame進行處理

personDF.show

 

val seq1 = Seq(("1","bingbing",35),("2","yuanyuan",34),("3","mimi",33))

val rdd1 =sc.parallelize(seq1)

val df = rdd1.toDF("id","name","age")

df.show

 

 

DSL:領域特定語言

////檢視DataFrame中的內容


//檢視DataFrame部分列中的內容

1.


2.


3.


//列印DataFrame的Schema資訊


//查詢所有的name和age,並將age+1

1.df.select(col("id"),col("name"),col("age")+1).show


2.df.select(df("id"), df("name"), df("age") + 1).show


//過濾age大於等於18的

df.filter(col("age") >= 35).show


//按年齡進行分組並統計相同年齡的人數

df.groupBy("age").count().show()


SQL 風格語法

//查詢年齡最大的前兩名

1.如果想使用SQL風格的語法,需要將DataFrame註冊成表

df.registerTempTable("t_person")

2.sqlContext.sql("select * from t_person order by age desc limit 2").show


//顯示錶的Schema資訊


以程式設計方式執行 Spark SQL 查詢

1. 編寫 Spark SQL 查詢程式

1. 透過反射推斷 Schema

=======================================================

package  com.qf.gp1708.day06

 

 

//透過反射獲取使用者資訊

 

import  org.apache.spark.rdd.RDD

import  org.apache.spark.sql.{DataFrame, SQLContext}

import  org.apache.spark.{SparkConf, SparkContext}

 

object  InferSchema {

   def  main(args: Array[String]): Unit = {

     val  conf =  new  SparkConf()

      .setMaster( "local" )

      .setAppName( "inferschema" )

     val  sc =  new  SparkContext(conf)

     val  sqlContext:SQLContext =  new  SQLContext(sc)

 

  1.   //獲取資料並切分

     val  line = sc.textFile( "C://Users/Song/Desktop/person.txt" ).map(_.split( "," ))

 

   3  //將獲取的資料和Person樣例類進行關聯

     val  personRdd: RDD[Godness] = line.map(arr=> Godness (arr(0).toLong,arr(1),arr(2).toInt,arr(3).toInt))

    

     //引入隱式轉換函式,這樣才可以呼叫到toDF方法

     import  sqlContext.implicits._

    

   4  //將personRDD轉換成DataFrame

     val  dF: DataFrame = personRdd.toDF

 

  5.   //註冊一張臨時表

     dF.registerTempTable( "t_person" )

     val  sql =  "select * from t_person where fv > 70 order by age"

 

     //查詢

     val  res: DataFrame = sqlContext.sql(sql)

 

    res.show()

 

    sc.stop()

  }

}

2// 建立樣例類

case class  Godness(id:Long,name:String,age:Int,fv:Int)

=========================================================

 

2. 透過 StructType 直接指定 Schema

===========================================

package  com.qf.gp1708.day06

 

 

import  org.apache.spark.rdd.RDD

import  org.apache.spark.sql.{DataFrame, Row, SQLContext}

import  org.apache.spark.sql.types.{IntegerType, StringType, StructField, StructType}

import  org.apache.spark.{SparkConf, SparkContext}

 

/**

  * 透過StructType型別直接指定Schema

  */

object  StructTypeSchema {

   def  main(args: Array[String]): Unit = {

     val  conf =  new  SparkConf()

      .setAppName( "str" )

      .setMaster( "local" )

     val  sc =  new  SparkContext(conf)

     val  sqlContext =  new  SQLContext(sc)

 

     //獲取資料並切分

     val  lines = sc.textFile( "hdfs://..." ).map(_.split( "," ))

     //指定schema資訊

     StructType {

       List (

         StructField ( "id" ,IntegerType, false ),

         StructField ( "name" ,StringType, true ),

         StructField ( "age" ,IntegerType, true ),

         StructField ( "fv" ,IntegerType, true ),

 

      )

    }

     //開始對映

     val  rowRDD: RDD[Row] = lines.map(arr => Row (arr(0).toInt,arr(1),arr(2).toInt,arr(3).toInt))

 

     //把RDD轉換為DataFrame

     val  personDF: DataFrame = sqlContext.createDataFrame(rowRDD,schema)

 

     //生成臨時表

     personDF.registerTempTable( "t_person" )

     val  sql =  "select name,age,fv from t_person where age >30 order by age desc"

     val  res = sqlContext.sql(sql)

    

    res.write.mode( "append" ).json( "c://out-20180903-1" )

    

    sc.stop()

 

 

  }

}

 

=================================================================

 

1.     資料來源

1.1.   JDBC

Spark SQL可以透過JDBC從關係型資料庫中讀取資料的方式建立DataFrame,透過對DataFrame一系列的計算後,還可以將資料再寫回關係型資料庫中。

1.1.1.     MySQL 中載入資料( Spark Shell 方式)

1.啟動Spark Shell,必須指定mysql連線驅動jar包

/usr/local/spark-1.6.1-bin-hadoop2.6/bin/spark-shell \

--master spark://node01:7077 \

--jars /usr/local/spark-1.6.1-bin-hadoop2.6/mysql-connector-java-5.1.35-bin.jar \

   (指定MySQL包)

--driver-class-path /usr/local/spark-1.6.1-bin-hadoop2.6/mysql-connector-java-5.1.35-bin.jar  (指定驅動類)

 

2.從mysql中載入資料

val jdbcDF = sqlContext.read.format("jdbc").options(Map("url" -> "jdbc:mysql://node03:3306/bigdata", "driver" -> "com.mysql.jdbc.Driver", "dbtable" -> "person", "user" -> "root", "password" -> "root")).load()

 

3.執行查詢

jdbcDF.show()

1.1.2.     將資料寫入到 MySQL 中(打 jar 包方式)

 

package  com.qf.gp1708.day06

 

 

import  java.util.Properties

 

import  org.apache.spark.rdd.RDD

import  org.apache.spark.sql.{Row, SQLContext}

import  org.apache.spark.sql.types.{IntegerType, StringType, StructField, StructType}

import  org.apache.spark.{SparkConf, SparkContext}

 

/**

  * 寫入資料到MySQL

  */

object  InsertData2MySQLDemo {

   def  main(args: Array[String]): Unit = {

     val  conf =  new  SparkConf().setAppName( "" ).setMaster( "local[2]" )

     val  sc =  new  SparkContext(conf)

     val  sqlContext =  new  SQLContext(sc)

 

     val  lines= sc.textFile( "" ).map(_.split( "," ))

 

 

     //生成Schema

     val  schema = StructType {

       Array (

         StructField ( "name" , StringType,  true ),

         StructField ( "age" , IntegerType,  true ),

         StructField ( "fv" , StringType,  true ),

      )

    }

 

     //對映

     val  personRDD = lines.map(arr => Row (arr(1).toString,arr(2).toInt,arr(3).toInt))

 

     //生成DataFrame

     val  personDF = sqlContext.createDataFrame(personRDD,schema)

 

     //生成用於寫入MySQL的配置資訊

     val  prop =  new  Properties()

    prop.put( "user" , "root" )

    prop.put( "password" , "root" )

    prop.put( "driver" , "com.mysql.jdbc.Driver" )

     val  jdbcUrl= "jdbc:mysql://hadoop03:3306/bigdata"

     val  table= "person"

 

     //把資料寫入MySQL

     personDF.write.mode( "append" ).jdbc(jdbcUrl,table,prop)

 

    sc.stop()

  }

}

 

/usr/local/spark-1.6.3-bin-hadoop2.6/spark-submit \

--class com.qf..... \

--master spark://hadoop01:7077 \

--executor-memory 512m \

--total-executor-cores 2 \

--jars /usr/.../mysql-connector-java-5.1.35-bin.jar \

--driver-class-path /usr/.../mysql-connector-java-5.1.35-bin.jar \

/root/1.jar

 

=======================================================

 

kafka:訊息中介軟體(快取資料)---解耦

  為處理實時資料提供一個統一、高吞吐量、低等待的平臺

   3 、為什麼需要訊息佇列(重要、瞭解)

   訊息系統的核心作用就是三點:解耦,非同步和並行


  Kafka對訊息儲存時根據Topic進行歸類

  Topic:底層就是佇列,將不同的訊息放在不同的佇列中進行分類

  

   釋出 /訂閱模式:1對多

  

  JMS:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913892/viewspace-2653694/,如需轉載,請註明出處,否則將追究法律責任。

相關文章