在Spark中,Dataframe简直可以称为内存中的文本文件。

就像在电脑上直接操作txt、 csv、 json文件一样简单。

val sparkConf = new SparkConf().setAppName("df2db").setMaster("local[1]")

val sc = new SparkContext(sparkConf)

val sqlContext : SQLContext = new SQLContext(sc)

val df = sqlContext.read.format("csv").option("header","true").load("D:\\spark test\\123")

val snapTable = "env0y"

df.registerTempTable(snapTable)

以上寥寥数语就把一个csv文件转为DataFrame并注册为一张临时表了,这时候就可以像操作数据库表一样操作这个snapTable了:

val sql = "SELECT * FROM " + snapTable

val dfTmp = this.sqlContext.sql(sql)

这样写代码方便简单,但可惜的是DataFrame毕竟仅仅存在于内存中,我们业务代码只会输出算法里规定的结果

也就是说,假如结果出错,不好定位到底是DataFrame本身数据有误,还是代码中的SQL写错了。。。

假如能随时随地操作DataFrame就好了,怎么办呢?

把DataFrame保存到真实的数据库去:

import java.util.Properties

val connectionUrl = "jdbc:sqlserver://10.119.46.153:1433"

val table = "Nettransmit.dbo.df2mssql"

val prop = new Properties()

prop.put("JDBC.Driver","com.microsoft.sqlserver.jdbc.SQLServerDriver")

prop.put("user", "sa")

prop.put("password", "ibas.1597")

val dfWriter = df.write.mode(SaveMode.Overwrite).jdbc(connectionUrl, table, prop)

这下好了,如果计算出错了,我们直接连上数据库几条sql就能debug个八九不离十。

唯一要注意的是,DataFrame to Database不是业务要求,所以上面的代码只能在开发模式或者测试模式的时候存在,正式发布版不应该出现 

既然可以写进去,自然也可以读出来:

//SqlServer 2 Dataframe

val dfviatable = sqlContext.read.jdbc(connectionUrl,table,prop)

dfviatable.show(10)

以上,DataFrame和数据库之间的极简交互就完成了,但如果业务中真的有读写数据库的需求了,性能问题可能会成为瓶颈,要注意的。

接下来是那么一点点优化。

从csv到DataFrame,我们使用df.printSchema()语句可以在控制台看到类似下面的输出:

root

|-- IMSI: string (nullable = true)

|-- UserType: string (nullable = true)

|-- Total PS Traffic(KB): string (nullable = true)

|-- Total Online Time(s): string (nullable = true)

|-- Total CS Traffic (ERL): string (nullable = true)

|-- Brand: string (nullable = true)

|-- Series: string (nullable = true)

|-- OS: string (nullable = true)

|-- Type: string (nullable = true)

|-- FDD LTE: string (nullable = true)

|-- TDD LTE: string (nullable = true)

|-- Only Report 3G Capability: string (nullable = true)

也就是说,写入到数据库之后每个字段的类型都是string,这显然是一种浪费。

而且很多值完全可以使用int或者double或者bool类型。

怎么办呢?得修改数据库的“方言”,就像在c++中std::locale 建立本地规则一样。

为了方便起见,封装一下:

import java.io.{File, FileInputStream}

import java.util.Properties

import org.apache.spark.sql.jdbc.{JdbcDialect, JdbcDialects, JdbcType}

import org.apache.spark.sql.types._

import org.apache.spark.sql.{DataFrame, SaveMode}

/**

* Created by env0y on 2017/11/24.

*/

object dataframe2db {

def df2db(df: DataFrame,table: String,properties: String) = {

try{

val is = new FileInputStream(new File(properties))

val prop = new Properties()

prop.load(is)

val url = String.valueOf(prop.get("url"))//

JdbcDialects.registerDialect(SQLServerDialect)

df.write.mode(SaveMode.Overwrite).jdbc(url,table,prop)

is.close()

}

}

val SQLServerDialect = new JdbcDialect {

override def canHandle(url: String): Boolean = url.startsWith("jdbc:jtds:sqlserver") || url.contains("sqlserver")

override def getJDBCType(dt: DataType): Option[JdbcType] = dt match {

case StringType => Some(JdbcType("NVARCHAR(128)", java.sql.Types.VARCHAR))

case BooleanType => Some(JdbcType("BIT(1)", java.sql.Types.BIT))

case IntegerType => Some(JdbcType("INTEGER", java.sql.Types.INTEGER))

case LongType => Some(JdbcType("BIGINT", java.sql.Types.BIGINT))

case DoubleType => Some(JdbcType("DOUBLE PRECISION", java.sql.Types.DOUBLE))

case FloatType => Some(JdbcType("REAL", java.sql.Types.REAL))

case ShortType => Some(JdbcType("INTEGER", java.sql.Types.INTEGER))

case ByteType => Some(JdbcType("INTEGER", java.sql.Types.INTEGER))

case BinaryType => Some(JdbcType("BINARY", java.sql.Types.BINARY))

case DateType => Some(JdbcType("DATE", java.sql.Types.DATE))

case TimestampType => Some(JdbcType("DATE", java.sql.Types.DATE))

// case DecimalType.Fixed(precision, scale) => Some(JdbcType("NUMBER(" + precision + "," + scale + ")", java.sql.Types.NUMERIC))

case t: DecimalType => Some(JdbcType(s"DECIMAL(${t.precision},${t.scale})", java.sql.Types.DECIMAL))

case _ => throw new IllegalArgumentException(s"Don't know how to save ${dt.json} to JDBC")

}

}

}

然后像这样调用:

dataframe2db.df2db(df,"Nettransmit.dbo.df2dbff","D:\\ database.properties")

第三个参数是数据库的属性配置文件,内容类似以下:

#\u5F00\u53D1\u6570\u636E\u5E93

driver=com.microsoft.sqlserver.jdbc.SQLServerDriver

url=jdbc:sqlserver://10.119.46.153:1433;databaseName=TspManagement

username=sa

password=ibas.1597

这时候再去观察从DataFrame写入到数据库中表会发现,字段属性都变成NVARCHAR(128)了~~

另外,直接修改DataFrame里面的Schema类型也很简单:

val df1 = df.withColumn("Only Report 3G Capability",col("Only Report 3G Capability").cast(DataTypes.FloatType))

df1.printSchema()

就这些,以上Spark的版本是1.6. 涉及的数据库是sqlServer.

DataFrame与数据库的相互转化的更多相关文章

  1. spark RDD,DataFrame,DataSet 介绍

    弹性分布式数据集(Resilient Distributed Dataset,RDD) RDD是Spark一开始就提供的主要API,从根本上来说,一个RDD就是你的数据的一个不可变的分布式元素集合,在 ...

  2. r语言与dataframe

    什么是DataFrame 引用 r-tutor上的定义: DataFrame 是一个表格或者类似二维数组的结构,它的各行表示一个实例,各列表示一个变量. 没错,DataFrame就是类似于Excel表 ...

  3. RDD、DataFrame和DataSet的区别

    原文链接:http://www.jianshu.com/p/c0181667daa0 RDD.DataFrame和DataSet是容易产生混淆的概念,必须对其相互之间对比,才可以知道其中异同. RDD ...

  4. RDD、DataFrame和DataSet

    简述 RDD.DataFrame和DataSet是容易产生混淆的概念,必须对其相互之间对比,才可以知道其中异同:DataFrame多了数据的结构信息,即schema.RDD是分布式的 Java对象的集 ...

  5. HibernateTools实现pojo类 数据库schma mapping映射的相互转换 二

    接着上一篇博客:HibernateTools实现pojo类 数据库schma mapping映射的相互转换 思路二:由数据库表,生成Mapping映射文件和POJO类. 尽管能够实现,但个人觉着先设计 ...

  6. SparkSQL 中 RDD 、DataFrame 、DataSet 三者的区别与联系

    一.SparkSQL发展: Shark是一个为spark设计的大规模数据仓库系统,它与Hive兼容      Shark建立在Hive的代码基础上,并通过将Hive的部分物理执行计划交换出来(by s ...

  7. Sprk SQL

    一.Spark SQL概述  1.Spark SQL的前生今世 Shark是一个为Spark设计的大规模数据仓库系统,它与Hive兼容.Shark建立在Hive的代码基础上,并通过将Hive的部分物理 ...

  8. spark 三种数据集的关系(二)

    一个Dataset是一个分布式的数据集,而且它是一个新的接口,这个新的接口是在Spark1.6版本里面才被添加进来的,所以要注意DataFrame是先出来的,然后在1.6版本才出现的Dataset,提 ...

  9. python数据分析入门学习笔记

    学习利用python进行数据分析的笔记&下星期二内部交流会要讲的内容,一并分享给大家.博主粗心大意,有什么不对的地方欢迎指正~还有许多尚待完善的地方,待我一边学习一边完善~ 前言:各种和数据分 ...

随机推荐

  1. 2019 gplt团体程序设计天梯赛总结

    分很菜… 以后写题一定记得把题意理清楚了再开始写. 模拟题还是大坑,代码还是写得不够多,代码量一大就写bug. 补题 l1-8 估值一亿的AI核心代码 补题链接:https://pintia.cn/p ...

  2. JavaScript获取日期方法

    var time = new Date(); //当前时间 var year = time.getFullYear();//当前年份 var month = time.getMonth()+1; // ...

  3. em与当前元素的不解之缘

    em是相对于当前元素的字体大小而言,比如font-size:14px;那么这个元素的1em=14px. 如果当前元素未定义字体大小,则会向上继承父元素的字体大小,如果当前元素的所有祖先元素都没有定义f ...

  4. 自己总结的php开发中用到的工具

    需要一个编辑器IDE,推荐用phpstorm. IDE安装完了,还要搞个Xdebug,这个很有用,程序断点跟踪调试就靠他了. phpstom平时使用的时候,编辑界面感觉很枯燥的时候,可以换个主题,换主 ...

  5. x86、Linux、GNU、GNOME是什么

    一.指令集架构: 指令集架构(英语:Instruction Set Architecture,缩写为ISA),又称指令集或指令集体系,是计算机体系结构中与程序设计有关的部分,包含了基本数据类型,指令集 ...

  6. 一个表空间使用率查询sql的优化

    话不多说,直接上运行计划: SQL> set lines 500; SQL> set pagesize 9999; SQL> set long 9999; SQL> selec ...

  7. 歌乐电子一道非常easy的笔试题目居然搞错了!!!

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMjI0NzQ2Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQk ...

  8. 微信企业号开发:UserAgent

    userAgent 属性是一个仅仅读的字符串,声明了浏览器用于 HTTP 请求的用户代理头 的值.微信企业号的打开网页的userAgent又包括那些信息呢? 使用userAgent能够推断用户訪问的浏 ...

  9. FPGA 浮点单元设计

    浮点数在内存中的存放格式例如以下: 地址 +0 +1 +2 +3 内容 SEEE EEEE EMMM MMMM MMMM MMMM MMMM MMMM 这里 S 代表符号位,1是负,0是正 E 偏移1 ...

  10. C++开发人脸性别识别教程(19)——界面美化

    在这篇博文中将完毕<C++开发人脸性别识别>的收尾工作.主要内容分为两部分:加入视频暂定功能.界面规范化. 一 视频暂停功能 严格来说这个视频暂定功能算是视频人脸性别识别的一个遗留问题,本 ...