spark DataFrame用法

rdd dataframe dataset互轉

DataFrame/Dataset轉RDD:

val rdd1=testDF.rdd
val rdd2=testDS.rdd

RDD轉DataFrame:

import spark.implicits._
val testDF = rdd.map {line=>
      (line._1,line._2)
    }.toDF("col1","col2")

Dataset轉DataFrame:

import spark.implicits._
val testDF = testDS.toDF

DataFrame轉Dataset:

import spark.implicits._
case class Coltest(col1:String,col2:Int)extends Serializable //定義字段名和類型
val testDS = testDF.as[Coltest]

 

讀取數據庫

object DataFrameOperations {
  def main (args: Array[String ]) {
    val sparkConf = new SparkConf().setAppName( "Spark SQL DataFrame Operations").setMaster( "local[2]" )
    val sparkContext = new SparkContext(sparkConf)

    val sqlContext = new SQLContext(sparkContext)
    val url = "jdbc:mysql://m000:3306/test"

    val jdbcDF = sqlContext.read.format( "jdbc" ).options(
      Map( "url" -> url,
        "user" -> "root",
        "password" -> "root",
        "dbtable" -> "spark_sql_test" )).load()

    val joinDF1 = sqlContext.read.format( "jdbc" ).options(
      Map("url" -> url ,
        "user" -> "root",
        "password" -> "root",
        "dbtable" -> "spark_sql_join1" )).load()

    val joinDF2 = sqlContext.read.format( "jdbc" ).options(
      Map ( "url" -> url ,
        "user" -> "root",
        "password" -> "root",
        "dbtable" -> "spark_sql_join2" )).load()

    ... ...
  }
}

幾個選項說明一下:

  • url - 數據庫的 JDBC 連接串
  • dbtable - 可以是表名,也可以是一個子查詢。如果是子查詢的話,必須用括號括起來,並加別名,參見上面代碼示例。
  • user - 數據庫用戶名
  • password - 數據庫密碼
  • partitionColumn - 用於併發分區的表字段。下面幾個選項都是圍繞這個字段來的。Spark 會根據分區數量按這個字段的上下限把取出來的數據等分成幾份,並行處理。
  • lowerBound - 字段下限
  • upperBound - 字段上限
  • numPartitions - 分區數量

得到的 DataFrame,可以通過字段名來引用列或者某行的值,如:

 

讀寫


val parquetFile = sqlContext.read.parquet("hdfs:///path/to/hdfs/file.parquet")
df.write.save("file:///path/to/local/file.parquet")
如上所示,直接使用內置函數讀寫文本,可以使用hdfs:或者file:標註是本地文件還是HDFS文件。

與RDD的轉換


DataFrame描述的是表的結構,而RDD描述的是數據集,它們之間需要轉換。

DataFrame轉換爲RDD


這個比較簡單,直接調用df.rdd即可,得到一個org.apache.spark.rdd.RDD[org.apache.spark.sql.Row]數據集。如下是一個數據示例:

RDD轉換爲DataFrame


這個要稍微複雜點。假設rdd是一個類型爲org.apache.spark.rdd.RDD[(String, Long)]的數據集,轉換辦法如下:

object schema {   
    val name = StructField("name", StringType, true)       
    val number = StructField("number", LongType, true)       
 
    val row = StructType(Array(name, number))
}
val row = rdd.map(x=>Row(x._1, x._2))    //轉換爲Row
df = sqlContext.createDataFrame(row, schema.row)    //創建dataframe
在這裏關鍵是創建了一個schema對象,來描述表的每個列的類型。

一些常見的SQL查詢用法


select


df.select($"date".substr(0,10) as "date", $"page")
用$"column"表示一個列,注意必須用雙引號,單引號會報錯。substr是截取字符串,類比於SQL中的LEFT, RIGHT。as表示重命名。
返回df


where


df.where($"column1" === "" && $"column2" === 34) or
df.where($"class" === "").df.where($"id" === 32)
這個地方的等於必須使用三個等號,如果是整數值不用引號,多個查詢條件可以使用&&,也可以多次調用。
返回DataFrame


count


df.count()
直接調用查詢函數
返回計數


order by 


df.sort(asc("column")) or df.sort(desc("column"))
使用asc或者desc函數,列作爲參數
返回DataFrame


group by 


df.groupBy("column1", "column2")
返回值是一個org.apache.spark.sql.GroupedData數據類型。

grouby必須結合聚合函數使用纔有效。例如,
df.groupBy("column1", "column2").count()
返回值是一個包含了columns1, column2和count列的DataFrame。

舉例:
df.groupBy("column1").agg(min("timestamp") as "min",max("timestamp") as "max" ,count("timestamp") as "count",max("timestamp")- min("timestamp") as "interval")
groupBy之後,對每組數據進行聚合,一些聚合操作包括max, min, count等。結合包括了column1及agg中指定的各列。


join


key.join(data,key("column1")===data("column2"),"inner")
連接查詢,key和data爲DataFrame。
返回值是join後的DataFrame
打印結果
df.show(10)
打印表的格式


df.take(10).foreach(println)
df.head(10).foreach(println)
打印數組格式

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章