zoukankan      html  css  js  c++  java
  • 转】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参数指定的是保存文件夹,并不是最后的保存文件名。

  • 相关阅读:
    [poj2778]DNA Sequence(AC自动机+矩阵快速幂)
    密码学学习笔记
    [hdu3695]Computer Virus on Planet Pandora(AC自动机)
    [hdu1277]全文检索(AC自动机)
    [hdu3065]病毒侵袭持续中(AC自动机)
    [hdu2896]病毒侵袭(AC自动机)
    lintcode-84-落单的数 III
    lintcode-83-落单的数 II
    lintcode-79-最长公共子串
    lintcode-78-最长公共前缀
  • 原文地址:https://www.cnblogs.com/zlslch/p/6039520.html
Copyright © 2011-2022 走看看