将DataFrame写成文件方法有很多
最简单的将DataFrame转换成RDD,通过saveASTextFile进行保存但是这个方法存在一些局限性:
1.将DataFrame转换成RDD或导致数据结构的改变
2.RDD的saveASTextFile如果文件存在则无法写入,也就意味着数据只能覆盖无法追加,对于有数据追加需求的人很不友好
3.如果数据需要二次处理,RDD指定分隔符比较繁琐

基于以上原因,在研读了Spark的官方文档后,决定采取DataFrame的自带方法 write 来实现。
此处采用mysql的数据作为数据源,读取mysql的方法在 Spark:读取mysql数据作为DataFrame 有详细介绍。

1.mysql的信息

mysql的信息我保存在了外部的配置文件,这样方便后续的配置添加。

  1. //配置文件示例:
  2. [hdfs@iptve2e03 tmp_lillcol]$ cat job.properties
  3. #mysql数据库配置
  4. mysql.driver=com.mysql.jdbc.Driver
  5. mysql.url=jdbc:mysql://127.0.0.1:3306/database1?useSSL=false&autoReconnect=true&failOverReadOnly=false&rewriteBatchedStatements=true
  6. mysql.username=user
  7. mysql.password=123456

2.需要的jar依赖

sbt版本,maven的对应修改即可

  1. libraryDependencies += "org.apache.spark" % "spark-core_2.10" % "1.6.0-cdh5.7.2"
  2. libraryDependencies += "org.apache.spark" % "spark-sql_2.10" % "1.6.0-cdh5.7.2"
  3. libraryDependencies += "org.apache.spark" % "spark-hive_2.10" % "1.6.0-cdh5.7.2"
  4. libraryDependencies += "org.apache.hbase" % "hbase-client" % "1.2.0-cdh5.7.2"
  5. libraryDependencies += "org.apache.hbase" % "hbase-server" % "1.2.0-cdh5.7.2"
  6. libraryDependencies += "org.apache.hbase" % "hbase-common" % "1.2.0-cdh5.7.2"
  7. libraryDependencies += "org.apache.hbase" % "hbase-protocol" % "1.2.0-cdh5.7.2"
  8. libraryDependencies += "mysql" % "mysql-connector-java" % "5.1.38"
  9. libraryDependencies += "org.apache.spark" % "spark-streaming_2.10" % "1.6.0-cdh5.7.2"
  10. libraryDependencies += "com.yammer.metrics" % "metrics-core" % "2.2.0"

3.完整实现代码

  1. import java.io.FileInputStream
  2. import java.util.Properties
  3.  
  4. import org.apache.spark.sql.hive.HiveContext
  5. import org.apache.spark.sql.{DataFrame, SQLContext, SaveMode}
  6. import org.apache.spark.{SparkConf, SparkContext}
  7.  
  8. /**
  9. * @author Administrator
  10. * 2018/10/16-14:35
  11. *
  12. */
  13. object TestSaveFile {
  14. var hdfsPath: String = ""
  15. var proPath: String = ""
  16. var DATE: String = ""
  17.  
  18. val sparkConf: SparkConf = new SparkConf().setAppName(getClass.getSimpleName)
  19. val sc: SparkContext = new SparkContext(sparkConf)
  20. val sqlContext: SQLContext = new HiveContext(sc)
  21.  
  22. def main(args: Array[String]): Unit = {
  23. hdfsPath = args(0)
  24. proPath = args(1)
  25. //不过滤读取
  26. val dim_sys_city_dict: DataFrame = readMysqlTable(sqlContext, "TestMysqlTble1", proPath)
  27. saveAsFileAbsPath(dim_sys_city_dict, hdfsPath + "TestSaveFile", "|", SaveMode.Overwrite)
  28. }
  29.  
  30. /**
  31. * 获取 Mysql 表的数据
  32. *
  33. * @param sqlContext
  34. * @param tableName 读取Mysql表的名字
  35. * @param proPath 配置文件的路径
  36. * @return 返回 Mysql 表的 DataFrame
  37. */
  38. def readMysqlTable(sqlContext: SQLContext, tableName: String, proPath: String): DataFrame = {
  39. val properties: Properties = getProPerties(proPath)
  40. sqlContext
  41. .read
  42. .format("jdbc")
  43. .option("url", properties.getProperty("mysql.url"))
  44. .option("driver", properties.getProperty("mysql.driver"))
  45. .option("user", properties.getProperty("mysql.username"))
  46. .option("password", properties.getProperty("mysql.password"))
  47. .option("dbtable", tableName)
  48. .load()
  49. }
  50.  
  51. /**
  52. * 将 DataFrame 保存为 hdfs 文件 同时指定保存绝对路径 与 分隔符
  53. *
  54. * @param dataFrame 需要保存的 DataFrame
  55. * @param absSaveDir 保存保存的路径 (据对路径)
  56. * @param splitRex 指定分割分隔符
  57. * @param saveMode 保存的模式:Append、Overwrite、ErrorIfExists、Ignore
  58. */
  59. def saveAsFileAbsPath(dataFrame: DataFrame, absSaveDir: String, splitRex: String, saveMode: SaveMode): Unit = {
  60. dataFrame.sqlContext.sparkContext.hadoopConfiguration.set("mapred.output.compress", "false")
  61. //为了方便观看结果去掉压缩格式
  62. val allClumnName: String = dataFrame.columns.mkString(",")
  63. val result: DataFrame = dataFrame.selectExpr(s"concat_ws('$splitRex',$allClumnName) as allclumn")
  64. result.write.mode(saveMode).text(absSaveDir)
  65. }
  66.  
  67. /**
  68. * 获取配置文件
  69. *
  70. * @param proPath
  71. * @return
  72. */
  73. def getProPerties(proPath: String): Properties = {
  74. val properties: Properties = new Properties()
  75. properties.load(new FileInputStream(proPath))
  76. properties
  77. }
  78. }

