轉】Spark DataFrames入門指南:創建和操作DataFrame


  原博文出自於:  http://blog.csdn.net/lw_ghy/article/details/51480358      感謝!

 

 

 

一、從csv文件創建DataFrame

  本文將介紹如何從csv文件創建DataFrame。

如何做?
  從csv文件創建DataFrame主要包括以下幾步驟:
  1、在build.sbt文件里面添加spark-csv支持庫;
  2、創建SparkConf對象,其中包括Spark運行所有的環境信息;
  3、創建SparkContext對象,它是進入Spark的核心切入點,然后我們可以通過它創建SQLContext對象;
  4、使用SQLContext對象加載CSV文件;
  5、Spark內置是不支持解析CSV文件的,但是Databricks公司開發了一個類庫可以支持解析CSV文件。所以我們需要把這個依賴文件加載到依賴文件中(pom.xml或者是build.sbt)

如果你是SBT工程,請加入以下依賴到build.sbt文件中:

 

[python]  view plain  copy
 
 print?
  1. libraryDependencies += "com.databricks" % "spark-csv_2.10" % "1.3.0"  

如果你是Maven工程,請加入以下依賴到pom.xml文件中:

[html]  view plain  copy
 
 print?
  1. <dependency>  
  2.     <groupid>com.databricks</groupid>  
  3.     <artifactid>spark-csv_2.10</artifactid>  
  4.     <version>1.3.0</version>  
  5. </dependency>  

6、SparkConf持有所有運行Spark程序的信息,在這個實例中,我們將以本地的方式運行這個程序,而且我們打算使用2個核(local[2]),部分代碼片段如下:

[python]  view plain  copy
 
 print?
  1. import org.apache.spark.SparkConf  
  2. val conf = new SparkConf().setAppName("csvDataFrame").setMaster("local[2]")  

7、使用SparkConf初始化SparkContext對象,SparkContext是進入Spark的核心切入點:

[python]  view plain  copy
 
 print?
  1. val sc = new SparkContext(conf)   

在Spark中查詢數據最簡單的一種方式就是使用SQL查詢,所以我們可以定義一個SQLContext對象:

[python]  view plain  copy
 
 print?
  1. val sqlContext=new SQLContext(sc)   

8、現在我們就可以加載事先准備好的數據了:

[python]  view plain  copy
 
 print?
  1. import com.databricks.spark.csv._   
  2. val students=sqlContext.csvFile(filePath="StudentData.csv", useHeader=true, delimiter='|')   

其中,students對象的類型是org.apache. spark.sql.DataFrame。

如何工作的
  csvFile方法接收需要加載的csv文件路徑filePath,如果需要加載的csv文件有頭部信息,我們可以將useHeader設置為true,這樣就可以將第一行的信息當作列名稱來讀;delimiter指定csv文件列之間的分隔符。

  除了使用csvFile函數,我們還可以使用sqlContext里面的load來加載csv文件:

[python]  view plain  copy
 
 print?
  1. val options = Map("header" -> "true", "path" -> "E:\\StudentData.csv")  
  2. val newStudents = sqlContext.read.options(options).format("com.databricks.spark.csv").load()  

附錄
為了方便大家測試,我提供了StudentData.csv文件的部分數據集:

[python]  view plain  copy
 
 print?
  1. id|studentName|phone|email  
  2. 1|Burke|1-300-746-8446|ullamcorper.velit.in@ametnullaDonec.co.uk  
  3. 2|Kamal|1-668-571-5046|pede.Suspendisse@interdumenim.edu  
  4. 3|Olga|1-956-311-1686|Aenean.eget.metus@dictumcursusNunc.edu  
  5. 4|Belle|1-246-894-6340|vitae.aliquet.nec@neque.co.uk  
  6. 5|Trevor|1-300-527-4967|dapibus.id@acturpisegestas.net  
  7. 6|Laurel|1-691-379-9921|adipiscing@consectetueripsum.edu  
  8. 7|Sara|1-608-140-1995|Donec.nibh@enimEtiamimperdiet.edu  
  9. 8|Kaseem|1-881-586-2689|cursus.et.magna@euismod.org  
  10. 9|Lev|1-916-367-5608|Vivamus.nisi@ipsumdolor.com  
  11. 10|Maya|1-271-683-2698|accumsan.convallis@ornarelectusjusto.edu  
  12. 11|Emi|1-467-270-1337|est@nunc.com  
  13. 12|Caleb|1-683-212-0896|Suspendisse@Quisque.edu  
  14. 13|Florence|1-603-575-2444|sit.amet.dapibus@lacusAliquamrutrum.ca  
  15. 14|Anika|1-856-828-7883|euismod@ligulaelit.co.uk  
  16. 15|Tarik|1-398-171-2268|turpis@felisorci.com  
  17. 16|Amena|1-878-250-3129|lorem.luctus.ut@scelerisque.com  
  18. 17|Blossom|1-154-406-9596|Nunc.commodo.auctor@eratSed.co.uk  
  19. 18|Guy|1-869-521-3230|senectus.et.netus@lectusrutrum.com  
  20. 19|Malachi|1-608-637-2772|Proin.mi.Aliquam@estarcu.net  
  21. 20|Edward|1-711-710-6552|lectus@aliquetlibero.co.uk  

 

二、從Scala case class中創建DataFrame

  在這篇文章中,你將學到如何從Scala case class中創建DataFrame。

如何做?
  1、我們首先創建一個case class,名為Employee,並且定義id和name兩個參數,如下:

