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( ...
随机推荐
- [JavaWeb] Ubuntu下载eclipse for ee
进入网站进行下载 https://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/2019- ...
- 2019年7月20日 - LeetCode0002
https://leetcode-cn.com/problems/add-two-numbers/submissions/ 我的方法: /** * Definition for singly-link ...
- Catalan公式
f(n)=f(1)*f(n-1)+f(2)*f(n-2)+f(3)*f(n-3)+......+f(n-1)*f(1) 例用:一个长度为n的无重复序列入栈的所有出栈方式
- php_review_day1
php中的小知识点(小白笔记整理):-----------------------------------------------------读取本地文件内的数据: file_get_contents ...
- GCC 编译多个文件
今天写数据结构的example,定义了3个文件:lish.h list.c main.c list.h是list.c的头文件,mian.c中对list.h进行了引用.代码如下: list.h 1 #i ...
- <<Modern CMake>> 翻译 1. CMake 介绍
<<Modern CMake>> 翻译 1. CMake 介绍 人们喜欢讨厌构建系统. 仅仅观看 CppCon17 上的演讲,就可以看到开发人员因为构建系统而闹笑话的例子. 这 ...
- Redis(四)--- Redis的命令参考
1.简述 数据类型也称数据对象,包含字符串对象(string).列表对象(list).哈希对象(hash).集合对象(set).有序集合对象(zset). 2.String数据类型命令 string ...
- containsObject 总是不含有,你会用吗
结论:containsObject:是在比较内存地址,即使两个对象内容完全一样,地址不同,那也是不同的.我个人认为这个方法应该叫是否存在同一个对象 (开始不知道这个知识,被坑,至少浪费了3个钟头,数组 ...
- java往文本文件中写入信息并修改
题目要求: 1.可以往一个文本文档中写入员工信息:name,id和详情 2.可以更改name package FanCQ.Xue.practice; import java.io.*;import j ...
- 这半年时间学Mysql的总结
一条sql语句的执行流程 select * from t where id=1 1.mysql执行一条查询语句的流程 1.1客户端输入用户名密码连接mysql服务器 1.2查询这条sql语句有没有对应 ...