近期又有需求为:导入Oracle的表到hive库中;

关于spark读取Oracle到hive有以下两点需要说明:

 1、数据量较小时,可以直接使用spark.read.jdbc(orclUrl,table_name,orclProperties)读取,效率应该没什么问题,能很快完成;

 2、数据量较大时候,使用spark.read.jdbc(orclUrl,table_name,分区条件,orclProperties)方法,分区读取,该方法可根据分区条件同时多线程读取;原理为在读取Oracle的SQL最后加入where+不同的分区条件;例如oracle 中的id为1~10;分区之后为where id >=1 and id <=5和where id >=6 and id <=10;两个线程同时读取;

源码如下:spark2.2.0;请注意看官方注释

  /**
* Construct a `DataFrame` representing the database table accessible via JDBC URL
* url named table using connection properties. The `predicates` parameter gives a list
* expressions suitable for inclusion in WHERE clauses; each one defines one partition
* of the `DataFrame`.
*
* Don't create too many partitions in parallel on a large cluster; otherwise Spark might crash
* your external database systems.
*
* @param url JDBC database url of the form `jdbc:subprotocol:subname`
* @param table Name of the table in the external database.
* @param predicates Condition in the where clause for each partition.
* @param connectionProperties JDBC database connection arguments, a list of arbitrary string
* tag/value. Normally at least a "user" and "password" property
* should be included. "fetchsize" can be used to control the
* number of rows per fetch.
* @since 1.4.0
*/
def jdbc(
url: String,
table: String,
predicates: Array[String],
connectionProperties: Properties): DataFrame = {
assertNoSpecifiedSchema("jdbc")
// connectionProperties should override settings in extraOptions.
val params = extraOptions.toMap ++ connectionProperties.asScala.toMap
val options = new JDBCOptions(url, table, params)
val parts: Array[Partition] = predicates.zipWithIndex.map { case (part, i) =>
JDBCPartition(part, i) : Partition
}
val relation = JDBCRelation(parts, options)(sparkSession)
sparkSession.baseRelationToDataFrame(relation)
}

在实际工作中发现。spark读取Oracle时,Oracle中的date类型并不能得到很好的支持,例如:2018-10-10 23:00格式的时间,在去读取到hive表中之后只剩下了2018-10-10,小时和分钟没了;

可行的解决方案如下:重写java的方言,代码如下:

import org.apache.spark.sql.jdbc.JdbcDialect;
import org.apache.spark.sql.jdbc.JdbcDialects;
import org.apache.spark.sql.jdbc.JdbcType;
import org.apache.spark.sql.types.DataType;
import org.apache.spark.sql.types.DataTypes;
import org.apache.spark.sql.types.MetadataBuilder;
import scala.Option;
import java.sql.Types; public class OracleDateTypeInit {
public static void oracleInit() {
JdbcDialect dialect = new JdbcDialect() { //判断是否为oracle库
@Override
public boolean canHandle(String url) {
return url.startsWith("jdbc:oracle");
} //用于读取Oracle数据库时数据类型的转换
@Override
public Option<DataType> getCatalystType(int sqlType, String typeName, int size, MetadataBuilder md) {
if (sqlType == Types.DATE && typeName.equals("DATE") && size == 0)
return Option.apply(DataTypes.TimestampType);
return Option.empty();
} //用于写Oracle数据库时数据类型的转换
@Override
public Option<JdbcType> getJDBCType(DataType dt) {
if (DataTypes.StringType.sameType(dt)) {
return Option.apply(
new JdbcType("VARCHAR2(255)", Types.VARCHAR));
} else if (DataTypes.BooleanType.sameType(dt)) {
return Option.apply(
new JdbcType("NUMBER(1)", Types.NUMERIC));
} else if (DataTypes.IntegerType.sameType(dt)) {
return Option.apply(
new JdbcType("NUMBER(10)", Types.NUMERIC));
} else if (DataTypes.LongType.sameType(dt)) {
return Option.apply(
new JdbcType("NUMBER(19)", Types.NUMERIC));
} else if (DataTypes.DoubleType.sameType(dt)) {
return Option.apply(
new JdbcType("NUMBER(19,4)", Types.NUMERIC));
} else if (DataTypes.FloatType.sameType(dt)) {
return Option.apply(
new JdbcType("NUMBER(19,4)", Types.NUMERIC));
} else if (DataTypes.ShortType.sameType(dt)) {
return Option.apply(
new JdbcType("NUMBER(5)", Types.NUMERIC));
} else if (DataTypes.ByteType.sameType(dt)) {
return Option.apply(
new JdbcType("NUMBER(3)", Types.NUMERIC));
} else if (DataTypes.BinaryType.sameType(dt)) {
return Option.apply(
new JdbcType("BLOB", Types.BLOB));
} else if (DataTypes.TimestampType.sameType(dt)) {
return Option.apply(
new JdbcType("DATE", Types.DATE));
} else if (DataTypes.DateType.sameType(dt)) {
return Option.apply(
new JdbcType("DATE", Types.DATE));
} else if (DataTypes.createDecimalType()
.sameType(dt)) { //unlimited
/* return DecimalType.Fixed(precision, scale)
=>Some(JdbcType("NUMBER(" + precision + "," + scale + ")",
java.sql.Types.NUMERIC))*/
return Option.apply(
new JdbcType("NUMBER(38,4)", Types.NUMERIC));
}
return Option.empty();
}
};
//注册此方言
JdbcDialects.registerDialect(dialect);
}
}