[python]  view plain  copy
 
 print?
  1. case class Employee(id: Int, name: String)  

和先前一樣,我們分別定義SparkConf、SparkContext以及SQLContext:

[python]  view plain  copy
 
 print?
  1. val conf = new SparkConf().setAppName("colRowDataFrame"). setMaster("local[2]")   
  2. val sc = new SparkContext(conf)  
  3. val sqlContext = new SQLContext(sc)   

2、我們可以通過很多方式來初始化Employee類,比如從關系型數據庫中獲取數據以此來定義Employee類。但是在本文為了簡單起見,我將直接定義一個Employee類的List,如下:

[python]  view plain  copy
 
 print?
  1. val listOfEmployees = List(Employee(1, "iteblog"), Employee(2, "Jason"), Employee(3, "Abhi"))  

3、我們將listOfEmployees列表傳遞給SQLContext類的createDataFrame 函數,這樣我們就可以創建出DataFrame了!然后我們可以調用DataFrame的printuSchema函數,打印出該DataFrame的模式,我們可以看出這個DataFrame主要有兩列:name和id,這正是我們定義Employee的兩個參數,並且類型都一致。

[python]  view plain  copy
 
 print?
  1. val empFrame = sqlContext.createDataFrame(listOfEmployees)  
  2. empFrame.printSchema  
  3. root  
  4.  |-- id: integer (nullable = false)  
  5.  |-- name: string (nullable = true)  

之所以DataFrame打印出的模式和Employee類的兩個參數一致,那是因為DataFrame內部通過反射獲取到的。

4、如果你對默認反射獲取到的模式名稱不感興趣,你可以通過withColumnRenamed函數來指定列名:

[python]  view plain  copy
 
 print?
  1. val empFrameWithRenamedColumns = sqlContext.createDataFrame(listOfEmployees).withColumnRenamed("id", "empId")  
  2. empFrameWithRenamedColumns.printSchema  
  3.   
  4. root  
  5.  |-- empId: integer (nullable = false)  
  6.  |-- name: string (nullable = true)  

5、我們可以使用Spark支持的SQL功能來查詢相關的數據。在使用這個功能之前,我們必須先對DataFrame注冊成一張臨時表,我們可以使用registerTempTable函數實現,如下:

[python]  view plain  copy
 
 print?
  1. empFrameWithRenamedColumns.registerTempTable("employeeTable")  

6、現在我們就可以使用SQL語句來查詢DataFrame里面的數據了:

[python]  view plain  copy
 
 print?
  1. val sortedByNameEmployees = sqlContext.sql("select * from employeeTable order by name desc")  
  2. sortedByNameEmployees.show()  
  3. +-----+-------+  
  4. |empId|   name|  
  5. +-----+-------+  
  6. |    1|iteblog|  
  7. |    2|  Jason|  
  8. |    3|   Abhi|  
  9. +-----+-------+  

它如何工作的
  createDataFrame函數可以接收一切繼承scala.Product類的集合對象:

[python]  view plain  copy
 
 print?
  1. def createDataFrame[A <: Product : TypeTag](rdd: RDD[A]): DataFrame  

而case class類就是繼承了Product。我們所熟悉的TupleN類型也是繼承了scala.Product類的,所以我們也可以通過TupleN來創建DataFrame:

[python]  view plain  copy
 
 print?
  1. val mobiles=sqlContext.createDataFrame(Seq((1,"Android"), (2, "iPhone"))) mobiles.printSchema mobiles.show()  
  2.   
  3. root  
  4.  |-- _1: integer (nullable = false)  
  5.  |-- _2: string (nullable = true)  
  6.   
  7. +---+-------+  
  8. | _1|     _2|  
  9. +---+-------+  
  10. |  1|Android|  
  11. |  2| iPhone|  
  12. +---+-------+  

我們知道,Tuple2的默認兩個參數名字分別是_1和_2,同樣,我們如果對這個默認的名字不是特別喜歡,我們也是可以通過withColumnRenamed函數對默認反射的列名進行重命名。

三、操作DataFrame

  在前面的文章中,我們介紹了如何創建DataFrame。本文將介紹如何操作DataFrame里面的數據和打印出DataFrame里面數據的模式

打印DataFrame里面的模式
  在創建完DataFrame之后,我們一般都會查看里面數據的模式,我們可以通過printSchema函數來查看。它會打印出列的名稱和類型:

 

 

[python]  view plain  copy
 
 print?
  1. students.printSchema   
  2. root  
  3.  |-- id: string (nullable = true)  
  4.  |-- studentName: string (nullable = true)  
  5.  |-- phone: string (nullable = true)  
  6.  |-- email: string (nullable = true)  

 

如果采用的是load方式參見DataFrame的,students.printSchema的輸出則如下:

 

[python]  view plain  copy
 
 print?
  1. root  
  2.  |-- id|studentName|phone|email: string (nullable = true)  

對DataFrame里面的數據進行采樣
  打印完模式之后,我們要做的第二件事就是看看加載進DataFrame里面的數據是否正確。從新創建的DataFrame里面采樣數據的方法有很多種。我們來對其進行介紹。

  最簡單的就是使用show方法,show方法有四個版本:
  (1)、第一個需要我們指定采樣的行數def show(numRows: Int);
  (2)、第二種不需要我們指定任何參數,這種情況下,show函數默認會加載出20行的數據def show();
  (3)、第三種需要指定一個boolean值,這個值說明是否需要對超過20個字符的列進行截取def show(truncate: Boolean);
  (4)、最后一種需要指定采樣的行和是否需要對列進行截斷def show(numRows: Int, truncate: Boolean)。實際上,前三個函數都是調用這個函數實現的。

  Show函數和其他函數不同的地方在於其不僅會顯示需要打印的行,而且還會打印出頭信息,並且會直接在默認的輸出流打出(console)。來看看怎么使用吧:

[python]  view plain  copy
 
 print?
  1. students.show()  //打印出20行  
  2. +---+-----------+--------------+--------------------+  
  3. | id|studentName|         phone|               email|  
  4. +---+-----------+--------------+--------------------+  
  5. |  1|      Burke|1-300-746-8446|ullamcorper.velit...|  
  6. |  2|      Kamal|1-668-571-5046|pede.Suspendisse@...|  
  7. |  3|       Olga|1-956-311-1686|Aenean.eget.metus...|  
  8. |  4|      Belle|1-246-894-6340|vitae.aliquet.nec...|  
  9. |  5|     Trevor|1-300-527-4967|dapibus.id@acturp...|  
  10. |  6|     Laurel|1-691-379-9921|adipiscing@consec...|  
  11. |  7|       Sara|1-608-140-1995|Donec.nibh@enimEt...|  
  12. |  8|     Kaseem|1-881-586-2689|cursus.et.magna@e...|  
  13. |  9|        Lev|1-916-367-5608|Vivamus.nisi@ipsu...|  
  14. 10|       Maya|1-271-683-2698|accumsan.convalli...|  
  15. 11|        Emi|1-467-270-1337|        est@nunc.com|  
  16. 12|      Caleb|1-683-212-0896|Suspendisse@Quisq...|  
  17. 13|   Florence|1-603-575-2444|sit.amet.dapibus@...|  
  18. 14|      Anika|1-856-828-7883|euismod@ligulaeli...|  
  19. 15|      Tarik|1-398-171-2268|turpis@felisorci.com|  
  20. 16|      Amena|1-878-250-3129|lorem.luctus.ut@s...|  
  21. 17|    Blossom|1-154-406-9596|Nunc.commodo.auct...|  
  22. 18|        Guy|1-869-521-3230|senectus.et.netus...|  
  23. 19|    Malachi|1-608-637-2772|Proin.mi.Aliquam@...|  
  24. 20|     Edward|1-711-710-6552|lectus@aliquetlib...|  
  25. +---+-----------+--------------+--------------------+  
  26. only showing top 20 rows  
  27. students.show(15)  
  28. +---+-----------+--------------+--------------------+  
  29. | id|studentName|         phone|               email|  
  30. +---+-----------+--------------+--------------------+  
  31. |  1|      Burke|1-300-746-8446|ullamcorper.velit...|  
  32. |  2|      Kamal|1-668-571-5046|pede.Suspendisse@...|  
  33. |  3|       Olga|1-956-311-1686|Aenean.eget.metus...|  
  34. |  4|      Belle|1-246-894-6340|vitae.aliquet.nec...|  
  35. |  5|     Trevor|1-300-527-4967|dapibus.id@acturp...|  
  36. |  6|     Laurel|1-691-379-9921|adipiscing@consec...|  
  37. |  7|       Sara|1-608-140-1995|Donec.nibh@enimEt...|  
  38. |  8|     Kaseem|1-881-586-2689|cursus.et.magna@e...|  
  39. |  9|        Lev|1-916-367-5608|Vivamus.nisi@ipsu...|  
  40. 10|       Maya|1-271-683-2698|accumsan.convalli...|  
  41. 11|        Emi|1-467-270-1337|        est@nunc.com|  
  42. 12|      Caleb|1-683-212-0896|Suspendisse@Quisq...|  
  43. 13|   Florence|1-603-575-2444|sit.amet.dapibus@...|  
  44. 14|      Anika|1-856-828-7883|euismod@ligulaeli...|  
  45. 15|      Tarik|1-398-171-2268|turpis@felisorci.com|  
  46. +---+-----------+--------------+--------------------+  
  47. only showing top 15 rows  
  48.   
  49. students.show(true)  
  50. +---+-----------+--------------+--------------------+  
  51. | id|studentName|         phone|               email|  
  52. +---+-----------+--------------+--------------------+  
  53. |  1|      Burke|1-300-746-8446|ullamcorper.velit...|  
  54. |  2|      Kamal|1-668-571-5046|pede.Suspendisse@...|  
  55. |  3|       Olga|1-956-311-1686|Aenean.eget.metus...|  
  56. |  4|      Belle|1-246-894-6340|vitae.aliquet.nec...|  
  57. |  5|     Trevor|1-300-527-4967|dapibus.id@acturp...|  
  58. |  6|     Laurel|1-691-379-9921|adipiscing@consec...|  
  59. |  7|       Sara|1-608-140-1995|Donec.nibh@enimEt...|  
  60. |  8|     Kaseem|1-881-586-2689|cursus.et.magna@e...|  
  61. |  9|        Lev|1-916-367-5608|Vivamus.nisi@ipsu...|  
  62. 10|       Maya|1-271-683-2698|accumsan.convalli...|  
  63. 11|        Emi|1-467-270-1337|        est@nunc.com|  
  64. 12|      Caleb|1-683-212-0896|Suspendisse@Quisq...|  
  65. 13|   Florence|1-603-575-2444|sit.amet.dapibus@...|  
  66. 14|      Anika|1-856-828-7883|euismod@ligulaeli...|  
  67. 15|      Tarik|1-398-171-2268|turpis@felisorci.com|  
  68. 16|      Amena|1-878-250-3129|lorem.luctus.ut@s...|  
  69. 17|    Blossom|1-154-406-9596|Nunc.commodo.auct...|  
  70. 18|        Guy|1-869-521-3230|senectus.et.netus...|  
  71. 19|    Malachi|1-608-637-2772|Proin.mi.Aliquam@...|  
  72. 20|     Edward|1-711-710-6552|lectus@aliquetlib...|  
  73. +---+-----------+--------------+--------------------+  
  74. only showing top 20 rows  
  75.   
  76. students.show(false)  
  77. +---+-----------+--------------+-----------------------------------------+  
  78. |id |studentName|phone         |email                                    |  
  79. +---+-----------+--------------+-----------------------------------------+  
  80. |1  |Burke      |1-300-746-8446|ullamcorper.velit.in@ametnullaDonec.co.uk|  
  81. |2  |Kamal      |1-668-571-5046|pede.Suspendisse@interdumenim.edu        |  
  82. |3  |Olga       |1-956-311-1686|Aenean.eget.metus@dictumcursusNunc.edu   |  
  83. |4  |Belle      |1-246-894-6340|vitae.aliquet.nec@neque.co.uk            |  
  84. |5  |Trevor     |1-300-527-4967|dapibus.id@acturpisegestas.net           |  
  85. |6  |Laurel     |1-691-379-9921|adipiscing@consectetueripsum.edu         |  
  86. |7  |Sara       |1-608-140-1995|Donec.nibh@enimEtiamimperdiet.edu        |  
  87. |8  |Kaseem     |1-881-586-2689|cursus.et.magna@euismod.org              |  
  88. |9  |Lev        |1-916-367-5608|Vivamus.nisi@ipsumdolor.com              |  
  89. |10 |Maya       |1-271-683-2698|accumsan.convallis@ornarelectusjusto.edu |  
  90. |11 |Emi        |1-467-270-1337|est@nunc.com                             |  
  91. |12 |Caleb      |1-683-212-0896|Suspendisse@Quisque.edu                  |  
  92. |13 |Florence   |1-603-575-2444|sit.amet.dapibus@lacusAliquamrutrum.ca   |  
  93. |14 |Anika      |1-856-828-7883|euismod@ligulaelit.co.uk                 |  
  94. |15 |Tarik      |1-398-171-2268|turpis@felisorci.com                     |  
  95. |16 |Amena      |1-878-250-3129|lorem.luctus.ut@scelerisque.com          |  
  96. |17 |Blossom    |1-154-406-9596|Nunc.commodo.auctor@eratSed.co.uk        |  
  97. |18 |Guy        |1-869-521-3230|senectus.et.netus@lectusrutrum.com       |  
  98. |19 |Malachi    |1-608-637-2772|Proin.mi.Aliquam@estarcu.net             |  
  99. |20 |Edward     |1-711-710-6552|lectus@aliquetlibero.co.uk               |  
  100. +---+-----------+--------------+-----------------------------------------+  
  101. only showing top 20 rows  
  102.   
  103. students.show(10,false)  
  104.   
  105. +---+-----------+--------------+-----------------------------------------+  
  106. |id |studentName|phone         |email                                    |  
  107. +---+-----------+--------------+-----------------------------------------+  
  108. |1  |Burke      |1-300-746-8446|ullamcorper.velit.in@ametnullaDonec.co.uk|  
  109. |2  |Kamal      |1-668-571-5046|pede.Suspendisse@interdumenim.edu        |  
  110. |3  |Olga       |1-956-311-1686|Aenean.eget.metus@dictumcursusNunc.edu   |  
  111. |4  |Belle      |1-246-894-6340|vitae.aliquet.nec@neque.co.uk            |  
  112. |5  |Trevor     |1-300-527-4967|dapibus.id@acturpisegestas.net           |  
  113. |6  |Laurel     |1-691-379-9921|adipiscing@consectetueripsum.edu         |  
  114. |7  |Sara       |1-608-140-1995|Donec.nibh@enimEtiamimperdiet.edu        |  
  115. |8  |Kaseem     |1-881-586-2689|cursus.et.magna@euismod.org              |  
  116. |9  |Lev        |1-916-367-5608|Vivamus.nisi@ipsumdolor.com              |  
  117. |10 |Maya       |1-271-683-2698|accumsan.convallis@ornarelectusjusto.edu |  
  118. +---+-----------+--------------+-----------------------------------------+  
  119. only showing top 10 rows  