4.测试

  1. def main(args: Array[String]): Unit = {
  2. hdfsPath = args(0)
  3. proPath = args(1)
  4. //不过滤读取
  5. val dim_sys_city_dict: DataFrame = readMysqlTable(sqlContext, "TestMysqlTble1", proPath)
  6. saveAsFileAbsPath(dim_sys_city_dict, hdfsPath + "TestSaveFile", "|", SaveMode.Overwrite)
  7. }

5.执行命令

  1. nohup spark-submit --master yarn \
  2. --driver-memory 4G \
  3. --num-executors 2 \
  4. --executor-cores 4 \
  5. --executor-memory 8G \
  6. --class com.iptv.job.basedata.TestSaveFile \
  7. --jars /var/lib/hadoop-hdfs/tmp_lillcol/mysql-connector-java-5.1.38.jar \
  8. test.jar \
  9. hdfs://ns1/user/hive/../ \
  10. /var/.../job.properties > ./TestSaveFile.log 2>&1 &

6.运行结果

  1. [hdfs@iptve4e03 tmp_lillcol]$ hadoop fs -du -h hdfs://ns1/user/hive/warehouse/TestSaveFile
  2. 0 0 hdfs://ns1/user/hive/warehouse/TestSaveFile/_SUCCESS
  3. 4.1 K 4.1 K hdfs://ns1/user/hive/warehouse/TestSaveFile/part-r-123412340-ec83e1f1-4bd9-4b4a-89a3-8489c1f908dc
  4.  
  5. [hdfs@iptve4e03 tmp_lillcol]$ hadoop fs -cat hdfs://ns1/user/hive/warehouse/TestSaveFile/part-r-123412340-ec83e1f1-4bd9-4b4a-89a3-8489c1f908dc
  6. 1234|12349|张三|韩服_G|11234|张三艾欧尼亚|韩服-G|1234D5A3434|3|张三天庭
  7. 12343|1234|1234|韩服_M|31234|李四艾欧尼亚|韩服-M|5F4EE4345|8|1234天庭
  8. 1234|12340|石中剑山|韩服_s8|11234|张三艾欧尼亚|韩服-s8|59B403434|5|石中剑山天庭
  9. 12344|12344|灵山|韩服_J|31234|李四艾欧尼亚|韩服-J|CF19F434B|40|灵山天庭
  10. 1234|1234|他家|韩服_H|11234|张三艾欧尼亚|韩服-Z|51234EB1434|9|他家天庭
  11. 12345|12340|云浮|韩服_F|31234|李四艾欧尼亚|韩服-Y|9C9C04344|41|浮天庭
  12. 1234|12348|潮边疆|韩服_Z|41234|佛山艾欧尼亚|韩服-Z|5B034340F|15|边疆天庭
  13. 12340|12344|河姆渡人源|韩服_HY|41234|深圳艾欧尼亚|韩服-HY434123490808|18|河姆渡人源天庭
  14. 1234|1234|佛山|韩服_S|41234|佛山艾欧尼亚|韩服-FS|EEA981434|4|佛祖天庭
  15. 12340|12343|揭阳|韩服_J|41234|深圳艾欧尼亚|韩服-JY|9FF084349|10|天庭
  16. 1234|1234|石中剑边疆|韩服_|41234|佛山艾欧尼亚|韩服-HZ|440A434FC|0|石中剑边疆天庭
  17. 12348|1234|梅边疆|韩服_Z|41234|深圳艾欧尼亚|韩服-MZ|E9B434F09|14|梅边疆天庭
  18. 1234|12348|石中剑名|韩服_M|41234|佛山艾欧尼亚|韩服-MM|5D0A94434|14|石中剑名天庭
  19. 12349|1234|日本|韩服_|41234|深圳艾欧尼亚|韩服-SG|BD0F34349|19|日本天庭
  20. 1234|1234|石中剑石中剑|韩服_ST|41234|佛山艾欧尼亚|韩服-ST|18D0D0434|0|石中剑石中剑天庭
  21. 12340|1234|深圳|韩服_Z|41234|深圳艾欧尼亚|韩服-Z|31E4C4344|4|深天庭
  22. 12340|12340|石中剑尾|韩服_SW|41234|佛山艾欧尼亚|韩服-SW|1BA1234434B|10|石中剑尾天庭
  23. 12341|1234|美国|韩服_Z|41234|深圳艾欧尼亚|韩服-Q|3C09D434B|13|美国天庭
  24. 12341|1234|湛江|韩服_Z|41234|佛山艾欧尼亚|韩服-Z|3A49A4340|11|我家天庭
  25. 1234|12343|清诗和远方|韩服_Y|11234|张三艾欧尼亚|韩服-Y|4344E0F31|10|清诗和远方天庭
  26. 1234|41234|李四|韩服_AZ|31234|李四艾欧尼亚|韩服-Z|13F1D4344|1|李四天庭

