Hive 集成 Hudi 实践(含代码)| 可能是全网最详细的数据湖系列
公众号后台越来越多人问关于数据湖相关的内容,看来大家对新技术还是很感兴趣的。关于数据湖的资料网络上还是比较少的,特别是实践系列,对于新技术来说,基础的入门文档还是很有必要的,所以这一篇希望能够帮助到想使用Hudi的同学入门。
本篇的Hudi使用的是孵化版本 0.5.2;其他依赖 Spark-2.4.4,Hive-1.1.0
Hudi 服务器环境准备
wget https://github.com/apache/hudi/archive/release-0.5.2-incubating.tar.gz
tar zxvf release-0.5.2-incubating.tar.gz
cd release-0.5.2-incubating
mvn clean package -DskipTests -DskipITs
cp ./hudi-hadoop-mr/target/hudi-hadoop-mr-0.5.2-incubating.jar $HIVE_HOME/lib/
拷贝依赖包到 Hive 路径是为了 Hive 能够正常读到 Hudi 的数据,至此服务器环境准备完毕。
用 Spark 写一段数据
一切准备完毕先写一段数据到 Hudi 里,首先数据源 ods.ods_user_event 的表结构为:
CREATE TABLE ods.ods_user_event(
uuid STRING,
name STRING,
addr STRING,
update_time STRING,
date STRING)
stored as parquet;
然后是 Maven 的依赖,详细代码关注公众号【老蒙大数据】回复 hudi 后即可获取。
<dependency>
<groupId>org.apache.hudi</groupId>
<artifactId>hudi-spark_2.11</artifactId>
<version>0.5.2-incubating</version>
</dependency>
<dependency>
<groupId>org.apache.hudi</groupId>
<artifactId>hudi-common</artifactId>
<version>0.5.2-incubating</version>
</dependency>
代码逻辑:
- 初始化 SparkSession,配置相关配置项
- 构建 DataFrame,大家可以自由发挥,这里的案例是从Hive读数据构建。
- DataFrame写入Hudi,这一块说到底就是把数据写入 HDFS 路径下,但是需要一堆配置,这些配置就体现了 Hudi 的特性:
- DataSourceWriteOptions.RECORDKEY_FIELD_OPT_KEY:指定唯一id的列名
- DataSourceWriteOptions.PRECOMBINE_FIELD_OPT_KEY:指定更新时间,该字段数值大的数据会覆盖小的
- DataSourceWriteOptions.PARTITIONPATH_FIELD_OPT_KEY:指定分区列,和Hive的分区概念类似
- HoodieIndexConfig.BLOOM_INDEX_UPDATE_PARTITION_PATH:设置当分区变更时,当前数据的分区目录是否变更
- HoodieIndexConfig.INDEX_TYPE_PROP:设置索引类型目前有 HBASE,INMEMORY,BLOOM,GLOBAL_BLOOM 四种索引
上述例子中,选择了 HoodieGlobalBloomIndex(全局索引),会在所有分区内查找指定的 recordKey。而 HoodieBloomIndex 只在指定的分区内查找。
def main(args: Array[String]): Unit = {
val sss = SparkSession.builder.appName("hudi")
.config("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
.config("hive.metastore.uris", "thrift://ip:port")
.enableHiveSupport().getOrCreate()
val sql = "select * from ods.ods_user_event"
val df: DataFrame = sss.sql(sql)
df.write.format("org.apache.hudi")
.option(DataSourceWriteOptions.RECORDKEY_FIELD_OPT_KEY, "recordKey")
.option(DataSourceWriteOptions.PRECOMBINE_FIELD_OPT_KEY, "update_time")
.option(DataSourceWriteOptions.PARTITIONPATH_FIELD_OPT_KEY, "date")
.option(HoodieIndexConfig.BLOOM_INDEX_UPDATE_PARTITION_PATH, "true")
.option(HoodieIndexConfig.INDEX_TYPE_PROP, HoodieIndex.IndexType.GLOBAL_BLOOM.name())
.option("hoodie.insert.shuffle.parallelism", "10")
.option("hoodie.upsert.shuffle.parallelism", "10")
.option(HoodieWriteConfig.TABLE_NAME, "ods.ods_user_event_hudi")
.mode(SaveMode.Append)
.save("/user/hudi/lake/ods.db/ods_user_event_hudi")
}
执行成功后会有如下结果,因为我们是按照date分区,每一天的数据会生成一个文件夹和Hive类似。
[hadoop@hadoop31 ~]# hdfs dfs -ls /user/hudi/lake/ods.db/ods_user_event_hudi/
Found 4 items
drwxr-xr-x - hadoop hadoop 0 2020-05-25 18:42 /user/hudi/lake/ods.db/ods_user_event_hudi/20200501
drwxr-xr-x - hadoop hadoop 0 2020-05-25 18:42 /user/hudi/lake/ods.db/ods_user_event_hudi/20200502
drwxr-xr-x - hadoop hadoop 0 2020-05-25 18:42 /user/hudi/lake/ods.db/ods_user_event_hudi/20200503
drwxr-xr-x - hadoop hadoop 0 2020-05-25 18:42 /user/hudi/lake/ods.db/ods_user_event_hudi/20200504
另外,注意 recordKey 必须唯一,不然数据会被覆盖,且值不能为 null,否则会有以下报错。
Caused by: org.apache.hudi.exception.HoodieKeyException: recordKey value: "null" for field: "user_uid" cannot be null or empty.
Hive 创建外部表读数据
上一步中 Spark 将数据写到了 hudi,想要通过Hive访问到这块数据,就需要创建一个Hive外部表了,因为 Hudi 配置了分区,所以为了能读到所有的数据,咱们的外部表也得分区,分区字段名可随意配置。
CREATE TABLE ods.ods_user_event_hudi(
uuid STRING,
name STRING,
addr STRING,
update_time STRING,
date STRING)
PARTITIONED BY (
`dt` string)
ROW FORMAT SERDE
'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe'
STORED AS INPUTFORMAT
'org.apache.hudi.hadoop.HoodieParquetInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat'
LOCATION
'/user/hudi/lake/ods.db/ods_user_event_hudi'
至此,直接读数据肯定是空的,因为我们创建的是个分区表,所以还需要指定分区
alter table ods.ods_user_event_hudi add if not exists partition(dt='20200504') location '/user/hudi/lake/ods.db/ods_user_event_hudi/20200504'
那么这个时候问题来了,一年有365个分区,要一个一个建立手动创建分区吗?
抱歉我也没发现更好的办法,只能送你个简单的脚本了。
#!/bin/bash
start_date=20190101
end_date=20200520
start=`date -d "$start_date" "+%s"`
end=`date -d "$end_date" "+%s"`
for((i=start;i<=end;i+=86400)); do
dt=$(date -d "@$i" "+%Y%m%d")
hive -e "alter table ods.ods_user_event_hudi add if not exists partition(dt='${dt}') location '/user/hudi/lake/ods.db/ods_user_event_hudi/${dt}';
"
done
后记
最后,执行 select * from ods.ods_user_event_hudi 要是没有数据你来找我。另外值得注意的是,如果此时直接用 Hive 将数据 insert into ods.ods_user_event_hudi,虽然数据会写入到 hudi 的目录下,但是相同的 recordKey 是不会覆盖原有数据的。
下一篇详细写 Spark 操作 Hudi 的相关内容,敬请期待。本篇详细代码关注公众号【老蒙大数据】回复 hudi 后即可获取。
推荐阅读
3000字长文教你大数据该怎么学!
选方向?大数据的职位你了解多少
Hive 集成 Hudi 实践(含代码)| 可能是全网最详细的数据湖系列的更多相关文章
- Hive集成HBase实践
#step1: create hive table 't_test' hive -e "create table test.t_user(id int,name string,age int ...
- Robinhood基于Apache Hudi的下一代数据湖实践
1. 摘要 Robinhood 的使命是使所有人的金融民主化. Robinhood 内部不同级别的持续数据分析和数据驱动决策是实现这一使命的基础. 我们有各种数据源--OLTP 数据库.事件流和各种第 ...
- 如何使用Hive集成Solr?
(一)Hive+Solr简介 Hive作为Hadoop生态系统里面离线的数据仓库,可以非常方便的使用SQL的方式来离线分析海量的历史数据,并根据分析的结果,来干一些其他的事情,如报表统计查询等. So ...
- Apache Hudi:云数据湖解决方案
1. 引入 开源Apache Hudi项目为Uber等大型组织提供流处理能力,每天可处理数据湖上的数十亿条记录. 随着世界各地的组织采用该技术,Apache开源数据湖项目已经日渐成熟. Apache ...
- 大数据学习系列之九---- Hive整合Spark和HBase以及相关测试
前言 在之前的大数据学习系列之七 ----- Hadoop+Spark+Zookeeper+HBase+Hive集群搭建 中介绍了集群的环境搭建,但是在使用hive进行数据查询的时候会非常的慢,因为h ...
- Apache Hudi 与 Hive 集成手册
1. Hudi表对应的Hive外部表介绍 Hudi源表对应一份HDFS数据,可以通过Spark,Flink 组件或者Hudi客户端将Hudi表的数据映射为Hive外部表,基于该外部表, Hive可以方 ...
- 科学经得起实践检验-python3.6通过决策树实战精准准确预测今日大盘走势(含代码)
科学经得起实践检验-python3.6通过决策树实战精准准确预测今日大盘走势(含代码) 春有百花秋有月,夏有凉风冬有雪: 若无闲事挂心头,便是人间好时节. --宋.无门慧开 不废话了,以下训练模型数据 ...
- 生态 | Apache Hudi集成Alluxio实践
原文链接:https://mp.weixin.qq.com/s/sT2-KK23tvPY2oziEH11Kw 1. 什么是Alluxio Alluxio为数据驱动型应用和存储系统构建了桥梁, 将数据从 ...
- 大数据技术之_11_HBase学习_02_HBase API 操作 + HBase 与 Hive 集成 + HBase 优化
第6章 HBase API 操作6.1 环境准备6.2 HBase API6.2.1 判断表是否存在6.2.2 抽取获取 Configuration.Connection.Admin 对象的方法以及关 ...
随机推荐
- java权限设计思考
1.粗粒度权限设计与细粒度权限设计 粗粒度(Coarse-graind) 表示类别级,即仅考虑对象的类别(the type of object),不考 ...
- ES[7.6.x]学习笔记(八)数据的增删改
在前面几节的内容中,我们学习索引.字段映射.分析器等,这些都是使用ES的基础,就像在数据库中创建表一样,基础工作做好以后,我们就要真正的使用它了,这一节我们要看看怎么向索引里写入数据.修改数据.删除数 ...
- GitHub 热点速览 Vol.19:如何叩响大厂的门?
作者:HelloGitHub-小鱼干 摘要:进大厂,无疑是升职加薪走上人生巅峰的一个敲门砖,那,如何拿到这个敲门砖呢?前辈的经验之谈,无疑会给我们进大厂带来许多的经验参考,本周的#大厂面试经验之谈#主 ...
- STM32 OSAL操作系统抽象层的移植
文章目录 什么是 OSAL? 源码安装 Linux 上OSAL的移植 STM32上OSAL的移植 关键点 测试代码 结语 附件 什么是 OSAL? 今天同学忽然问我有没有搞过OSAL,忽然间一头雾水, ...
- 可怕!CPU竟成了黑客的帮凶!
本故事根据CPU真实漏洞改编 前情回顾 还记得我吗,我是阿Q,就是那个CPU一号车间的阿Q啊.如果你忘记了我,记得看看这里回忆一下哦:完了!CPU一味求快出事儿了! 自从我们车间用上了乱序执行和分支预 ...
- .NETcore中使用jwt来对api进行身份验证
对于 登陆,身份,授权这之类的操作,我们最常用的几种方法无非就是 cookie session token 这三者的差别 https://www.cnblogs.com/moyand/p/904797 ...
- [hdu5402 Travelling Salesman Problem]YY
题意:给一个n*m的矩形,每个格子有一个非负数,求一条从(1,1)到(n,m)的路径(不能经过重复的格子),使得经过的数的和最大,输出具体的方案 思路:对于row为奇数的情况,一行行扫下来即可全部走完 ...
- ASP.NET Core Blazor 初探之 Blazor Server
上周初步对Blazor WebAssembly进行了初步的探索(ASP.NET Core Blazor 初探之 Blazor WebAssembly).这次来看看Blazor Server该怎么玩. ...
- python--常用模块calendar
常用模块: calendar.time.datetime.timeit.os.shutil.zip.math.string 上述所有的模块使用理论上都应该先导入,string是特例 -calendar ...
- Lr运行错误Error: Socket descriptor not found. Hint: the problem might be
在controller中,运行时,报如下错误“Error: Socket descriptor not found. Hint: the problem might be solved applyi ...