我們還可以使用head(n: Int)方法來采樣數據,這個函數也需要輸入一個參數標明需要采樣的行數,而且這個函數返回的是Row數組,我們需要遍歷打印。當然,我們也可以使用head()函數直接打印,這個函數只是返回數據的一行,類型也是Row。

[python]  view plain  copy
 
 print?
  1. students.head(5).foreach(println)  
  2. [1,Burke,1-300-746-8446,ullamcorper.velit.in@ametnullaDonec.co.uk]  
  3. [2,Kamal,1-668-571-5046,pede.Suspendisse@interdumenim.edu]  
  4. [3,Olga,1-956-311-1686,Aenean.eget.metus@dictumcursusNunc.edu]  
  5. [4,Belle,1-246-894-6340,vitae.aliquet.nec@neque.co.uk]  
  6. [5,Trevor,1-300-527-4967,dapibus.id@acturpisegestas.net]  
  7. println(students.head())  
  8. [1,Burke,1-300-746-8446,ullamcorper.velit.in@ametnullaDonec.co.uk]  

除了show、head函數。我們還可以使用first和take函數,他們分別調用head()和head(n)

[python]  view plain  copy
 
 print?
  1. println(students.first())  
  2. [1,Burke,1-300-746-8446,ullamcorper.velit.in@ametnullaDonec.co.uk]  
  3. students.take(5).foreach(println)  
  4. [1,Burke,1-300-746-8446,ullamcorper.velit.in@ametnullaDonec.co.uk]  
  5. [2,Kamal,1-668-571-5046,pede.Suspendisse@interdumenim.edu]  
  6. [3,Olga,1-956-311-1686,Aenean.eget.metus@dictumcursusNunc.edu]  
  7. [4,Belle,1-246-894-6340,vitae.aliquet.nec@neque.co.uk]  
  8. [5,Trevor,1-300-527-4967,dapibus.id@acturpisegestas.net]  

