Spark写PGSQL分区表

这里写目录标题

    • 需求
    • 碰到的问题
      • 格式问题
      • 分区问题(重点)
    • 解决
      • 完整代码
      • 效果

需求

spark程序计算后的数据需要往PGSQL中的分区表进行写入。

碰到的问题

格式问题

使用了字符串格式,导致插入报错。

val frame = df.withColumn("insert_time",current_timestamp()))
Batch entry 0 INSERT INTO t ("a","insert_time") VALUES 
(1,'2023-08-01 10:00:00') was aborted: ERROR: column 
"insert_time" is of type timestamp without time zone but 
expression is of type character varying

分区问题(重点)

一直都是spark计算完后写单表或者hive的表,都需要去手动去维护分区。但是写PGSQL空表(只有表字段,还没有数据,没有创建分区),需要手动先创建分区,否则会报错。

报错信息

Partition key of the failing row contains (insert_time) = 
(2023-08-04 21:14:09.641).  Call getNextException to see other 
errors in the batch.

插入失败的行的分区键包含的时间戳值 2023-08-04 21:14:09.641 在分区表中找不到对应的分区范围。

解决

最终的解决方案是在插入数据之前,通过代码去添加分区,添加好分区后再写入数据即可。

object WritePgSQL {def main(args: Array[String]): Unit = {val spark = SparkSession.builder().appName("SparkPostgreSQLPartitionedTable").config("spark.master", "local").getOrCreate()// 设置PostgreSQL连接信息val postgresUrl = "jdbc:postgresql://192.168.160.123:5432/test"val connectionProperties = new java.util.Properties()connectionProperties.setProperty("user", "test")connectionProperties.setProperty("password", "123456")// 创建测试数据val data = Seq((1, "2023-08-01 10:00:00"),(2, "2023-08-02 12:00:00"),(3, "2023-08-03 15:00:00"))val columns = Seq("a", "insert_time1")val df = spark.createDataFrame(data).toDF(columns: _*)val frame = df.drop("insert_time1").withColumn("insert_time", current_timestamp().cast("timestamp"))// 动态创建分区范围// p1 可以换成p20230804这样的分区格式// t为表名// (TIMESTAMP '2023-08-04 00:00:00') 分区开始范围,一般通过代码生成,为计算时间的零点// (TIMESTAMP '2023-08-05 00:00:00') 分区结束范围,一般通过代码生成,为计算时间的下一天零点val createPartitionSql =s"""CREATE TABLE "p1" PARTITION OF t FOR VALUES FROM (TIMESTAMP '2023-08-04 00:00:00') TO (TIMESTAMP '2023-08-05 00:00:00') ;"""println(createPartitionSql)// 执行创建分区 SQLval connection = java.sql.DriverManager.getConnection(postgresUrl, connectionProperties)val statement = connection.createStatement()statement.executeUpdate(createPartitionSql)connection.close()// 将数据写入PostgreSQL分区表frame.write.mode("append").jdbc(postgresUrl, "t", connectionProperties)}
}

完整代码

自动生成当天日期和分区名称

object WritePgSQL {def main(args: Array[String]): Unit = {val spark = SparkSession.builder().appName("SparkPostgreSQLPartitionedTable").config("spark.master", "local").getOrCreate()// 设置PostgreSQL连接信息val postgresUrl = "jdbc:postgresql://192.168.160.123:5432/test"val connectionProperties = new java.util.Properties()connectionProperties.setProperty("user", "test")connectionProperties.setProperty("password", "123456")// 创建测试数据val data = Seq((1, "2023-08-01 10:00:00"),(2, "2023-08-02 12:00:00"),(3, "2023-08-03 15:00:00"))val columns = Seq("a", "insert_time1")val df = spark.createDataFrame(data).toDF(columns: _*)val frame = df.drop("insert_time1").withColumn("insert_time", current_timestamp().cast("timestamp"))// 获取今天和明天的时间范围// 获取当前日期val currentDate = LocalDate.now()// 获取下一天的日期val nextDayDate = currentDate.plusDays(1)// 创建固定的时间部分(00:00:00)val startTime = LocalTime.of(0, 0, 0)// 组合日期和时间来得到完整的日期时间,并格式化为字符串val currentDateTimeString = LocalDateTime.of(currentDate, startTime).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))val nextDayDateTimeString = LocalDateTime.of(nextDayDate, startTime).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))// 格式化为yyyyMMdd字符串val dateFormatter = DateTimeFormatter.ofPattern("yyyyMMdd")val currentDateString = currentDate.format(dateFormatter)// 动态创建分区范围val createPartitionSql =s"""CREATE TABLE "p$currentDateString" PARTITION OF tFOR VALUES FROM (TIMESTAMP '$currentDateTimeString') TO (TIMESTAMP '$nextDayDateTimeString') ;"""// 执行创建分区 SQLval connection = java.sql.DriverManager.getConnection(postgresUrl, connectionProperties)val statement = connection.createStatement()statement.executeUpdate(createPartitionSql)connection.close()// 将数据写入PostgreSQL分区表frame.write.mode("append").jdbc(postgresUrl, "t", connectionProperties)}
}

效果

在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/52095.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于SpringBoot+Vue的CSGO赛事管理系统设计与实现(源码+LW+部署文档等)

博主介绍: 大家好,我是一名在Java圈混迹十余年的程序员,精通Java编程语言,同时也熟练掌握微信小程序、Python和Android等技术,能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

机器学习入门之 pandas

pandas 有三种数据结构 一种是 Series 一种是 Dataframe import pandas as pd import numpy as np score np.random.randint(0,100,[10,5])score[0,0] 100Datascore pd.DataFrame(score)subject ["语文","数学","英语","物理&quo…

网络——初识网络

网络基础 文章目录 网络基础计算机网络产生的背景认识网络协议网络协议初识协议分层OSI七层模型TCP/IP四层模型网络传输基本流程协议报头 认识IP地址认识MAC地址ifconfig查看主机地址ifconfig查看主机地址 计算机网络产生的背景 独立模式:计算机之间相互独立 早期的…

Linux系统jenkins+newman+postman持续集成环境搭建

1、首先安装nodejs 下载nodejs压缩包,下载地址:nodejs官网下载 建议不用下载最新的,我这里用的是推荐的v12.18版本 下载和解压命令 wget https://nodejs.org/dist/v12.18.3/node-v12.18.3-linux-x64.tar.xz解压安装包(记得没有z&…

基于web特产店销售管理系统的设计与实现(论文+源码)_kaic

摘要 农业是我国国民经济的重要组成部分,随着信息化的普及,4G网络、光纤以及5G网络也日益完善,农业信息化的发展成为了必然。同时,由于本年疫情原因,导致农作物积压销售,甚至腐烂造成不必要的浪费&#xff…

prometheus监控k8s kube-proxy target down

prometheus kube-proxy target down 解决 修改配置 kubectl edit cm/kube-proxy -n kube-systemmetricsBindAddress: "0.0.0.0:10249"删除 kube-proxy pod 使之重启应用配置 kubectl delete pod --force `kubectl get pod -n kube-system |grep kube-proxy|awk {pr…

【设计模式——学习笔记】23种设计模式——迭代器模式Iterator(原理讲解+应用场景介绍+案例介绍+Java代码实现)

文章目录 案例引入介绍基础介绍应用场景登场角色 案例实现案例一实现 案例二实现 迭代器模式在JDK源码中的应用总结文章说明 案例引入 编写程序展示一个学校院系结构: 需求是这样,要在一个页面中展示出学校的院系组成,一个学校有多个学院,一…

突破视觉边界:深入探索AI图像识别的现状与挑战

图像识别作为人工智能领域的一个重要研究方向,取得了许多令人瞩目的成就。深入探索当前AI图像识别技术的现状以及所面临的挑战,讨论各种方法的优势和局限性。 目录 引言1.1 AI图像识别的背景和概述1.2 人工智能在图像识别中的应用和重要性 图像识别基础知…

MCU的类型和应用领域简介

MCU(Microcontroller Unit)根据存储器类型可分为无片内ROM型和带片内ROM型。无片内ROM型的芯片需要外接EPROM才能应用,而带片内ROM型则有不同的子类型,如片内EPROM型、MASK片内掩模ROM型和片内Flash型。 MCU还可以按照用途分为通…

动画制作选择Blender还是Maya

Blender和Maya是两种最广泛使用的 3D 建模和动画应用程序。许多经验丰富的用户表示,Blender 在雕刻工具方面远远领先于 Maya,并且在 3D 建模方面达到了相同的质量水平。对于刚接触动画行业的人来说,您可能会问“我应该使用 Blender 还是 Maya…

C#实现旋转图片验证码

开发环境:C#,VS2019,.NET Core 3.1,ASP.NET Core 1、建立一个验证码控制器 新建两个方法Create和Check,Create用于创建验证码(返回1张图片和令牌),Check用于验证(验证图…