spark通过JDBC读取外部数据库,过滤数据
官网链接:
http://spark.apache.org/docs/latest/sql-programming-guide.html#jdbc-to-other-databases
http://spark.apache.org/docs/latest/sql-data-sources-jdbc.html
1. 过滤数据
情景:使用spark通过JDBC的方式读取postgresql数据库中的表然后存储到hive表中供后面数据处理使用,但是只读取postgresql表中的某些字段,并且做一下数据上的过滤
根据平常的方式,基本都是读取整张表,感觉不应该这么不友好的,于是去官网翻了翻,如下:

指定dbtable参数时候可以使用子查询的方式,不单纯是指定表名
测试代码如下:
package com.kong.test.test;
import java.util.Properties;
import org.apache.spark.sql.SaveMode;
import org.apache.spark.sql.SparkSession;
import org.apache.spark.sql.types.DataTypes;
public class SparkHiveTest {
public static void main(String[] args) {
SparkSession spark = SparkSession
.builder()
.appName("SparkCalibration")
.master("local")
.enableHiveSupport()
.getOrCreate();
spark.sparkContext().setLogLevel("ERROR");
spark.sparkContext().setLocalProperty("spark.scheduler.pool", "production");
String t2 = "(select id, name from test1) tmp";//这里需要有个别名
String createSql = "create table if not exists default.test1 (\r\n" +
"id string,\r\n" +
"name string\r\n" +
")ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' stored as TEXTFILE";
spark.sql(createSql);
spark.read().format("jdbc")
.option("url", "jdbc:postgresql://ip address/database")
.option("dbtable", t2).option("user", "login user").option("password", "login passwd")
.option("fetchsize", "1000")
.load()
.createOrReplaceTempView("test1_tmp");
spark.sql("insert overwrite table default.test1 select * from test1_tmp").show();
}
}
另外:如果对于hive表的存储格式没有要求,可以更简洁,如下:
spark.read().format("jdbc")
.option("url", "jdbc:postgresql://ip address/database")
.option("dbtable", t2).option("user", "login user").option("password", "login passwd")
.option("fetchsize", "1000")
.load().write().mode(SaveMode.Overwrite).saveAsTable("default.test");
至于基于哪种保存模式(SaveMode.Overwrite)可以结合实际场景;另外spark saveAsTable()默认是以parquet+snappy的形式写数据(生成的文件名.snappy.parquet),当然,也可以通过format()传入参数,使用orc等格式,并且可以指定其他压缩方式。
2. spark通过JDBC读取外部数据库的源码实现
2.1 最简洁的api,单分区
源码如下:
/**
* Construct a `DataFrame` representing the database table accessible via JDBC URL
* url named table and connection properties.
*
* @since 1.4.0
*/
def jdbc(url: String, table: String, properties: Properties): DataFrame = {
assertNoSpecifiedSchema("jdbc")
// properties should override settings in extraOptions.
this.extraOptions ++= properties.asScala
// explicit url and dbtable should override all
this.extraOptions += (JDBCOptions.JDBC_URL -> url, JDBCOptions.JDBC_TABLE_NAME -> table)
format("jdbc").load()
}
2.2 指定表某个字段的上下限值(数值类型),生成相对应的where条件并行读取,源码如下:
/**
* Construct a `DataFrame` representing the database table accessible via JDBC URL
* url named table. Partitions of the table will be retrieved in parallel based on the parameters
* passed to this function.
*
* 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 columnName the name of a column of integral type that will be used for partitioning.
* @param lowerBound the minimum value of `columnName` used to decide partition stride.
* @param upperBound the maximum value of `columnName` used to decide partition stride.
* @param numPartitions the number of partitions. This, along with `lowerBound` (inclusive),
* `upperBound` (exclusive), form partition strides for generated WHERE
* clause expressions used to split the column `columnName` evenly. When
* the input is less than 1, the number is set to 1.
* @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,
columnName: String,
lowerBound: Long,
upperBound: Long,
numPartitions: Int,
connectionProperties: Properties): DataFrame = {
// columnName, lowerBound, upperBound and numPartitions override settings in extraOptions.
this.extraOptions ++= Map(
JDBCOptions.JDBC_PARTITION_COLUMN -> columnName,
JDBCOptions.JDBC_LOWER_BOUND -> lowerBound.toString,
JDBCOptions.JDBC_UPPER_BOUND -> upperBound.toString,
JDBCOptions.JDBC_NUM_PARTITIONS -> numPartitions.toString)
jdbc(url, table, connectionProperties)
}
2.3 通过predicates: Array[String],传入每个分区的where子句中的谓词条件,并行读取,比如 :
String[] predicates = new String[] {"date <= '20180501'","date > '20180501' and date <= '20181001'","date > '20181001'"};
/**
* 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通过JDBC读取外部数据库,过滤数据的更多相关文章
- 读取mysql数据库的数据,转为json格式
# coding=utf-8 ''' Created on 2016-10-26 @author: Jennifer Project:读取mysql数据库的数据,转为json格式 ''' import ...
- spring(读取外部数据库配置信息、基于注解管理bean、DI)
###解析外部配置文件在resources文件夹下,新建db.properties(和数据库连接相关的信息) driverClassName=com.mysql.jdbc.Driverurl=jdbc ...
- 读取mysq数据库l数据,并使用dataview显示
来自<sencha touch权威指南>,约198页开始 通过php脚本,可以将mysql数据库的数据作为json数据格式进行读取. (1)php代码(bookinfo.php): < ...
- AndroidStudio 中查看获取MD5和SHA1值以及如何查看手机应用信息以及读取*.db数据库里面数据
查看获取MD5和SHA1值具体操作方式链接 查看获取MD5和SHA1值实际操作命令CMD语句: C:\Users\Administrator>cd .android C:\Users\Admin ...
- C# 读取Oracle数据库视图数据异常问题处理
会出现类似现在这种提示的错误 System.Data.OracleClient 需要 Oracle 客户端软件 version 8.1.7 或更高版本 情况1.开发过程中遇到这种问题解决 由于.net ...
- 在jsp页面直接读取mysql数据库显示数据
闲来无事,学学java,虽说编程语言相通,但是接触一门新知识还是有些疑惑,边学边记录,方便以后温故. 直接给出代码: <%@page import="java.sql.ResultSe ...
- Excel2003读取sqlserver数据库表数据(图)
- 使用JDBC在MySQL数据库中快速批量插入数据
使用JDBC连接MySQL数据库进行数据插入的时候,特别是大批量数据连续插入(10W+),如何提高效率呢? 在JDBC编程接口中Statement 有两个方法特别值得注意: void addBatch ...
- [原创]java使用JDBC向MySQL数据库批次插入10W条数据测试效率
使用JDBC连接MySQL数据库进行数据插入的时候,特别是大批量数据连续插入(100000),如何提高效率呢?在JDBC编程接口中Statement 有两个方法特别值得注意:通过使用addBatch( ...
随机推荐
- JavaScript控制语句结构、函数部分
HTML页面代码: <html> <head> <meta charset="UTF-8"> <title>HelloWorld&l ...
- 高性能javascript-总结(一)
性能优化 第一章:加载和执行 总结: 将所有<script>标签放到页面底部.这能确保在脚本执行前页面已经渲染了. 合并脚本.<script>标签越少,加载越快,响应速度也更迅 ...
- Elasticsearch 技术分析(九):Elasticsearch的使用和原理总结
前言 之前已经分享过Elasticsearch的使用和原理的知识,由于近期在公司内部做了一次内部分享,所以本篇主要是基于之前的博文的一个总结,希望通过这篇文章能让读者大致了解Elasticsearch ...
- nginx配置目录访问&用户名密码控制
背景 项目上需要一些共享目录让外地同事可以网页访问对应的文件,且受权限控制: 现有环境: centos nginx 你可以了解到以下内容: 配置nginx开启目录访问 并配置nginx用户名和密码进行 ...
- VMware里装XP 没有找到硬盘驱动器
遇到问题: 解决:要给虚拟机配上一个虚拟的硬盘驱动器.在VMWare的虚拟机配置里面给这个虚拟机增加硬盘,选IDE模式,而非SCSI,设定硬盘大小和文件名就可以了.
- Web服务器怎么解析URL
问:Web服务器是如何将浏览器中输入的地址"http://localhost:8080/SimpleServlet/First" 答:以Java 为例(各种语言都是类似的) 1)地 ...
- VMWare虚拟机:三台虚拟机互通且连网
虚拟机:三台虚拟机互通且连网 目录 一.虚拟机 相关软件 虚拟机安装 Linux系统安装 1) 使用三个Linux虚拟机 多台虚拟机互通且上网 1) 多台配置注意事项 2) 虚拟机软件的配置 3) W ...
- TreeSet类的排序
TreeSet支持两种排序方法:自然排序和定制排序.TreeSet默认采用自然排序. 1.自然排序 TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素之间大小关系, ...
- Python 之父撰文回忆:为什么要创造 pgen 解析器?
花下猫语: 近日,Python 之父在 Medium 上开通了博客,并发布了一篇关于 PEG 解析器的文章(参见我翻的 全文译文).据我所知,他有自己的博客,为什么还会跑去 Medium 上写文呢?好 ...
- mybatis动态插入数据库
<insert id="dynamicAddUser"> insert into t_user <!-- trim 对所有的表中列名 进行动态处理 --> ...