7.总结

在整个过程中有几个需要注意的点

  • 只能存一个列
  1. /**
  2. * Saves the content of the [[DataFrame]] in a text file at the specified path.
  3. * The DataFrame must have only one column that is of string type.
  4. * Each row becomes a new line in the output file. For example:
  5. * {{{
  6. * // Scala:
  7. * df.write.text("/path/to/output")
  8. *
  9. * // Java:
  10. * df.write().text("/path/to/output")
  11. * }}}
  12. *
  13. * @since 1.6.0
  14. */
  15. def text(path: String): Unit = format("text").save(path)

这段代码已经说明了一切,是的,只能保存只有一列的DataFrame.

但是比起RDD,DataFrame能够比较轻易的处理这种情况

  1. def saveAsFileAbsPath(dataFrame: DataFrame, absSaveDir: String, splitRex: String, saveMode: SaveMode): Unit = {
  2. dataFrame.sqlContext.sparkContext.hadoopConfiguration.set("mapred.output.compress", "false")
  3. //为了方便观看结果去掉压缩格式
  4. val allClumnName: String = dataFrame.columns.mkString(",")
  5. val result: DataFrame = dataFrame.selectExpr(s"concat_ws('$splitRex',$allClumnName) as allclumn")
  6. result.write.mode(saveMode).text(absSaveDir)
  7. }

上述代码中 我们通过columns.mkString(",")获取 dataFrame 的所有列名并用","分隔,然后通过selectExpr(s"concat_ws('$splitRex',$allClumnName) as allclumn")将所有数据拼接当成一列,完美解决只能保存一列的问题

  • DataFrame 某个字段为空

如果 DataFrame 中某个字段为null,那么在你最中生成的文件中不会有该字段,所以,如果对结果字段的个数有要求的,最好在数据处理的时候将有可能为null的数据赋值空串"",特别是还有将数据load进Hive需求的,否则数据会出现错位

至此DataFrame 写文件功能实现

此文为本人工作总结,转载请标明出处!!!!!!!

Spark:DataFrame 写入文本文件的更多相关文章

  1. Spark DataFrame写入HBase的常用方式

    Spark是目前最流行的分布式计算框架,而HBase则是在HDFS之上的列式分布式存储引擎,基于Spark做离线或者实时计算,数据结果保存在HBase中是目前很流行的做法.例如用户画像.单品画像.推荐 ...

  2. Spark:将DataFrame写入Mysql

    Spark将DataFrame进行一些列处理后,需要将之写入mysql,下面是实现过程 1.mysql的信息 mysql的信息我保存在了外部的配置文件,这样方便后续的配置添加. //配置文件示例: [ ...

  3. [Spark][Python][DataFrame][Write]DataFrame写入的例子

    [Spark][Python][DataFrame][Write]DataFrame写入的例子 $ hdfs dfs -cat people.json {"name":" ...

  4. spark dataframe操作集锦(提取前几行,合并,入库等)

    https://blog.csdn.net/sparkexpert/article/details/51042970 spark dataframe派生于RDD类,但是提供了非常强大的数据操作功能.当 ...

  5. spark DataFrame 常见操作

    spark dataframe派生于RDD类,但是提供了非常强大的数据操作功能.当然主要对类SQL的支持. 在实际工作中会遇到这样的情况,主要是会进行两个数据集的筛选.合并,重新入库. 首先加载数据集 ...

  6. spark dataframe unionall

    今天本来想写一个spark dataframe unionall的demo,由于粗心报下面错误: Exception in thread "main" org.apache.spa ...

  7. Android 建立文件夹、生成文件并写入文本文件内容

    一.首先添加权限 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE">& ...

  8. Java基础知识强化之IO流笔记51:IO流练习之 键盘录入学生信息按照总分排序写入文本文件中的案例

    1.  键盘录入学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分排序写入文本文件中 分析:   A:创建学生类   B:创建集合对象      TreeSet<Student>   ...

  9. C# 实现写入文本文件内容功能

    private void write_txt(string str1, string str2, string str3) { System.DateTime currentTime = System ...

随机推荐

  1. 关于python那些事儿

    学习总结: 1.输入一个数据 a=input. 2.在输出结果中增加字符 # 运行如下语句: print("你的名字叫{}.".format("饺子")) (以 ...

  2. Java将ip字符串转换成整数的代码

    下面代码是关于Java将ip字符串转换成整数的代码,希望对各位有较大用途. public class IpUtil { public static int Ip2Int(String strIp){ ...

  3. Delphi 对ini文件的操作

    界面如图: 代码如下: unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Vari ...

  4. js获取元素属性值为空的原因和解决办法

    问题描述:js获取某元素的属性值为空 代码: <!-- css定义在head中 --> <style> #box{ width: 100px; height: 100px; b ...

  5. Codeforces Round #162 (Div. 1) B. Good Sequences (dp+分解素数)

    题目:http://codeforces.com/problemset/problem/264/B 题意:给你一个递增序列,然后找出满足两点要求的最长子序列 第一点是a[i]>a[i-1] 第二 ...

  6. 专业的“python爬虫工程师”需要学习哪些知识?

    学到哪种程度 暂且把目标定位初级爬虫工程师,简单列一下吧: (必要部分) 熟悉多线程编程.网络编程.HTTP协议相关 开发过完整爬虫项目(最好有全站爬虫经验,这个下面会说到) 反爬相关,cookie. ...

  7. Linux虚拟机部署单机solr报错500解决方法之一

    HTTP Status 500 - {msg=SolrCore 'collection1' is not available due to init failure: Could not load c ...

  8. 玩转BLE(1)_Eddystone beacon

    1. 前言 你相信两条命令就可以把自己的破手机变成一个Beacon节点吗?不相信的话就接着往下看吧. 通过前几篇“蓝牙协议分析”相关的文章,特别是“蓝牙协议分析(3)_蓝牙低功耗(BLE)协议栈介绍” ...

  9. Knut重排算法

    /// <summary> /// 这是Knut重排算法的实现 /// </summary> /// <param name="number"> ...

  10. Asp.net MVC Form认证,IIS改成集成模式后,FormsAuthentication.SetAuthCookie无效,Request.IsAuthenticated值,始终为false,页面提示HTTP 错误 401.0 - Unauthorized,您无权查看此目录或页面

    最近公司领导要求,IIS网站要由经典模式改为集成模式,以提高性能.改完之后,登录成功跳转到主页之后,页面提示“”HTTP 错误 401.0 - Unauthorized“,“您无权查看此目录或页面”, ...