查詢DataFrame里面的列
  正如你所看到的,所有的DataFrame里面的列都是有名稱的。Select函數可以幫助我們從DataFrame中選擇需要的列,並且返回一個全新的DataFrame,下面我將此進行介紹。

  1、只選擇一列。假如我們只想從DataFrame中選擇email這列,因為DataFrame是不可變的(immutable),所以這個操作會返回一個新的DataFrame:

[python]  view plain  copy
 
 print?
  1. val emailDataFrame: DataFrame = students.select("email")  


現在我們有一個名叫emailDataFrame全新的DataFrame,而且其中只包含了email這列,讓我們使用show來看看是否是這樣的:

 

 

[python]  view plain  copy
 
 print?
  1. emailDataFrame.show(3)   
  2. +--------------------+  
  3. |               email|  
  4. +--------------------+  
  5. |ullamcorper.velit...|  
  6. |pede.Suspendisse@...|  
  7. |Aenean.eget.metus...|  
  8. +--------------------+  
  9. only showing top 3 rows  

2、選擇多列。其實select函數支持選擇多列。

[python]  view plain  copy
 
 print?
  1. val studentEmailDF = students.select("studentName", "email")  
  2. studentEmailDF.show(5)  
  3. +-----------+--------------------+  
  4. |studentName|               email|  
  5. +-----------+--------------------+  
  6. |      Burke|ullamcorper.velit...|  
  7. |      Kamal|pede.Suspendisse@...|  
  8. |       Olga|Aenean.eget.metus...|  
  9. |      Belle|vitae.aliquet.nec...|  
  10. |     Trevor|dapibus.id@acturp...|  
  11. +-----------+--------------------+  
  12. only showing top 5 rows  

需要主要的是,我們select列的時候,需要保證select的列是有效的,換句話說,就是必須保證select的列是printSchema打印出來的。如果列的名稱是無效的,將會出現org.apache.spark.sql.AnalysisException異常,如下:

[python]  view plain  copy
 
 print?
  1. val studentEmailDF = students.select("studentName", "iteblog")  
  2. studentEmailDF.show(5)  
  3.   
  4. Exception in thread "main" org.apache.spark.sql.AnalysisException: cannot resolve 'iteblog' given input columns id, studentName, phone, email;  

根據條件過濾數據
  現在我們已經知道如何在DataFrame中選擇需要的列,讓我們來看看如何根據條件來過濾DataFrame里面的數據。對應基於Row的數據,我們可以將DataFrame看作是普通的Scala集合,然后我們根據需要的條件進行相關的過濾,為了展示清楚,我在語句沒后面都用show函數展示過濾的結果。

[python]  view plain  copy
 
 print?
  1. students.filter("id > 5").show(7)   
  2. +---+-----------+--------------+--------------------+  
  3. | id|studentName|         phone|               email|  
  4. +---+-----------+--------------+--------------------+  
  5. |  6|     Laurel|1-691-379-9921|adipiscing@consec...|  
  6. |  7|       Sara|1-608-140-1995|Donec.nibh@enimEt...|  
  7. |  8|     Kaseem|1-881-586-2689|cursus.et.magna@e...|  
  8. |  9|        Lev|1-916-367-5608|Vivamus.nisi@ipsu...|  
  9. 10|       Maya|1-271-683-2698|accumsan.convalli...|  
  10. 11|        Emi|1-467-270-1337|        est@nunc.com|  
  11. 12|      Caleb|1-683-212-0896|Suspendisse@Quisq...|  
  12. 13|   Florence|1-603-575-2444|sit.amet.dapibus@...|  
  13. 14|      Anika|1-856-828-7883|euismod@ligulaeli...|  
  14. 15|      Tarik|1-398-171-2268|turpis@felisorci.com|  
  15. +---+-----------+--------------+--------------------+  
  16. only showing top 10 rows  
  17.   
  18. students.filter("studentName =''").show(7)   
  19. +---+-----------+--------------+--------------------+  
  20. | id|studentName|         phone|               email|  
  21. +---+-----------+--------------+--------------------+  
  22. 21|           |1-598-439-7549|consectetuer.adip...|  
  23. 32|           |1-184-895-9602|accumsan.laoreet@...|  
  24. 45|           |1-245-752-0481|Suspendisse.eleif...|  
  25. 83|           |1-858-810-2204|sociis.natoque@eu...|  
  26. 94|           |1-443-410-7878|Praesent.eu.nulla...|  
  27. +---+-----------+--------------+--------------------+  

