spark jdbc写数据到Hive

由于spark本身是不支持jdbc写入hive的,我们这里通过byzer做了实现,byzer自带了HiveJdbcDialect,有了这个功能后,我们通过save是可以正常创建表结构的,然后就拷贝hdfs数据,并通过原生的hive load data关联hdfs文件数据。

需要注意的是,直接通过spark jdbc写hive会报如下错误:

java.sql.SQLFeatureNotSupportedException: Method not supported
at org.apache.hive.jdbc.HivePreparedStatement.addBatch(HivePreparedStatement.java:78)

查看源码后发现此方法不支持

  public void addBatch() throws SQLException {
    // TODO Auto-generated method stub
    throw new SQLFeatureNotSupportedException("Method not supported");
  }

源码改造

我们可以简单处理一下SQLFeatureNotSupportedException异常,或者单独实现一个createTable spark数据源,去掉数据源中的saveTable即可,代码位置如下:

保存到Hive,使用overwrite模式

在byzer中使用方式如下:

注意,我们在createTableOptions中设置了 STORED AS PARQUET ,是为了生成形如下面的建表语句:

CREATE TABLE parquet_test (
 id int,
 str string,
 mp MAP<STRING,STRING>,
 lst ARRAY<STRING>,
 strct STRUCT<A:STRING,B:STRING>) 
PARTITIONED BY (part string)
STORED AS PARQUET;

保存到Hive,使用ignore模式

由于我们全程使用sql完成保存操作,读者可能会发现,这个是不是没有办法支持 ignore模式了?在第二步中save操作已经创建好了表结构,后续的sql如果使用 `load data inpath ... ignore into table` 句式,不是会导致应该写入数据,但是由于先创建了表,导致忽略写入吗?

上面的理解是正确的,确实会导致数据无法写入,同时在 SaveMode 的选择上,我们会陷入3个困境:

  • 使用 ignore into table ,会导致表存在或者不存在,都无法写入,因为第二步总是会创建表结构。

  • 使用 overwrite into table ,会导致本来表存在我们在业务中是需要跳过不写入(第二步使用了save ignore),而在最后一步我们强制做了 overwrite ,导致原有数据被覆盖。

  • 分成几段sql来处理,在处理保存操作之前,我们去发起请求查询一下表是否存在,一旦发现存在,我们可以在业务代码中跳过表创建的执行,否则就执行overwrite 句式。但这样也会导致一个问题,需要多次的交互才能完成一个保存操作,sql层面ignore 语义是缺失的,同时多阶段操作也会增加数据不一致的风险。

解法:Byzer支持在sql中写if ... else 逻辑,借此功能我们可以在sql中完成表是否存在的检测逻辑。

if 语法为命令式语法,详情参考 分支/If|Else ,下面是一个简单示例:

set status= `select status from raw_cnodejs_articles` where type="sql" and mode="runtime";

-- 如果状态不是200,则模拟不带数据的新表
!if ''' :status != 200 '''; 
!then; 
    run command as EmptyTableWithSchema.`` where schema='''st(field(content,binary),field(status,integer))''' as raw_cnodejs_articles;    
!fi;

完成的save ignore操作示例代码如下:

  1. 首先我们加载数据源,通过save语法创建表结构,执行了一个简单的数据处理算子(列增加唯一标识符),并读取目标表计算表数据行数:

  1. 根据行数我们判断是否执行HDFS数据写入,如果行数(tabVal)大于0,则不做数据写入,直接执行可以空指令(!emptyTable;):

读者会注意到load FS操作并没有指定路径,这里实际上是做hdfs Nameservice 配置初始化,为后续方便我们做save操作,不会做实际的文件读取,详情参考: https://github.com/byzer-org/byzer-lang/issues/1868

  1. 如果是空表,我们对写入的数据做hive元数据关联:

通过 !fi; 命令,结束if语句。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值