官网链接:

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读取外部数据库,过滤数据的更多相关文章

  1. 读取mysql数据库的数据,转为json格式

    # coding=utf-8 ''' Created on 2016-10-26 @author: Jennifer Project:读取mysql数据库的数据,转为json格式 ''' import ...

  2. spring(读取外部数据库配置信息、基于注解管理bean、DI)

    ###解析外部配置文件在resources文件夹下,新建db.properties(和数据库连接相关的信息) driverClassName=com.mysql.jdbc.Driverurl=jdbc ...

  3. 读取mysq数据库l数据,并使用dataview显示

    来自<sencha touch权威指南>,约198页开始 通过php脚本,可以将mysql数据库的数据作为json数据格式进行读取. (1)php代码(bookinfo.php): < ...

  4. AndroidStudio 中查看获取MD5和SHA1值以及如何查看手机应用信息以及读取*.db数据库里面数据

    查看获取MD5和SHA1值具体操作方式链接 查看获取MD5和SHA1值实际操作命令CMD语句: C:\Users\Administrator>cd .android C:\Users\Admin ...

  5. C# 读取Oracle数据库视图数据异常问题处理

    会出现类似现在这种提示的错误 System.Data.OracleClient 需要 Oracle 客户端软件 version 8.1.7 或更高版本 情况1.开发过程中遇到这种问题解决 由于.net ...

  6. 在jsp页面直接读取mysql数据库显示数据

    闲来无事,学学java,虽说编程语言相通,但是接触一门新知识还是有些疑惑,边学边记录,方便以后温故. 直接给出代码: <%@page import="java.sql.ResultSe ...

  7. Excel2003读取sqlserver数据库表数据(图)

  8. 使用JDBC在MySQL数据库中快速批量插入数据

    使用JDBC连接MySQL数据库进行数据插入的时候,特别是大批量数据连续插入(10W+),如何提高效率呢? 在JDBC编程接口中Statement 有两个方法特别值得注意: void addBatch ...

  9. [原创]java使用JDBC向MySQL数据库批次插入10W条数据测试效率

    使用JDBC连接MySQL数据库进行数据插入的时候,特别是大批量数据连续插入(100000),如何提高效率呢?在JDBC编程接口中Statement 有两个方法特别值得注意:通过使用addBatch( ...

随机推荐

  1. BAT的人都是怎么学习的

    不知道你发现没,在技术领域走在前列的人,基本都符合一个条件:保持对新技术的敏感度,还能定期更新自己的技能储备. 要做到这一点,最高效的办法就是直接跟 BAT 等一线大厂取经.说白了,平台足够大,就有更 ...

  2. 将 unsiged char 转换成对应的十六进制字符用以显示出来如 unsiged char a[]={0x00,0x01,0x30,0x38}转化为“00013038”

    int CEnCryptionAndDeCryptionDlg::Byte2Hex(const unsigned char* input,unsigned long inLen, unsigned c ...

  3. 洛谷 P1463、POI2002、HAOI2007 反素数

    题意: 求最小的$x\in[1,N]$,使得$x$为$g(x)$最大的数 中最小的一个. 分析: 1.$x$不会有超过$10$个不同质因子.理由:$2 \times 3\times 5...\time ...

  4. 自实现input上传指定文件到服务器

    遇到问题,解决问题,记录问题,成长就是一步一步走出来的. 一.添加 input 标签 我的工作中遇到了,需要上传pdf文件到服务器的需求,而且只能上传pdf文件,accept指定了 pdf 类型. & ...

  5. Excel催化剂开源第3波-修复ExcelCom加载项失效问题及WPS可调用Com加载项的方法

    为了还原一个干净无侵扰的网络世界,本文将不进行大规模地分发,若您觉得此文有用,不妨小范围地分享到真正有需要的人手中 功能概述 修复ExcelCom加载项常见问题,如每次需重新勾选COM加载项或COM加 ...

  6. TensorFlow笔记-模型的保存,恢复,实现线性回归

    模型的保存 tf.train.Saver(var_list=None,max_to_keep=5) •var_list:指定将要保存和还原的变量.它可以作为一个 dict或一个列表传递. •max_t ...

  7. Java秒杀系统实战系列~整体业务流程介绍与数据库设计

    摘要: 本篇博文是“Java秒杀系统实战系列文章”的第三篇,本篇博文将主要介绍秒杀系统的整体业务流程,并根据相应的业务流程进行数据库设计,最终采用Mybatis逆向工程生成相应的实体类Entity.操 ...

  8. CSRF_TOKEN

    目的是防御CSRF攻击. Token就是令牌,最大的特点就是随机性,不可预测. CSRF 攻击之所以能够成功,是因为黑客可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于 cookie 中, ...

  9. ElasticSearch全文搜索引擎

    一.ElasticSearch简介 1.1 什么是ElasticSearch ElasticSearch简称ES,其中Elastic      从名字里我们可以知道,ES的特点就在于灵活的搜索,其实E ...

  10. git远程服务器回滚

    1.git log查找commit hash 2.git reset --hard hash 回滚本地git库 3.git push -f origin(git仓库的url) branch名 强制提交