注意看第一個過濾語句,雖然id被解析成String了,但是程序依然正確地做出了比較。我們也可以對多個條件進行過濾:

[python]  view plain  copy
 
 print?
  1. students.filter("studentName ='' OR studentName = 'NULL'").show(7)   
  2. +---+-----------+--------------+--------------------+  
  3. | id|studentName|         phone|               email|  
  4. +---+-----------+--------------+--------------------+  
  5. 21|           |1-598-439-7549|consectetuer.adip...|  
  6. 32|           |1-184-895-9602|accumsan.laoreet@...|  
  7. 33|       NULL|1-105-503-0141|Donec@Inmipede.co.uk|  
  8. 45|           |1-245-752-0481|Suspendisse.eleif...|  
  9. 83|           |1-858-810-2204|sociis.natoque@eu...|  
  10. 94|           |1-443-410-7878|Praesent.eu.nulla...|  
  11. +---+-----------+--------------+--------------------+  

我們還可以采用類SQL的語法對數據進行過濾:

[python]  view plain  copy
 
 print?
  1. students.filter("SUBSTR(studentName,0,1) ='M'").show(7)   
  2. +---+-----------+--------------+--------------------+  
  3. | id|studentName|         phone|               email|  
  4. +---+-----------+--------------+--------------------+  
  5. 10|       Maya|1-271-683-2698|accumsan.convalli...|  
  6. 19|    Malachi|1-608-637-2772|Proin.mi.Aliquam@...|  
  7. 24|    Marsden|1-477-629-7528|Donec.dignissim.m...|  
  8. 37|      Maggy|1-910-887-6777|facilisi.Sed.nequ...|  
  9. 61|     Maxine|1-422-863-3041|aliquet.molestie....|  
  10. 77|      Maggy|1-613-147-4380| pellentesque@mi.net|  
  11. 97|    Maxwell|1-607-205-1273|metus.In@musAenea...|  
  12. +---+-----------+--------------+--------------------+  
  13. only showing top 7 rows  

對DataFrame里面的數據進行排序
使用sort函數我們可以對DataFrame中指定的列進行排序:

[python]  view plain  copy
 
 print?
  1. students.sort(students("studentName").desc).show(7)   
  2. +---+-----------+--------------+--------------------+  
  3. | id|studentName|         phone|               email|  
  4. +---+-----------+--------------+--------------------+  
  5. 50|      Yasir|1-282-511-4445|eget.odio.Aliquam...|  
  6. 52|       Xena|1-527-990-8606|in.faucibus.orci@...|  
  7. 86|     Xandra|1-677-708-5691|libero@arcuVestib...|  
  8. 43|     Wynter|1-440-544-1851|amet.risus.Donec@...|  
  9. 31|    Wallace|1-144-220-8159| lorem.lorem@non.net|  
  10. 66|      Vance|1-268-680-0857|pellentesque@netu...|  
  11. 41|     Tyrone|1-907-383-5293|non.bibendum.sed@...|  
  12. +---+-----------+--------------+--------------------+  
  13. only showing top 7 rows  

也可以對多列進行排序:

[python]  view plain  copy
 
 print?
  1. students.sort("studentName", "id").show(10)   
  2. +---+-----------+--------------+--------------------+  
  3. | id|studentName|         phone|               email|  
  4. +---+-----------+--------------+--------------------+  
  5. 21|           |1-598-439-7549|consectetuer.adip...|  
  6. 32|           |1-184-895-9602|accumsan.laoreet@...|  
  7. 45|           |1-245-752-0481|Suspendisse.eleif...|  
  8. 83|           |1-858-810-2204|sociis.natoque@eu...|  
  9. 94|           |1-443-410-7878|Praesent.eu.nulla...|  
  10. 91|       Abel|1-530-527-7467|    urna@veliteu.edu|  
  11. 69|       Aiko|1-682-230-7013|turpis.vitae.puru...|  
  12. 47|       Alma|1-747-382-6775|    nec.enim@non.org|  
  13. 26|      Amela|1-526-909-2605| in@vitaesodales.edu|  
  14. 16|      Amena|1-878-250-3129|lorem.luctus.ut@s...|  
  15. +---+-----------+--------------+--------------------+  
  16. only showing top 10 rows  

從上面的結果我們可以看出,默認是按照升序進行排序的。我們也可以將上面的語句寫成下面的:

[python]  view plain  copy
 
 print?
  1. students.sort(students("studentName").asc, students("id").asc).show(10)   

這兩個語句運行的效果是一致的。

對列進行重命名
  如果我們對DataFrame中默認的列名不感興趣,我們可以在select的時候利用as對其進行重命名,下面的列子將studentName重命名為name,而email這列名字不變:

[python]  view plain  copy
 
 print?
  1. students.select(students("studentName").as("name"), students("email")).show(10)  
  2. +--------+--------------------+  
  3. |    name|               email|  
  4. +--------+--------------------+  
  5. |   Burke|ullamcorper.velit...|  
  6. |   Kamal|pede.Suspendisse@...|  
  7. |    Olga|Aenean.eget.metus...|  
  8. |   Belle|vitae.aliquet.nec...|  
  9. |  Trevor|dapibus.id@acturp...|  
  10. |  Laurel|adipiscing@consec...|  
  11. |    Sara|Donec.nibh@enimEt...|  
  12. |  Kaseem|cursus.et.magna@e...|  
  13. |     Lev|Vivamus.nisi@ipsu...|  
  14. |    Maya|accumsan.convalli...|  
  15. +--------+--------------------+  
  16. only showing top 10 rows  

