Hudi Spark-SQL增量查询数据几种方式

这篇具有很好参考价值的文章主要介绍了Hudi Spark-SQL增量查询数据几种方式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

由于项目上主要用Hive查询Hudi,所以之前总结过一篇:Hive增量查询Hudi表。最近可能会有Spark SQL增量查询Hudi表的需求,并且我发现目前用纯Spark SQL的形式还不能直接增量查询Hudi表,于是进行学习总结一下。

编程方式(DF+SQL)

先看一下官方文档上Spark SQL增量查询的方式,地址:https://hudi.apache.org/cn/docs/quick-start-guide#incremental-query 和 https://hudi.apache.org/cn/docs/querying_data#incremental-query

它是先通过spark.read中添加增量参数的形式读Hudi表为DF,然后将DF注册成临时表,最后通过Spark SQL查询临时表的形式,实现增量查询的。

参数

  • hoodie.datasource.query.type=incremental 查询类型,值为incremental时代表增量查询,默认值snapshot,增量查询时,该参数必填
  • hoodie.datasource.read.begin.instanttime 增量查询开始时间,必填 例如:20221126170009762
  • hoodie.datasource.read.end.instanttime 增量查询结束时间,非必填 例如:20221126170023240
  • hoodie.datasource.read.incr.path.glob 增量查询指定分区路径,非必填 例如 /dt=2022-11*/*
    查询范围 (BEGIN_INSTANTTIME,END_INSTANTTIME],也就是大于开始时间(不包含),小于等于结束时间(包含),如果没有指定结束时间,那么查询大于BEGIN_INSTANTTIME到现在为止最新的数据,如果指定INCR_PATH_GLOB,那么只在指定分区路径下面查询对应的数据。

代码示例

完整代码地址:https://github.com/dongkelun/hudi-demo/blob/master/hudi0.12_spark3.1/src/main/scala/com/dkl/hudi/spark3_1/IncrementalQuery.scala

import org.apache.hudi.DataSourceReadOptions.{BEGIN_INSTANTTIME, END_INSTANTTIME, INCR_PATH_GLOB, QUERY_TYPE, QUERY_TYPE_INCREMENTAL_OPT_VAL}
import org.apache.spark.sql.SparkSession
import org.apache.spark.sql.catalyst.TableIdentifier

val tableName = "test_hudi_incremental"

spark.sql(
  s"""
     |create table $tableName (
     |  id int,
     |  name string,
     |  price double,
     |  ts long,
     |  dt string
     |) using hudi
     | partitioned by (dt)
     | options (
     |  primaryKey = 'id',
     |  preCombineField = 'ts',
     |  type = 'cow'
     | )
     |""".stripMargin)

spark.sql(s"insert into $tableName values (1,'hudi',10,100,'2022-11-25')")
spark.sql(s"insert into $tableName values (2,'hudi',10,100,'2022-11-25')")
spark.sql(s"insert into $tableName values (3,'hudi',10,100,'2022-11-26')")
spark.sql(s"insert into $tableName values (4,'hudi',10,100,'2022-12-26')")
spark.sql(s"insert into $tableName values (5,'hudi',10,100,'2022-12-27')")

val table = spark.sessionState.catalog.getTableMetadata(TableIdentifier(tableName))
val basePath = table.storage.properties("path")

// incrementally query data
val incrementalDF = spark.read.format("hudi").
  option(QUERY_TYPE.key, QUERY_TYPE_INCREMENTAL_OPT_VAL).
  option(BEGIN_INSTANTTIME.key, beginTime).
  option(END_INSTANTTIME.key, endTime).
  option(INCR_PATH_GLOB.key, "/dt=2022-11*/*").
        load(basePath)
//  table(tableName)

incrementalDF.createOrReplaceTempView(s"temp_$tableName")

spark.sql(s"select * from  temp_$tableName").show()
spark.stop()

结果:

+-------------------+--------------------+------------------+----------------------+--------------------+---+----+-----+---+----------+
|_hoodie_commit_time|_hoodie_commit_seqno|_hoodie_record_key|_hoodie_partition_path|   _hoodie_file_name| id|name|price| ts|        dt|
+-------------------+--------------------+------------------+----------------------+--------------------+---+----+-----+---+----------+
|  20221126165954300|20221126165954300...|              id:1|         dt=2022-11-25|de99b299-b9de-423...|  1|hudi| 10.0|100|2022-11-25|
|  20221126170009762|20221126170009762...|              id:2|         dt=2022-11-25|de99b299-b9de-423...|  2|hudi| 10.0|100|2022-11-25|
|  20221126170030470|20221126170030470...|              id:5|         dt=2022-12-27|75f8a760-9dc3-452...|  5|hudi| 10.0|100|2022-12-27|
|  20221126170023240|20221126170023240...|              id:4|         dt=2022-12-26|4751225d-4848-4dd...|  4|hudi| 10.0|100|2022-12-26|
|  20221126170017119|20221126170017119...|              id:3|         dt=2022-11-26|2272e513-5516-43f...|  3|hudi| 10.0|100|2022-11-26|
+-------------------+--------------------+------------------+----------------------+--------------------+---+----+-----+---+----------+

+-----------------+
|      commit_time|
+-----------------+
|20221126170030470|
|20221126170023240|
|20221126170017119|
|20221126170009762|
|20221126165954300|
+-----------------+

20221126170009762
20221126170023240
+-------------------+--------------------+------------------+----------------------+--------------------+---+----+-----+---+----------+
|_hoodie_commit_time|_hoodie_commit_seqno|_hoodie_record_key|_hoodie_partition_path|   _hoodie_file_name| id|name|price| ts|        dt|
+-------------------+--------------------+------------------+----------------------+--------------------+---+----+-----+---+----------+
|  20221126170017119|20221126170017119...|              id:3|         dt=2022-11-26|2272e513-5516-43f...|  3|hudi| 10.0|100|2022-11-26|
+-------------------+--------------------+------------------+----------------------+--------------------+---+----+-----+---+----------+

注释掉INCR_PATH_GLOB,结果:

+-------------------+--------------------+------------------+----------------------+--------------------+---+----+-----+---+----------+
|_hoodie_commit_time|_hoodie_commit_seqno|_hoodie_record_key|_hoodie_partition_path|   _hoodie_file_name| id|name|price| ts|        dt|
+-------------------+--------------------+------------------+----------------------+--------------------+---+----+-----+---+----------+
|  20221127155346067|20221127155346067...|              id:4|         dt=2022-12-26|33e7a2ed-ea28-428...|  4|hudi| 10.0|100|2022-12-26|
|  20221127155339981|20221127155339981...|              id:3|         dt=2022-11-26|a5652ae0-942a-425...|  3|hudi| 10.0|100|2022-11-26|
+-------------------+--------------------+------------------+----------------------+--------------------+---+----+-----+---+----------+

继续注释掉END_INSTANTTIME,结果:

20221127161253433
20221127161311831
+-------------------+--------------------+------------------+----------------------+--------------------+---+----+-----+---+----------+
|_hoodie_commit_time|_hoodie_commit_seqno|_hoodie_record_key|_hoodie_partition_path|   _hoodie_file_name| id|name|price| ts|        dt|
+-------------------+--------------------+------------------+----------------------+--------------------+---+----+-----+---+----------+
|  20221127161320347|20221127161320347...|              id:5|         dt=2022-12-27|7b389e57-ca44-4aa...|  5|hudi| 10.0|100|2022-12-27|
|  20221127161311831|20221127161311831...|              id:4|         dt=2022-12-26|2707ce02-548a-422...|  4|hudi| 10.0|100|2022-12-26|
|  20221127161304742|20221127161304742...|              id:3|         dt=2022-11-26|264bc4a9-930d-4ec...|  3|hudi| 10.0|100|2022-11-26|
+-------------------+--------------------+------------------+----------------------+--------------------+---+----+-----+---+----------+

可以看到不包含起始时间,包含结束时间。

纯SQL方式

一般项目上都采用纯SQL方式进行增量查询,这样比较方便,纯SQL的方式参数和上面讲的参数是一样的,接下来看一下怎么用纯SQL方式实现

建表造数

