一、需求:spark写入phoniex

二、实现方式

1.官网方式

 dataFrame.write
.format("org.apache.phoenix.spark")
.mode("overwrite")
.option("table", table)
.option("zkUrl", zkUrl)
.option("skipNormalizingIdentifier", true)
.save()

这个方式底层是使用MapReduce的RecordWriter实现类PhoenixRecordWriter通过jdbc方式写入

但是默认的batchsize是1000,所以插入速度极慢,但是官网没有说明写入的参数设置,需要去源码里面寻找一下

所以可以通过设置参数来提升速度

  .option(PhoenixConfigurationUtil.UPSERT_BATCH_SIZE,batch)

二、自己实现jdbc的通用方式(任何jdbc方式都可以写入)

代码:

object JdbcUtils {
def jdbcBatchInsert(dataFrame: DataFrame, table: String, url: String, pro: Properties, batch: Int): Unit = {
val fields: Array[String] = dataFrame.schema.fieldNames
val schema: Array[StructField] = dataFrame.schema.toArray
val numFields = fields.length
val fieldsSql = fields.map(str => "\"".concat(str).concat("\"")).mkString("(", ",", ")")
val charSql = fields.map(str => "?").mkString(",")
val setters: Array[JDBCValueSetter] = schema.map(f => makeSetter(f.dataType))
val insertSql = s"upsert into $table $fieldsSql values ($charSql) "
System.err.println("插入sql:" + insertSql)
val start = System.currentTimeMillis()
dataFrame.rdd.foreachPartition(partition => {
val connection = DriverManager.getConnection(url, pro)
try {
connection.setAutoCommit(false)
val pstmt: PreparedStatement = connection.prepareStatement(insertSql)
var count = 0
var cnt = 0
partition.foreach(row => {
for (i <- 0 until numFields) {
if (row.isNullAt(i)) {
pstmt.setNull(i + 1, getJdbcType(schema(i).dataType))
} else {
setters(i).apply(pstmt, row, i)
}
}
pstmt.addBatch()
count += 1
if (count % batch == 0) {
pstmt.executeBatch()
connection.commit()
cnt += 1
println(s"${TaskContext.get.partitionId}分区,提交第${cnt}次,${count}tiao")
}
})
pstmt.executeBatch()
connection.commit()
println(s"第${TaskContext.get.partitionId}分区,共提交第${cnt},${count}条")
} finally {
connection.close()
}
})
val end = System.currentTimeMillis()
println(s"插入表$table,共花费时间${(end - start) / 1000}秒")
} private type JDBCValueSetter = (PreparedStatement, Row, Int) => Unit /**
* 类型匹配 如果有其他类型 自行添加
*
* @param dataType
* @return
*/
def makeSetter(dataType: DataType): JDBCValueSetter = dataType match {
case IntegerType =>
(stmt: PreparedStatement, row: Row, pos: Int) =>
if (row.isNullAt(pos)) {
stmt.setNull(pos + 1, java.sql.Types.INTEGER)
} else {
stmt.setInt(pos + 1, row.getInt(pos))
}
case LongType =>
(stmt: PreparedStatement, row: Row, pos: Int) =>
stmt.setLong(pos + 1, row.getLong(pos)) case DoubleType =>
(stmt: PreparedStatement, row: Row, pos: Int) =>
stmt.setDouble(pos + 1, row.getDouble(pos)) case FloatType =>
(stmt: PreparedStatement, row: Row, pos: Int) =>
stmt.setFloat(pos + 1, row.getFloat(pos)) case ShortType =>
(stmt: PreparedStatement, row: Row, pos: Int) =>
stmt.setInt(pos + 1, row.getShort(pos)) case ByteType =>
(stmt: PreparedStatement, row: Row, pos: Int) =>
stmt.setInt(pos + 1, row.getByte(pos)) case BooleanType =>
(stmt: PreparedStatement, row: Row, pos: Int) =>
stmt.setBoolean(pos + 1, row.getBoolean(pos)) case StringType =>
(stmt: PreparedStatement, row: Row, pos: Int) =>
stmt.setString(pos + 1, row.getString(pos)) case BinaryType =>
(stmt: PreparedStatement, row: Row, pos: Int) =>
stmt.setBytes(pos + 1, row.getAs[Array[Byte]](pos)) case TimestampType =>
(stmt: PreparedStatement, row: Row, pos: Int) =>
stmt.setTimestamp(pos + 1, row.getAs[java.sql.Timestamp](pos)) case DateType =>
(stmt: PreparedStatement, row: Row, pos: Int) =>
stmt.setDate(pos + 1, row.getAs[java.sql.Date](pos)) case t: DecimalType =>
(stmt: PreparedStatement, row: Row, pos: Int) =>
stmt.setBigDecimal(pos + 1, row.getDecimal(pos)) /* case ArrayType(et, _) =>
// remove type length parameters from end of type name
val typeName = getJdbcType(et, dialect).databaseTypeDefinition
.toLowerCase(Locale.ROOT).split("\\(")(0)
(stmt: PreparedStatement, row: Row, pos: Int) =>
val array = conn.createArrayOf(
typeName,
row.getSeq[AnyRef](pos).toArray)
stmt.setArray(pos + 1, array)*/ case _ =>
(_: PreparedStatement, _: Row, pos: Int) =>
throw new IllegalArgumentException(
s"Can't translate non-null value for field $pos")
} /**
* sql类型匹配 如果有其他类型 自行添加
*
* @param dt
* @return
*/
private def getJdbcType(dt: DataType): Int = {
dt match {
case IntegerType => java.sql.Types.INTEGER
case LongType => java.sql.Types.BIGINT
case DoubleType => java.sql.Types.DOUBLE
case StringType => java.sql.Types.VARCHAR
case _ => java.sql.Types.VARCHAR
}
}
}  