使用时调用就可以了

//spark直接读取hive之后date类型的数据只剩年月日了,需要转为TimestampType
OracleDateTypeInit.oracleInit()

spark读写Oracle、hive的艰辛之路(二)-Oracle的date类型的更多相关文章

  1. Oracle中把一个DateTime的字符串转化成date类型。to_date('2016/12/8 18:55:43','yyyy/MM/dd hh24:mi:ss'),

    Oracle中把一个DateTime或者该形态字符串转化成date类型. to_date('2016/12/8 18:55:43','yyyy/MM/dd hh24:mi:ss'), 或者: sele ...

  2. spark读写Oracle、hive的艰辛之路(一)

    前两天工作需求,要通过给的几个Oracle的视图把数据入到hive库中,很遗憾,使用的华为云平台的集区环境中并没有sqoop1,当然也并没有sqoop2,所以,想到的解决方案是使用spark读取Ora ...

  3. Spark 读写hive 表

    spark 读写hive表主要是通过sparkssSession 读表的时候,很简单,直接像写sql一样sparkSession.sql("select * from xx") 就 ...

  4. 大数据学习系列之七 ----- Hadoop+Spark+Zookeeper+HBase+Hive集群搭建 图文详解

    引言 在之前的大数据学习系列中,搭建了Hadoop+Spark+HBase+Hive 环境以及一些测试.其实要说的话,我开始学习大数据的时候,搭建的就是集群,并不是单机模式和伪分布式.至于为什么先写单 ...

  5. HADOOP+SPARK+ZOOKEEPER+HBASE+HIVE集群搭建(转)

    原文地址:https://www.cnblogs.com/hanzhi/articles/8794984.html 目录 引言 目录 一环境选择 1集群机器安装图 2配置说明 3下载地址 二集群的相关 ...

  6. spark2.3.0 配置spark sql 操作hive

    spark可以通过读取hive的元数据来兼容hive,读取hive的表数据,然后在spark引擎中进行sql统计分析,从而,通过spark sql与hive结合实现数据分析将成为一种最佳实践.配置步骤 ...

  7. 使用Spark读写CSV格式文件(转)

    原文链接:使用Spark读写CSV格式文件 CSV格式的文件也称为逗号分隔值(Comma-Separated Values,CSV,有时也称为字符分隔值,因为分隔字符也可以不是逗号.在本文中的CSV格 ...

  8. Spark读写ES

    本文主要介绍spark sql读写es.structured streaming写入es以及一些参数的配置 ES官方提供了对spark的支持,可以直接通过spark读写es,具体可以参考ES Spar ...

  9. Oracle/Hive/Impala SQL比较1

    5 Function      指数据库内置的function,不讨论UDF.另外,操作符都不比较了,区别不大.   5.1 数学函数 功能 Oracle Hive Impala ABS 绝对值,有 ...

随机推荐

  1. losetup命令使用

    1.losetup命令 Linux系统losetup命令用来设置循坏设备,循坏设备可以把文件虚拟成块设备,借此来模拟整个文件系统,让用户得以将其视为硬盘驱动器,光驱等设备,并挂入当作目录来使用. (1 ...

  2. Faiss的学习和入门文章

    可以看这里的文章: https://www.leiphone.com/news/201703/84gDbSOgJcxiC3DW.html https://waltyou.github.io/Faiss ...

  3. 删除排序链表中的重复元素II --链表

    题目 给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字. 示例1 输入: ->->->->->-> 输出: ->-> ...

  4. thymeleaf是用于编写html模版的编程语言(工具语言)

    一.编程语言 用于编写html模版的编程语言. thymeleaf一种命令式和声名式混合的寄生语言. html与thymeleaf的结合是dsl与命令式语言的结合. html与thymeleaf的结合 ...

  5. 【LeetCode】387. First Unique Character in a String

    Difficulty:easy  More:[目录]LeetCode Java实现 Description https://leetcode.com/problems/first-unique-cha ...

  6. Geany——Python配置

    Geany是一个很不错的编辑器,操作很简单,这里记录一下Geany的入手设置(在下是一个Python程序猿,就以Python为例): 1:新建:选择 下拉菜单中的  main.py  ,然后就能生成P ...

  7. python基础01day

    1 python多版本共存 因为python2和python3的解释器程序都是python.exe,在同时加入环境变量的情况下名称重复,如果重命名的话又会造成需要链接解释器的程序无法调用解释器,所以采 ...

  8. 【开发笔记】-Tomcat启动时设置Jdk版本

    1. Window版本Tomcat 到bin下的setclasspath.bat文件,在文件的开始处添加如下代码: set JAVA_HOME=D:\Program Files\Java\jdk1.8 ...

  9. 工具sublime安装

    默认安装后是英文版 view-show console 安装packagecontrol https://packagecontrol.io/installation ctrl+`打开控制台,输入代码 ...

  10. js两个不同类型值比较Boolean(0=='')

    写js遇到的问题 本以为 Boolean(0=='') 结果为true 可是在控制台执行 Boolean(0==' ')trueBoolean(0==null)false 百度得知,两个不同类型值比较 ...