create table hudi.test_hudi_incremental (id int,name string,price double,ts long,dt string
) using hudipartitioned by (dt)options (primaryKey = 'id',preCombineField = 'ts',type = 'cow'
);insert into hudi.test_hudi_incremental values (1,'a1', 10, 1000, '2022-11-25');
insert into hudi.test_hudi_incremental values (2,'a2', 20, 2000, '2022-11-25');
insert into hudi.test_hudi_incremental values (3,'a3', 30, 3000, '2022-11-26');
insert into hudi.test_hudi_incremental values (4,'a4', 40, 4000, '2022-12-26');
insert into hudi.test_hudi_incremental values (5,'a5', 50, 5000, '2022-12-27');

看一下有哪些commit_time

select distinct(_hoodie_commit_time) from test_hudi_incremental order by _hoodie_commit_time
+----------------------+
| _hoodie_commit_time  |
+----------------------+
| 20221130163618650    |
| 20221130163703640    |
| 20221130163720795    |
| 20221130163726780    |
| 20221130163823274    |
+----------------------+

纯SQL方式(一)

使用Call Procedures:copy_to_temp_viewcopy_to_table,目前这两个命令已经合到master,由scxwhite 苏承祥老哥贡献,这俩参数差不多,建议使用copy_to_temp_view,因为copy_to_table会先将数据落盘而copy_to_temp_view是创建的临时表,效率会高一点,且数据落盘无意义,后面还要将落盘的表删掉。

支持的参数

  • table
  • query_type
  • view_name
  • begin_instance_time
  • end_instance_time
  • as_of_instant
  • replace
  • global

测试SQL:

call copy_to_temp_view(table => 'test_hudi_incremental', query_type => 'incremental', 
view_name => 'temp_incremental', begin_instance_time=> '20221130163703640', end_instance_time => '20221130163726780');select _hoodie_commit_time, id, name, price, ts, dt from temp_incremental;

结果:

+----------------------+-----+-------+--------+-------+-------------+
| _hoodie_commit_time  | id  | name  | price  |  ts   |     dt      |
+----------------------+-----+-------+--------+-------+-------------+
| 20221130163726780    | 4   | a4    | 40.0   | 4000  | 2022-12-26  |
| 20221130163720795    | 3   | a3    | 30.0   | 3000  | 2022-11-26  |
+----------------------+-----+-------+--------+-------+-------------+

可以看到这种方式是可以实现增量查询的,但是需要注意,如果需要修改增量查询的起始时间,那么就需要重复执行copy_to_temp_view,但是因为临时表temp_incremental已经存在,要么新起个表名,要么先删掉,再创建新的,我建议先删掉,通过下面的命令删除

drop view if exists temp_incremental;

纯SQL方式(二)

PR地址:https://github.com/apache/hudi/pull/7182,这个PR同样由scxwhite贡献,目前只支持Spark3.2以上的版本(目前社区未合并)
增量查询SQL

select id, name, price, ts, dt from tableName
[
'hoodie.datasource.query.type'=>'incremental',
'hoodie.datasource.read.begin.instanttime'=>'$instant1',
'hoodie.datasource.read.end.instanttime'=>'$instant2'
]

这种方式,是支持了一种新的语法,在查询SQL后通过在[]添加参数的形式,感兴趣的话可以拉一下代码,自己打包试一下。

纯SQL方式(三)

使用 Spark SQL Hint实现,具体实现方式,请查看KnightChess的这篇文章如何使用 Spark SQL Hint 对 Hudi 进行增量查询、时间旅行
最终的效果如下

select/*+hoodie_prop('default.h1',map('hoodie.datasource.read.begin.instanttime', '20221127083503537', 'hoodie.datasource.read.end.instanttime', '20221127083506081')),hoodie_prop('default.h2',map('hoodie.datasource.read.begin.instanttime', '20221127083508715', 'hoodie.datasource.read.end.instanttime', '20221127083511803'))*/id, name, price, ts
from (select id, name, price, tsfrom default.h1union allselect id, name, price, tsfrom default.h2
)

是在hint中添加增量查询相关的参数,先指定表名再写参数,但是文章好像未给出完整的代码地址,大家有时间可以自己试一下。

纯SQL方式(四)

这种方式,是我按照Hive增量查询Hudi的方式修改的源码,通过set的方式实现增量查询。
PR地址:https://github.com/apache/hudi/pull/7339

关于为啥目前不能通过set参数进行增量查询,这里说明一下:根据文章Hudi Spark SQL源码学习总结-select(查询),可知Hudi的DefaultSource.createRelation中的optParams参数为readDataSourceTable中的options = table.storage.properties ++ pathOption,也就是表本身属性中的配置参数+path,之后在createRelation并没有接收其他参数,所以不能通过set参数的形式进行查询

和Hive增量查询一样,指定具体表名的增量查询参数

set hoodie.test_hudi_incremental.datasource.query.type=incremental
set hoodie.test_hudi_incremental.datasource.read.begin.instanttime=20221130163703640;
select _hoodie_commit_time, id, name, price, ts, dt from test_hudi_incremental;
+----------------------+-----+-------+--------+-------+-------------+
| _hoodie_commit_time  | id  | name  | price  |  ts   |     dt      |
+----------------------+-----+-------+--------+-------+-------------+
| 20221130163823274    | 5   | a5    | 50.0   | 5000  | 2022-12-27  |
| 20221130163726780    | 4   | a4    | 40.0   | 4000  | 2022-12-26  |
| 20221130163720795    | 3   | a3    | 30.0   | 3000  | 2022-11-26  |
+----------------------+-----+-------+--------+-------+-------------+

如果不同的库下面有相同的表名,则可以通过库名.表名的形式:

## 需要先开启使用数据库名称限定表名的配置,开启后上面不加库名的配置就失效了
set hoodie.query.use.database = true;
set hoodie.hudi.test_hudi_incremental.datasource.query.type=incremental;
set hoodie.hudi.test_hudi_incremental.datasource.read.begin.instanttime=20221130163703640;
set hoodie.hudi.test_hudi_incremental.datasource.read.end.instanttime=20221130163726780;
set hoodie.hudi.test_hudi_incremental.datasource.read.incr.path.glob=/dt=2022-11*/*;
refresh table test_hudi_incremental;
select _hoodie_commit_time, id, name, price, ts, dt from test_hudi_incremental;
+----------------------+-----+-------+--------+-------+-------------+
| _hoodie_commit_time  | id  | name  | price  |  ts   |     dt      |
+----------------------+-----+-------+--------+-------+-------------+
| 20221130163720795    | 3   | a3    | 30.0   | 3000  | 2022-11-26  |
+----------------------+-----+-------+--------+-------+-------------+

大家可以自己试一下,不同的库表关联的情形

这里需要注意一点,更新参数后,需要先refresh table,再查询,否则查询时修改的参数不生效,因为会使用缓存中的参数。
这种方式只是简单地修改了一下源码,使set的参数对查询生效。

为了避免有些读者嫌打包麻烦,这里给大家提供了hudi-spark3.1-bundle_2.12-0.13.0-SNAPSHOT.jar的下载地址:https://download.csdn.net/download/dkl12/87221476

总结

本文总结了Spark SQL增量查询Hudi表的一些参数设置,并给出了示例,介绍了使用纯Spark SQL实现增量查询Hudi表的几种方式,不确定未来社区会采用哪种方式,大家目前如果有这种需求的话,可以先选择一种自己喜欢的方式,等未来社区版本支持后,再升级版本。

参考:如何使用 Spark SQL Hint 对 Hudi 进行增量查询、时间旅行... - 墨天轮

Spark SQL增量查询Hudi表文章来源地址https://www.toymoban.com/news/detail-507546.html

到了这里,关于Hudi Spark-SQL增量查询数据几种方式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • spark-sql数据重复之File Output Committer问题

      我们先来回顾下之前介绍过的三种Committer:FileOutputCommitter V1、FileOutputCommitter V2、S3A Committer,其基本代表了整体的演进趋势。 核心代码讲解详细参照:Spark CommitCoordinator 保证数据一致性 OutputCommitter commitTask commitJob mapreduce.fileoutputcommitter.algorithm.version | 技术世界 | committask

    2024年02月14日
    浏览(40)
  • 04_Hudi 集成 Spark、保存数据至Hudi、集成Hive查询、MergeInto 语句

    本文来自\\\"黑马程序员\\\"hudi课程 4.第四章 Hudi 集成 Spark 4.1 环境准备 4.1.1 安装MySQL 5.7.31 4.1.2 安装Hive 2.1 4.1.3 安装Zookeeper 3.4.6 4.1.4 安装Kafka 2.4.1 4.2 滴滴运营分析 4.2.1 需求说明 4.2.2 环境准备 4.2.2.1 工具类SparkUtils 4.2.2.2 日期转换星期 4.2.3 数据ETL保存 4.2.3.1 开发步骤 4.2.3.2 加载CS

    2024年02月13日
    浏览(46)
  • spark-sql

    [root@localhost bin]# ./spark-sql Error: Failed to load class org.apache.spark.sql.hive.thriftserver.SparkSQLCLIDriver. Failed to load main class org.apache.spark.sql.hive.thriftserver.SparkSQLCLIDriver. You need to build Spark with -Phive and -Phive-thriftserver. 24/02/22 00:23:20 INFO ShutdownHookManager: Shutdown hook called 24/02/22 00:23:20 INFO Shutd

    2024年02月22日
    浏览(41)
  • 数仓知识07:数据增量更新的几种方式

    1、增量更新的几种方式 增量更新的本质,其实是获取源表中数据变化的情况(增、删、改),然后将源表中发生的变化同步至目标表中。 不同的方式,获取源表中数据变化的情况不一样,受技术的限制、表结构的限制,某些方式可能无法获取到完整的数据变化情况,因此只

    2024年02月06日
    浏览(45)
  • Spark-SQL小结

    目录 一、RDD、DataFrame、DataSet的概念、区别联系、相互转换操作   1.RDD概念   2.DataFrame概念   3.DataSet概念   4.RDD、DataFrame、DataSet的区别联系   5.RDD、DataFrame、DataSet的相互转换操作    1 RDD-DataFrame、DataSet    2  DataFrame-RDD,DataSet    3 DataSet-RDD,DataFrame 二、Spark-SQL连接JDBC的方式

    2024年02月09日
    浏览(43)
  • 02_快速体验 Hudi、编译 Hudi、安装HDFS、安装Spark 3.x、模拟数据、插入数据、查询数据、.hoodie文件、数据文件、Hudi 数据存储概述、Metadata 元数据等

    本文来自\\\"黑马程序员\\\"hudi课程 2.第二章 快速体验 Hudi 2.1 编译 Hudi 2.1.1 第一步、Maven 安装 2.1.2 第二步、下载源码包 2.1.3 第三步、添加Maven镜像 2.1.4 第四步、执行编译命令 2.1.5 第五步、Hudi CLI测试 2.2 环境准备 2.2.1 安装HDFS 2.2.2 安装Spark 3.x 2.3 spark-shell 使用 2.3.1 启动spark-shell

    2024年02月04日
    浏览(38)
  • spark-sql字段血缘实现

    Apache Spark是一个开源的大数据处理框架,它提供了一种高效、易于使用的方式来处理大规模数据集。在Spark中,数据是通过DataFrame和Dataset的形式进行操作的,这些数据结构包含了一系列的字段(也称为列)。字段血缘是Spark中的一个关键概念,它帮助我们理解数据的来源和流

    2024年02月02日
    浏览(49)
  • Spark参数配置和调优,Spark-SQL、Config

    一、Hive-SQL / Spark-SQL参数配置和调优 二、shell脚本spark-submit参数配置 三、sparkSession中配置参数

    2024年02月13日
    浏览(45)
  • Spark-SQL连接Hive的五种方法

    若使用Spark内嵌的Hive,直接使用即可,什么都不需要做(在实际生产活动中,很少会使用这一模式) 步骤: 将Hive中conf/下的hive-site.xml拷贝到Spark的conf/目录下; 把Mysql的驱动copy到jars/目录下; 如果访问不到hdfs,则将core-site.xml和hdfs-site.xml拷贝到conf/目录下; 重启spark-shell;

    2024年02月16日
    浏览(41)
  • spark-sql: insert overwrite分区表问题

    用spark-sql,insert overwrite分区表时发现两个比较麻烦的问题: 从目标表select出来再insert overwrite目标表时报错:Error in query: Cannot overwrite a path that is also being read from. 从其他表select出来再insert overwrite目标表时,其他分区都被删除了. 印象中这两个问题也出现过,但凭经验和感觉,

    2024年02月11日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包