测试:

#config是个map集合要不要都可以
val connectionProperties = new Properties();
connectionProperties.setProperty(QueryServices.MAX_MUTATION_SIZE_ATTRIB, config.getOrDefault("phoenix.mutate.maxSize", "500000")); //改变默认的500000
connectionProperties.setProperty(QueryServices.MUTATE_BATCH_SIZE_BYTES_ATTRIB, config.getOrDefault("phoenix.mutate.batchSizeBytes", "1073741824000")) val batch = config.getOrDefault("phoenix.insert.batchSize", "50000").toInt //调用插入方法
JdbcUtils.jdbcBatchInsert(dataFrame, table, phoenixUrl, connectionProperties, batch);

  

spark使用jdbc批次提交方式写入phoniex的工具类的更多相关文章

  1. Java中常用的加密方式(附多个工具类)

    一.Java常用加密方式 Base64加密算法(编码方式) MD5加密(消息摘要算法,验证信息完整性) 对称加密算法 非对称加密算法 数字签名算法 数字证书 二.分类按加密算法是否需要key被分为两类 ...

  2. 【JDBC】学习路径5-提取JDBCUtils工具类

    回顾我们上面几节的内容,我们发现重复代码非常多,比如注册驱动.连接.关闭close()等代码,非常繁杂. 于是我们将这些重复的大段代码进行包装.提取成JDBCUtils工具类. 第一章:提取注册连接模 ...

  3. Spark jdbc postgresql数据库连接和写入操作源码解读

    概述:Spark postgresql jdbc 数据库连接和写入操作源码解读,详细记录了SparkSQL对数据库的操作,通过java程序,在本地开发和运行.整体为,Spark建立数据库连接,读取数据 ...

  4. Spark Standalone与Spark on YARN的几种提交方式

    不多说,直接上干货! Spark Standalone的几种提交方式 别忘了先启动spark集群!!! spark-shell用于调试,spark-submit用于生产. 1.spark-shell ...

  5. Spark jdbc postgresql数据库连接和写入操作源代码解读

    概述:Spark postgresql jdbc 数据库连接和写入操作源代码解读.具体记录了SparkSQL对数据库的操作,通过java程序.在本地开发和执行.总体为,Spark建立数据库连接,读取数 ...

  6. spark之JDBC开发(实战)

    一.概述 Spark Core.Spark-SQL与Spark-Streaming都是相同的,编写好之后打成jar包使用spark-submit命令提交到集群运行应用$SPARK_HOME/bin#. ...

  7. spark之JDBC开发(连接数据库测试)

    spark之JDBC开发(连接数据库测试) 以下操作属于本地模式操作: 1.在Eclipse4.5中建立工程RDDToJDBC,并创建一个文件夹lib用于放置第三方驱动包 [hadoop@CloudD ...

  8. Spark使用jdbc时的并行度

    Spark SQL支持数据源使用JDBC从其他数据库读取数据. 与使用JdbcRDD相比,应优先使用此功能. 这是因为结果以DataFrame的形式返回,并且可以轻松地在Spark SQL中进行处理或 ...

  9. 各种数据库使用JDBC连接的方式

    Java数据库连接(JDBC)由一组用 Java 编程语言编写的类和接口组成.JDBC 为工具/数据库开发人员提供了一个标准的 API,使他们能够用纯Java API 来编写数据库应用程序.然而各个开 ...

  10. spark下使用submit提交任务后报jar包已存在错误

    使用spark submit进行任务提交,离线跑数据,提交后的一段时间内可以application可以正常运行.过了一段时间后,就抛出以下错误: org.apache.spark.SparkExcep ...

随机推荐

  1. [DApp] ethers.js VS Moralis

    ether.js 是 Web3 封装的 js 库,特别适合以太坊平台. Moralis 不仅是 Web3 的封装,还是一体化解决方案,包括服务端部署方案和适配各种链,使用范围更广. 在选择上,主要还是 ...

  2. 2019-8-31-C#-获取进程退出代码

    title author date CreateTime categories C# 获取进程退出代码 lindexi 2019-08-31 16:55:58 +0800 2019-02-13 09: ...

  3. van-tab吸顶后头部透明色渐变响应

    方法一:监听滚动事件 $('.scrollContent').bind('touchmove', function(e){             var  winHeight = $(window) ...

  4. 三、Prophecis 一站式云原生机器学习平台

    Prophecis 是微众银行自研大数据平台套件 WeDataSphere 的核心应用工具之一,为用户提供了全栈的机器学习应用开发与部署解决方案.作为WeDataSphere 功能工具应用系统,Pro ...

  5. 【经典爬虫案例】用Python爬取微博热搜榜!

    目录 一.爬取目标 二.编写爬虫代码 2.1 前戏 2.2 获取cookie 2.3 请求页面 2.4 解析页面 2.5 转换热搜类别 2.6 保存结果 2.7 查看结果数据 三.获取完整源码 一.爬 ...

  6. 【python爬虫案例】用python爬豆瓣读书TOP250排行榜!

    目录 一.爬虫对象-豆瓣读书TOP250 二.python爬虫代码讲解 三.讲解视频 四.完整源码 一.爬虫对象-豆瓣读书TOP250 今天我们分享一期python爬虫案例讲解.爬取对象是,豆瓣读书T ...

  7. JS对Cookie的应用--JavaScript实例集锦(初学)

    一个网站上的cookie信息可以实现下次自动登录,记录你的历史等等 可以在火狐浏览器查看本地代码的cookie信息: 打开火狐浏览器--点击右键--查看页面信息--安全--查看cookie <! ...

  8. QQ/钉钉远程控制和商业远程控制哪个好用

    提到远程协助.远程控制,你会想到什么? 国内最古老.最被用户熟知的,大概就是QQ远程控制了.QQ远程控制,方便易用.打开聊天窗口,点窗口上方"-",再移动到如图所示的电脑-箭头图标 ...

  9. 抽丝剥茧:详述一次DevServer Proxy配置无效问题的细致排查过程

    事情的起因是这样的,在一个已上线的项目中,其中一个包含登录和获取菜单的接口因响应时间较长,后端让我尝试未经服务转发的另一域名下的新接口,旧接口允许跨域请求,但新接口不允许本地访问(只允许发布测试/生产 ...

  10. python小功能

    django实现将linux目录和文件名列出来 def index(request): obj=models.USER.objects.all() fileroot = 'd:\machangwei' ...