將DataFrame看作是關系型數據表
  DataFrame的一個強大之處就是我們可以將它看作是一個關系型數據表,然后在其上運行SQL查詢語句,只要我們進行下面兩步即可實現:
  (1)、將DataFrame注冊成一張名為students的表:

[python]  view plain  copy
 
 print?
  1. students.registerTempTable("students")   

(2)、然后我們在其上用標准的SQL進行查詢:

[python]  view plain  copy
 
 print?
  1. sqlContext.sql("select * from students where studentName!='' order by email desc").show(7)  
  2.   
  3. +---+-----------+--------------+--------------------+  
  4. | id|studentName|         phone|               email|  
  5. +---+-----------+--------------+--------------------+  
  6. 87|      Selma|1-601-330-4409|vulputate.velit@p...|  
  7. 96|   Channing|1-984-118-7533|viverra.Donec.tem...|  
  8. |  4|      Belle|1-246-894-6340|vitae.aliquet.nec...|  
  9. 78|       Finn|1-213-781-6969|vestibulum.massa@...|  
  10. 53|     Kasper|1-155-575-9346|velit.eget@pedeCu...|  
  11. 63|      Dylan|1-417-943-8961|vehicula.aliquet@...|  
  12. 35|     Cadman|1-443-642-5919|ut.lacus@adipisci...|  
  13. +---+-----------+--------------+--------------------+  
  14. only showing top 7 rows  

對兩個DataFrame進行Join操作
  前面我們已經知道如何將DataFrame注冊成一張表,現在我們來看看如何使用普通的SQL對兩個DataFrame進行Join操作。

  1、內聯:內聯是默認的Join操作,它僅僅返回兩個DataFrame都匹配到的結果,來看看下面的例子:

[python]  view plain  copy
 
 print?
  1. val students1 = sqlContext.csvFile(filePath = "E:\\StudentPrep1.csv", useHeader = true, delimiter = '|')  
  2. val students2 = sqlContext.csvFile(filePath = "E:\\StudentPrep2.csv", useHeader = true, delimiter = '|')  
  3. val studentsJoin = students1.join(students2, students1("id") === students2("id"))  
  4. studentsJoin.show(studentsJoin.count.toInt)  
  5.   
  6. +---+-----------+--------------+--------------------+---+------------------+--------------+--------------------+  
  7. | id|studentName|         phone|               email| id|       studentName|         phone|               email|  
  8. +---+-----------+--------------+--------------------+---+------------------+--------------+--------------------+  
  9. |  1|      Burke|1-300-746-8446|ullamcorper.velit...|  1|BurkeDifferentName|1-300-746-8446|ullamcorper.velit...|  
  10. |  2|      Kamal|1-668-571-5046|pede.Suspendisse@...|  2|KamalDifferentName|1-668-571-5046|pede.Suspendisse@...|  
  11. |  3|       Olga|1-956-311-1686|Aenean.eget.metus...|  3|              Olga|1-956-311-1686|Aenean.eget.metus...|  
  12. |  4|      Belle|1-246-894-6340|vitae.aliquet.nec...|  4|BelleDifferentName|1-246-894-6340|vitae.aliquet.nec...|  
  13. |  5|     Trevor|1-300-527-4967|dapibus.id@acturp...|  5|            Trevor|1-300-527-4967|dapibusDifferentE...|  
  14. |  6|     Laurel|1-691-379-9921|adipiscing@consec...|  6|LaurelInvalidPhone|     000000000|adipiscing@consec...|  
  15. |  7|       Sara|1-608-140-1995|Donec.nibh@enimEt...|  7|              Sara|1-608-140-1995|Donec.nibh@enimEt...|  
  16. |  8|     Kaseem|1-881-586-2689|cursus.et.magna@e...|  8|            Kaseem|1-881-586-2689|cursus.et.magna@e...|  
  17. |  9|        Lev|1-916-367-5608|Vivamus.nisi@ipsu...|  9|               Lev|1-916-367-5608|Vivamus.nisi@ipsu...|  
  18. 10|       Maya|1-271-683-2698|accumsan.convalli...| 10|              Maya|1-271-683-2698|accumsan.convalli...|  
  19. +---+-----------+--------------+--------------------+---+------------------+--------------+--------------------+  

2、右外聯:在內連接的基礎上,還包含右表中所有不符合條件的數據行,並在其中的左表列填寫NULL ,來看看下面的實例:

[python]  view plain  copy
 
 print?
  1. val studentsRightOuterJoin = students1.join(students2, students1("id") === students2("id"), "right_outer")  
  2. studentsRightOuterJoin.show(studentsRightOuterJoin.count.toInt)  
  3. +----+-----------+--------------+--------------------+---+--------------------+--------------+--------------------+  
  4. |  id|studentName|         phone|               email| id|         studentName|         phone|               email|  
  5. +----+-----------+--------------+--------------------+---+--------------------+--------------+--------------------+  
  6. |   1|      Burke|1-300-746-8446|ullamcorper.velit...|  1|  BurkeDifferentName|1-300-746-8446|ullamcorper.velit...|  
  7. |   2|      Kamal|1-668-571-5046|pede.Suspendisse@...|  2|  KamalDifferentName|1-668-571-5046|pede.Suspendisse@...|  
  8. |   3|       Olga|1-956-311-1686|Aenean.eget.metus...|  3|                Olga|1-956-311-1686|Aenean.eget.metus...|  
  9. |   4|      Belle|1-246-894-6340|vitae.aliquet.nec...|  4|  BelleDifferentName|1-246-894-6340|vitae.aliquet.nec...|  
  10. |   5|     Trevor|1-300-527-4967|dapibus.id@acturp...|  5|              Trevor|1-300-527-4967|dapibusDifferentE...|  
  11. |   6|     Laurel|1-691-379-9921|adipiscing@consec...|  6|  LaurelInvalidPhone|     000000000|adipiscing@consec...|  
  12. |   7|       Sara|1-608-140-1995|Donec.nibh@enimEt...|  7|                Sara|1-608-140-1995|Donec.nibh@enimEt...|  
  13. |   8|     Kaseem|1-881-586-2689|cursus.et.magna@e...|  8|              Kaseem|1-881-586-2689|cursus.et.magna@e...|  
  14. |   9|        Lev|1-916-367-5608|Vivamus.nisi@ipsu...|  9|                 Lev|1-916-367-5608|Vivamus.nisi@ipsu...|  
  15. |  10|       Maya|1-271-683-2698|accumsan.convalli...| 10|                Maya|1-271-683-2698|accumsan.convalli...|  
  16. |null|       null|          null|                null|999|LevUniqueToSecondRDD|1-916-367-5608|Vivamus.nisi@ipsu...|  
  17. +----+-----------+--------------+--------------------+---+--------------------+--------------+--------------------+  

3、左外聯:在內連接的基礎上,還包含左表中所有不符合條件的數據行,並在其中的右表列填寫NULL ,同樣我們來看看下面的實例:

[python]  view plain  copy
 
 print?
  1. val studentsLeftOuterJoin = students1.join(students2, students1("id") === students2("id"), "left_outer")  
  2. studentsLeftOuterJoin.show(studentsLeftOuterJoin.count.toInt)  
  3. +---+-----------+--------------+--------------------+----+------------------+--------------+--------------------+  
  4. | id|studentName|         phone|               email|  id|       studentName|         phone|               email|  
  5. +---+-----------+--------------+--------------------+----+------------------+--------------+--------------------+  
  6. |  1|      Burke|1-300-746-8446|ullamcorper.velit...|   1|BurkeDifferentName|1-300-746-8446|ullamcorper.velit...|  
  7. |  2|      Kamal|1-668-571-5046|pede.Suspendisse@...|   2|KamalDifferentName|1-668-571-5046|pede.Suspendisse@...|  
  8. |  3|       Olga|1-956-311-1686|Aenean.eget.metus...|   3|              Olga|1-956-311-1686|Aenean.eget.metus...|  
  9. |  4|      Belle|1-246-894-6340|vitae.aliquet.nec...|   4|BelleDifferentName|1-246-894-6340|vitae.aliquet.nec...|  
  10. |  5|     Trevor|1-300-527-4967|dapibus.id@acturp...|   5|            Trevor|1-300-527-4967|dapibusDifferentE...|  
  11. |  6|     Laurel|1-691-379-9921|adipiscing@consec...|   6|LaurelInvalidPhone|     000000000|adipiscing@consec...|  
  12. |  7|       Sara|1-608-140-1995|Donec.nibh@enimEt...|   7|              Sara|1-608-140-1995|Donec.nibh@enimEt...|  
  13. |  8|     Kaseem|1-881-586-2689|cursus.et.magna@e...|   8|            Kaseem|1-881-586-2689|cursus.et.magna@e...|  
  14. |  9|        Lev|1-916-367-5608|Vivamus.nisi@ipsu...|   9|               Lev|1-916-367-5608|Vivamus.nisi@ipsu...|  
  15. 10|       Maya|1-271-683-2698|accumsan.convalli...|  10|              Maya|1-271-683-2698|accumsan.convalli...|  
  16. 11|    iteblog|        999999| iteblog@iteblog.com|null|              null|          null|                null|  
  17. +---+-----------+--------------+--------------------+----+------------------+--------------+--------------------+  

將DataFrame保存成文件
  下面我來介紹如何將DataFrame保存到一個文件里面。前面我們加載csv文件用到了load函數,與之對於的用於保存文件可以使用save函數。具體操作包括以下兩步:

  1、首先創建一個map對象,用於存儲一些save函數需要用到的一些屬性。這里我將制定保存文件的存放路徑和csv的頭信息。

[python]  view plain  copy
 
 print?
  1. val saveOptions = Map("header" -> "true", "path" -> "iteblog.csv")  

為了基於學習的態度,我們從DataFrame里面選擇出studentName和email兩列,並且將studentName的列名重定義為name。

[python]  view plain  copy
 
 print?
  1. val copyOfStudents = students.select(students("studentName").as("name"), students("email"))  

2、下面我們調用save函數保存上面的DataFrame數據到iteblog.csv文件夾中

[python]  view plain  copy
 
 print?
  1. copyOfStudents.write.format("com.databricks.spark.csv").mode(SaveMode.Overwrite).options(saveOptions).save()  

mode函數可以接收的參數有Overwrite、Append、Ignore和ErrorIfExists。從名字就可以很好的理解,Overwrite代表覆蓋目錄下之前存在的數據;Append代表給指定目錄下追加數據;Ignore代表如果目錄下已經有文件,那就什么都不執行;ErrorIfExists代表如果保存目錄下存在文件,那么拋出相應的異常。

  需要注意的是,上述path參數指定的是保存文件夾,並不是最后的保存文件名。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM