原博文出自于:  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文件中:

  1. libraryDependencies += "com.databricks" % "spark-csv_2.10" % "1.3.0"

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

  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]),部分代码片段如下:

  1. import org.apache.spark.SparkConf
  2. val conf = new SparkConf().setAppName("csvDataFrame").setMaster("local[2]")

7、使用SparkConf初始化SparkContext对象,SparkContext是进入Spark的核心切入点:

  1. val sc = new SparkContext(conf)

在Spark中查询数据最简单的一种方式就是使用SQL查询,所以我们可以定义一个SQLContext对象:

  1. val sqlContext=new SQLContext(sc)

8、现在我们就可以加载事先准备好的数据了:

  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文件:

  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文件的部分数据集:

  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两个参数,如下:

  1. case class Employee(id: Int, name: String)

和先前一样,我们分别定义SparkConf、SparkContext以及SQLContext:

  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,如下:

  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的两个参数,并且类型都一致。

  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函数来指定列名:

  1. val empFrameWithRenamedColumns = sqlContext.createDataFrame(listOfEmployees).withColumnRenamed("id", "empId")
  2. empFrameWithRenamedColumns.printSchema
  3. root
  4. |-- empId: integer (nullable = false)
  5. |-- name: string (nullable = true)

5、我们可以使用Spark支持的SQL功能来查询相关的数据。在使用这个功能之前,我们必须先对DataFrame注册成一张临时表,我们可以使用registerTempTable函数实现,如下:

  1. empFrameWithRenamedColumns.registerTempTable("employeeTable")

6、现在我们就可以使用SQL语句来查询DataFrame里面的数据了:

  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类的集合对象:

  1. def createDataFrame[A <: Product : TypeTag](rdd: RDD[A]): DataFrame

而case class类就是继承了Product。我们所熟悉的TupleN类型也是继承了scala.Product类的,所以我们也可以通过TupleN来创建DataFrame:

  1. val mobiles=sqlContext.createDataFrame(Seq((1,"Android"), (2, "iPhone"))) mobiles.printSchema mobiles.show()
  2. root
  3. |-- _1: integer (nullable = false)
  4. |-- _2: string (nullable = true)
  5. +---+-------+
  6. | _1|     _2|
  7. +---+-------+
  8. |  1|Android|
  9. |  2| iPhone|
  10. +---+-------+

我们知道,Tuple2的默认两个参数名字分别是_1和_2,同样,我们如果对这个默认的名字不是特别喜欢,我们也是可以通过withColumnRenamed函数对默认反射的列名进行重命名。

三、操作DataFrame

  在前面的文章中,我们介绍了如何创建DataFrame。本文将介绍如何操作DataFrame里面的数据和打印出DataFrame里面数据的模式

打印DataFrame里面的模式
  在创建完DataFrame之后,我们一般都会查看里面数据的模式,我们可以通过printSchema函数来查看。它会打印出列的名称和类型:

  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的输出则如下:

  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)。来看看怎么使用吧:

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

我们还可以使用head(n: Int)方法来采样数据,这个函数也需要输入一个参数标明需要采样的行数,而且这个函数返回的是Row数组,我们需要遍历打印。当然,我们也可以使用head()函数直接打印,这个函数只是返回数据的一行,类型也是Row。

  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)

  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:

  1. val emailDataFrame: DataFrame = students.select("email")

现在我们有一个名叫emailDataFrame全新的DataFrame,而且其中只包含了email这列,让我们使用show来看看是否是这样的:

  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函数支持选择多列。

  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异常,如下:

  1. val studentEmailDF = students.select("studentName", "iteblog")
  2. studentEmailDF.show(5)
  3. 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函数展示过滤的结果。

  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. students.filter("studentName =''").show(7)
  18. +---+-----------+--------------+--------------------+
  19. | id|studentName|         phone|               email|
  20. +---+-----------+--------------+--------------------+
  21. | 21|           |1-598-439-7549|consectetuer.adip...|
  22. | 32|           |1-184-895-9602|accumsan.laoreet@...|
  23. | 45|           |1-245-752-0481|Suspendisse.eleif...|
  24. | 83|           |1-858-810-2204|sociis.natoque@eu...|
  25. | 94|           |1-443-410-7878|Praesent.eu.nulla...|
  26. +---+-----------+--------------+--------------------+

注意看第一个过滤语句,虽然id被解析成String了,但是程序依然正确地做出了比较。我们也可以对多个条件进行过滤:

  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的语法对数据进行过滤:

  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中指定的列进行排序:

  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

也可以对多列进行排序:

  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

从上面的结果我们可以看出,默认是按照升序进行排序的。我们也可以将上面的语句写成下面的:

  1. students.sort(students("studentName").asc, students("id").asc).show(10)

这两个语句运行的效果是一致的。

对列进行重命名
  如果我们对DataFrame中默认的列名不感兴趣,我们可以在select的时候利用as对其进行重命名,下面的列子将studentName重命名为name,而email这列名字不变:

  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的表:

  1. students.registerTempTable("students")

(2)、然后我们在其上用标准的SQL进行查询:

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

对两个DataFrame进行Join操作
  前面我们已经知道如何将DataFrame注册成一张表,现在我们来看看如何使用普通的SQL对两个DataFrame进行Join操作。

  1、内联:内联是默认的Join操作,它仅仅返回两个DataFrame都匹配到的结果,来看看下面的例子:

  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. | id|studentName|         phone|               email| id|       studentName|         phone|               email|
  7. +---+-----------+--------------+--------------------+---+------------------+--------------+--------------------+
  8. |  1|      Burke|1-300-746-8446|ullamcorper.velit...|  1|BurkeDifferentName|1-300-746-8446|ullamcorper.velit...|
  9. |  2|      Kamal|1-668-571-5046|pede.Suspendisse@...|  2|KamalDifferentName|1-668-571-5046|pede.Suspendisse@...|
  10. |  3|       Olga|1-956-311-1686|Aenean.eget.metus...|  3|              Olga|1-956-311-1686|Aenean.eget.metus...|
  11. |  4|      Belle|1-246-894-6340|vitae.aliquet.nec...|  4|BelleDifferentName|1-246-894-6340|vitae.aliquet.nec...|
  12. |  5|     Trevor|1-300-527-4967|dapibus.id@acturp...|  5|            Trevor|1-300-527-4967|dapibusDifferentE...|
  13. |  6|     Laurel|1-691-379-9921|adipiscing@consec...|  6|LaurelInvalidPhone|     000000000|adipiscing@consec...|
  14. |  7|       Sara|1-608-140-1995|Donec.nibh@enimEt...|  7|              Sara|1-608-140-1995|Donec.nibh@enimEt...|
  15. |  8|     Kaseem|1-881-586-2689|cursus.et.magna@e...|  8|            Kaseem|1-881-586-2689|cursus.et.magna@e...|
  16. |  9|        Lev|1-916-367-5608|Vivamus.nisi@ipsu...|  9|               Lev|1-916-367-5608|Vivamus.nisi@ipsu...|
  17. | 10|       Maya|1-271-683-2698|accumsan.convalli...| 10|              Maya|1-271-683-2698|accumsan.convalli...|
  18. +---+-----------+--------------+--------------------+---+------------------+--------------+--------------------+

2、右外联:在内连接的基础上,还包含右表中所有不符合条件的数据行,并在其中的左表列填写NULL ,来看看下面的实例:

  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 ,同样我们来看看下面的实例:

  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的头信息。

  1. val saveOptions = Map("header" -> "true", "path" -> "iteblog.csv")

为了基于学习的态度,我们从DataFrame里面选择出studentName和email两列,并且将studentName的列名重定义为name。

  1. val copyOfStudents = students.select(students("studentName").as("name"), students("email"))

2、下面我们调用save函数保存上面的DataFrame数据到iteblog.csv文件夹中

  1. copyOfStudents.write.format("com.databricks.spark.csv").mode(SaveMode.Overwrite).options(saveOptions).save()

mode函数可以接收的参数有Overwrite、Append、Ignore和ErrorIfExists。从名字就可以很好的理解,Overwrite代表覆盖目录下之前存在的数据;Append代表给指定目录下追加数据;Ignore代表如果目录下已经有文件,那就什么都不执行;ErrorIfExists代表如果保存目录下存在文件,那么抛出相应的异常。

  需要注意的是,上述path参数指定的是保存文件夹,并不是最后的保存文件名。

转】Spark DataFrames入门指南:创建和操作DataFrame的更多相关文章

  1. [转] Spark快速入门指南 – Spark安装与基础使用

    [From] https://blog.csdn.net/w405722907/article/details/77943331 Spark快速入门指南 – Spark安装与基础使用 2017年09月 ...

  2. Spark高速入门指南(Quick Start Spark)

    版权声明:本博客已经不再更新.请移步到Hadoop技术博客:https://www.iteblog.com https://blog.csdn.net/w397090770/article/detai ...

  3. Spark Streaming 入门指南

    这篇博客帮你开始使用Apache Spark Streaming和HBase.Spark Streaming是核心Spark API的一个扩展,它能够处理连续数据流. Spark Streaming是 ...

  4. 关于 HSSF 和 XSSF 功能的开发者入门指南 (Apache POI 操作 Excel)

    关于 HSSF 和 XSSF 功能的开发者入门指南 笔者深夜无眠,特此对本文翻译一部分,未完成部分待后续更新 本文源文地址 意欲使用 HSSF 和 XSSF 功能快熟读写电子表格?那本文就是为你而写的 ...

  5. 【转】Spark快速入门指南

    尊重版权,原文:http://blog.csdn.net/macyang/article/details/7100523   - Spark是什么? Spark is a MapReduce-like ...

  6. Spark—GraphX编程指南

    Spark系列面试题 Spark面试题(一) Spark面试题(二) Spark面试题(三) Spark面试题(四) Spark面试题(五)--数据倾斜调优 Spark面试题(六)--Spark资源调 ...

  7. javaCV入门指南:调用FFmpeg原生API和JavaCV是如何封装了FFmpeg的音视频操作?

    通过"javaCV入门指南:序章 "大家知道了处理音视频流媒体的前置基本知识,基本知识包含了像素格式.编解码格式.封装格式.网络协议以及一些音视频专业名词,专业名词不会赘述,自行搜 ...

  8. redis入门指南(二)—— 数据操作相关命令

    写在前面 以下绝大部分内容取材于<redis入门指南>,部分结合个人知识,实践后得出. 只记录重要,明确,属于新知的相关内容,杜绝冗余和重复. 字符串 1.字符串类型是redis中最常见的 ...

  9. Apache Spark 2.2.0 中文文档 - Spark Streaming 编程指南 | ApacheCN

    Spark Streaming 编程指南 概述 一个入门示例 基础概念 依赖 初始化 StreamingContext Discretized Streams (DStreams)(离散化流) Inp ...

随机推荐

  1. dom4j API使用简介

    dom4j API使用简介 功能简介 dom4j是一个Java的XML API,类似于jdom,用来读写XML文件的.dom4j是一个非常非常优秀的Java XML API,具有性能优异.功能强大和极 ...

  2. View Transform(视图变换)详解

    http://www.cnblogs.com/graphics/archive/2012/07/12/2476413.html 什么是View Transform 我们可以用照相机的原理来阐释3D图形 ...

  3. Projective Texture的原理与实现

    http://blog.csdn.net/xukunn1226/article/details/775644 Projective Texture是比较常见的一种技术,实现起来代码也就区区的不过百行, ...

  4. Redis 网络通信及连接机制学习

    看了这篇文章 http://blog.nosqlfan.com/html/4153.html 本文所述内容基于 Redis2.6 及以上版本. 注:在客户端通过 info 命令可以查看服务器版本信息, ...

  5. android利用数字证书对程序签名

     签名的必要性 1.  防止你已安装的应用被恶意的第三方覆盖或替换掉. 2.  开发者的身份标识,签名可以防止抵赖等事件的发生. 开发Android的人这么多,完全有可能大家都把类名,包名起成了一个同 ...

  6. 瞎折腾之 NHibernate ORM框架的接触(MVC + Repository源码)(一)

    在这炮火连天.技术更新迅猛的年代,不接触了解.甚至会用2~3种框架都不好意思说自己有多少年工作经验.况且出去面试也会有点吹牛的底子嘛. 这次折腾了NHibernate.其实这些ORM框架封装好了都是给 ...

  7. [原创] - C#编程大幅提高OUTLOOK的邮件搜索能力!

    使用OUTLOOK, 你有没有遇到过上图的问题? 多达18419封邮件! 太多了, 每次想找一个邮件都非常耗时, 想办法解决这个问题成了一件非常紧迫的事情. 利用MS Search当然可以, 但是它太 ...

  8. nanakon

    1.安装python pip3 install tornado pip3 install pymysql pip3 install qiniu pip3 install pillow 2.安装mysq ...

  9. 文件IO一些注意的地方

    两个各自独立的进程各自打开同一个文件,则每个进程都有各自的文件表项.这是因为每个进程都有它自己对该文件的当前偏移量.但是对一个给定的文件只有一个v节点表项.lseek()只修改文件表项中的当前文件偏移 ...

  10. 切换PS工具栏里的快捷键

    工具箱(多种工具共用一个快捷键的可同时按[Shift]加此快捷键选取,可以在[常规]'快捷键[Ctrl]+[k]'里设置是否使用[Shift]切换) 其它快捷键: 矩形.椭圆选框工具[M] 裁剪工具[ ...