Hudi 数据湖的插入,更新,查询,分析操作示例

作者:Grey

原文地址:

博客园:Hudi 数据湖的插入,更新,查询,分析操作示例

CSDN:Hudi 数据湖的插入,更新,查询,分析操作示例

前置工作

首先,需要先完成

Linux 下搭建 Kafka 环境

Linux 下搭建 Hadoop 环境

Linux 下搭建 HBase 环境

Linux 下搭建 Hive 环境

本文基于上述四个环境已经搭建完成的基础上进行 Hudi 数据湖的插入,更新,查询操作。

开发环境

Scala 2.11.8

JDK 1.8

需要熟悉 Maven 构建项目和 Scala 一些基础语法。

操作步骤

master 节点首先启动集群,执行:

stop-dfs.sh && start-dfs.sh

启动 yarn,执行:

stop-yarn.sh && start-yarn.sh

然后准备一个 Mave 项目,在 src/main/resources 目录下,将 Hadoop 的一些配置文件拷贝进来,分别是

$HADOOP_HOME/etc/hadoop/core-site.xml 文件

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
<name>fs.default.name</name>
<value>hdfs://master:9000</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/usr/local/hadoop/tmp</value>
</property>
</configuration>

注意,需要在你访问集群的机器上配置 host 文件,这样才可以识别 master 节点。

$HADOOP_HOME/etc/hadoop/hdfs-site.xml 文件

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?> <configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
<property>
<name>dfs.permissions</name>
<value>false</value>
</property>
</configuration>

$HADOOP_HOME/etc/hadoop/yarn-site.xml 文件,目前还没有任何配置

<?xml version="1.0"?>

<configuration>
</configuration>

然后,设计实体的数据结构,

package git.snippet.entity

case class MyEntity(uid: Int,
uname: String,
dt: String
)

插入数据代码如下

package git.snippet.test

import git.snippet.entity.MyEntity
import git.snippet.util.JsonUtil
import org.apache.spark.SparkConf
import org.apache.spark.sql.{SaveMode, SparkSession} object DataInsertion { def main(args: Array[String]): Unit = {
System.setProperty("HADOOP_USER_NAME", "root")
val sparkConf = new SparkConf().setAppName("MyFirstDataApp")
.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
.setMaster("local[*]")
val sparkSession = SparkSession.builder().config(sparkConf).enableHiveSupport().getOrCreate()
val ssc = sparkSession.sparkContext
ssc.hadoopConfiguration.set("dfs.client.use.datanode.hostname", "true")
insertData(sparkSession)
} def insertData(sparkSession: SparkSession) = {
import org.apache.spark.sql.functions._
import sparkSession.implicits._
val commitTime = System.currentTimeMillis().toString //生成提交时间
val df = sparkSession.read.text("/mydata/data1")
.mapPartitions(partitions => {
partitions.map(item => {
val jsonObject = JsonUtil.getJsonData(item.getString(0))
MyEntity(jsonObject.getIntValue("uid"), jsonObject.getString("uname"), jsonObject.getString("dt"))
})
})
val result = df.withColumn("ts", lit(commitTime)) //添加ts 时间戳列
.withColumn("uuid", col("uid"))
.withColumn("hudipart", col("dt")) //增加hudi分区列
result.write.format("org.apache.hudi")
.option("hoodie.insert.shuffle.parallelism", 2)
.option("hoodie.upsert.shuffle.parallelism", 2)
.option("PRECOMBINE_FIELD_OPT_KEY", "ts") //指定提交时间列
.option("RECORDKEY_FIELD_OPT_KEY", "uuid") //指定uuid唯一标示列
.option("hoodie.table.name", "myDataTable")
.option("hoodie.datasource.write.partitionpath.field", "hudipart") //分区列
.mode(SaveMode.Overwrite)
.save("/snippet/data/hudi")
}
}

然后,在 master 节点先准备好数据

vi data1

输入如下数据

{'uid':1,'uname':'grey','dt':'2022/09'}
{'uid':2,'uname':'tony','dt':'2022/10'}

然后创建文件目录,

hdfs dfs -mkdir /mydata/

把 data1 放入目录下

hdfs dfs -put data1 /mydata/

访问:http://192.168.100.130:50070/explorer.html#/mydata

可以查到这个数据

接下来执行插入数据的 scala 代码,执行完毕后,验证一下

访问:http://192.168.100.130:50070/explorer.html#/snippet/data/hudi/2022

可以查看到插入的数据

准备一个 data2 文件

cp data1 data2 && vi data2

data2 的数据更新为

{'uid':1,'uname':'grey1','dt':'2022/11'}
{'uid':2,'uname':'tony1','dt':'2022/12'}

然后执行

hdfs dfs -put data2 /mydata/

更新数据的代码,我们可以做如下调整,完整代码如下

package git.snippet.test

import git.snippet.entity.MyEntity
import git.snippet.util.JsonUtil
import org.apache.hudi.{DataSourceReadOptions, DataSourceWriteOptions}
import org.apache.spark.SparkConf
import org.apache.spark.sql.{SaveMode, SparkSession} object DataUpdate { def main(args: Array[String]): Unit = {
System.setProperty("HADOOP_USER_NAME", "root")
val sparkConf = new SparkConf().setAppName("MyFirstDataApp")
.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
.setMaster("local[*]")
val sparkSession = SparkSession.builder().config(sparkConf).enableHiveSupport().getOrCreate()
val ssc = sparkSession.sparkContext
ssc.hadoopConfiguration.set("dfs.client.use.datanode.hostname", "true")
updateData(sparkSession)
} def updateData(sparkSession: SparkSession) = {
import org.apache.spark.sql.functions._
import sparkSession.implicits._
val commitTime = System.currentTimeMillis().toString //生成提交时间
val df = sparkSession.read.text("/mydata/data2")
.mapPartitions(partitions => {
partitions.map(item => {
val jsonObject = JsonUtil.getJsonData(item.getString(0))
MyEntity(jsonObject.getIntValue("uid"), jsonObject.getString("uname"), jsonObject.getString("dt"))
})
})
val result = df.withColumn("ts", lit(commitTime)) //添加ts 时间戳列
.withColumn("uuid", col("uid")) //添加uuid 列
.withColumn("hudipart", col("dt")) //增加hudi分区列
result.write.format("org.apache.hudi")
// .option(DataSourceWriteOptions.TABLE_TYPE_OPT_KEY, DataSourceWriteOptions.MOR_TABLE_TYPE_OPT_VAL)
.option("hoodie.insert.shuffle.parallelism", 2)
.option("hoodie.upsert.shuffle.parallelism", 2)
.option("PRECOMBINE_FIELD_OPT_KEY", "ts") //指定提交时间列
.option("RECORDKEY_FIELD_OPT_KEY", "uuid") //指定uuid唯一标示列
.option("hoodie.table.name", "myDataTable")
.option("hoodie.datasource.write.partitionpath.field", "hudipart") //分区列
.mode(SaveMode.Append)
.save("/snippet/data/hudi")
}
}

执行更新数据的代码。

验证一下,访问:http://192.168.100.130:50070/explorer.html#/snippet/data/hudi/2022

可以查看到更新的数据情况

数据查询的代码也很简单,完整代码如下

package git.snippet.test

import org.apache.spark.SparkConf
import org.apache.spark.sql.SparkSession object DataQuery { def main(args: Array[String]): Unit = {
System.setProperty("HADOOP_USER_NAME", "root")
val sparkConf = new SparkConf().setAppName("MyFirstDataApp")
.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
.setMaster("local[*]")
val sparkSession = SparkSession.builder().config(sparkConf).enableHiveSupport().getOrCreate()
val ssc = sparkSession.sparkContext
ssc.hadoopConfiguration.set("dfs.client.use.datanode.hostname", "true")
queryData(sparkSession)
} def queryData(sparkSession: SparkSession) = {
val df = sparkSession.read.format("org.apache.hudi")
.load("/snippet/data/hudi/*/*")
df.show()
println(df.count())
}
}

执行,输出以下信息,验证成功。

数据查询也支持很多查询条件,比如增量查询,按时间段查询等。

接下来是 flink 实时数据分析的服务,首先需要在 master 上启动 kafka,并创建 一个名字为 mytopic 的 topic,详见Linux 下搭建 Kafka 环境

相关命令如下

创建topic

kafka-topics.sh --zookeeper 127.0.0.1:2181 --replication-factor 1 --partitions 1 --create --topic  mytopic

生产者启动配置

kafka-console-producer.sh --broker-list 127.0.0.1:9092 --topic mytopic

消费者启动配置

kafka-console-consumer.sh --bootstrap-server 127.0.0.1:9092 --topic mytopic

然后运行如下代码

package git.snippet.analyzer;

import org.apache.flink.api.common.serialization.SimpleStringSchema;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer; import java.util.Properties; public class DataAnalyzer {
public static void main(String[] args) {
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); Properties properties = new Properties();
properties.setProperty("bootstrap.servers", "192.168.100.130:9092");
properties.setProperty("group.id", "snippet");
//构建FlinkKafkaConsumer
FlinkKafkaConsumer<String> myConsumer = new FlinkKafkaConsumer<>("mytopic", new SimpleStringSchema(), properties);
//指定偏移量
myConsumer.setStartFromLatest();
final DataStream<String> stream = env.addSource(myConsumer);
env.enableCheckpointing(5000);
stream.print();
try {
env.execute("DataAnalyzer");
} catch (Exception e) {
e.printStackTrace();
}
}
}

其中

properties.setProperty("bootstrap.servers", "192.168.100.130:9092");

根据自己的配置调整,然后通过 kakfa 的生产者客户端输入一些数据,这边可以收到这个数据,验证完毕。

完整代码见

data-lake

Hudi 数据湖的插入,更新,查询,分析操作示例的更多相关文章

  1. Apache Hudi数据跳过技术加速查询高达50倍

    介绍 在 Hudi 0.10 中,我们引入了对高级数据布局优化技术的支持,例如 Z-order和希尔伯特空间填充曲线(作为新的聚类算法),即使在经常使用过滤器查询大表的复杂场景中,也可以在多个列而非单 ...

  2. C 线性表的链式存储实现及插入、删除等操作示例

    一.链式存储的优势 线性表的存储可以通过顺序存储或链式存储实现,其中顺序存储基于数组实现(见本人上一篇博客),在进行插入删除等操作时,需对表内某一部分元素逐个移动,效率较低.而链式结构不依赖于地址连续 ...

  3. C 线性表的顺序存储实现及插入、删除等操作示例

    一.线性表的定义 线性表(Linear List)是由同一类型元素构成的有序序列的线性结构.线性表中元素的个数称为线性表的长度:线性表内没有元素(长度为0)时,称为空表:表的起始位置称为表头,表的结束 ...

  4. 使用Apache Spark和Apache Hudi构建分析数据湖

    1. 引入 大多数现代数据湖都是基于某种分布式文件系统(DFS),如HDFS或基于云的存储,如AWS S3构建的.遵循的基本原则之一是文件的"一次写入多次读取"访问模型.这对于处理 ...

  5. 数据湖框架选型很纠结?一文了解Apache Hudi核心优势

    英文原文:https://hudi.apache.org/blog/hudi-indexing-mechanisms/ Apache Hudi使用索引来定位更删操作所在的文件组.对于Copy-On-W ...

  6. 使用Apache Hudi构建大规模、事务性数据湖

    一个近期由Hudi PMC & Uber Senior Engineering Manager Nishith Agarwal分享的Talk 关于Nishith Agarwal更详细的介绍,主 ...

  7. Apache Hudi:云数据湖解决方案

    1. 引入 开源Apache Hudi项目为Uber等大型组织提供流处理能力,每天可处理数据湖上的数十亿条记录. 随着世界各地的组织采用该技术,Apache开源数据湖项目已经日渐成熟. Apache ...

  8. 印度最大在线食品杂货公司Grofers的数据湖建设之路

    1. 起源 作为印度最大的在线杂货公司的数据工程师,我们面临的主要挑战之一是让数据在整个组织中的更易用.但当评估这一目标时,我们意识到数据管道频繁出现错误已经导致业务团队对数据失去信心,结果导致他们永 ...

  9. 构建数据湖上低延迟数据 Pipeline 的实践

    T 摘要 · 云原生与数据湖是当今大数据领域最热的 2 个话题,本文着重从为什么传统数仓 无法满足业务需求? 为何需要建设数据湖?数据湖整体技术架构.Apache Hudi 存储模式与视图.如何解决冷 ...

随机推荐

  1. 【Github开源项目体验】- ZFile 基于 Java 的在线网盘

    [Github开源项目体验]- ZFile 基于 Java 的在线网盘 在线云盘.网盘.OneDrive.云存储.私有云.对象存储.h5ai.上传.下载 date: 2022-08-02 addres ...

  2. Java面试题(六)--Redis

    1 Redis基础篇 1.简单介绍一下Redis优点和缺点? 优点: 1.本质上是一个 Key-Value 类型的内存数据库,很像memcached 2.整个数据库统统加载在内存当中进行操作,定期通过 ...

  3. Android OOM 问题探究 -- 从入门到放弃

    一.前言 最近客户反馈了一些OOM的问题,很早之前自己也有简单了解过OOM的知识,但时间久远,很多东西都记不清了. 现在遇到这个OOM问题,也即趁此搜索了一些资料,对OOM问题做一些探究,把资料记录于 ...

  4. 用 Windows Server 2019 搭建求生之路服务器

    准备工作 要搭建一台 Windows Server 的求生之路服务器需要做以下几点前置工作: 购买一台云服务器,如腾讯云: 下载 SteamCMD: 安装 SourceMod.MateMod.L4dT ...

  5. C++ 添加程序图标到我的电脑

    C++ 像我的电脑中 百度网盘的 那图标快捷方式.如何生成的呢?设置程序图标到我的电脑 请看下边代码 就ok了(*^__^*) 嘻嘻-- 类似下图: 大家如果看我下边的不是很清楚,可以下载这个具体工程 ...

  6. TCP实现多个客户端发送数据给服务器端

    SocketThread给服务端用的线程类: public class SocketThread extends Thread{ private Socket socket; public Socke ...

  7. CF915G Coprime Arrays (莫比乌斯反演)

    CF915G Coprime Arrays 题解 (看了好半天终于看懂了) 我们先对于每一个i想,那么 我们设 我们用莫比乌斯反演 有了这个式子,可比可以求出△ans呢?我们注意到,由于那个(i/d) ...

  8. 【JDBC】学习路径8-连接池

    为什么是连接池? 第一.受我们硬件资源的限制,我们的一些资源使用时有限制的比如我们的数据库 连接数和线程数.为了摆脱这些限制,我们就使用了池化技术来将这些资源限制在一定范围内. 第二.我们创建和销毁这 ...

  9. 自定义View3-水波纹扩散(仿支付宝咻一咻)实现代码、思想

    PS:自定义view篇-水波纹实现 效果:水波纹扩散 场景:雷达.按钮点击效果.搜索等 实现:先上效果图,之前记得支付宝有一个咻一咻,当时就是水波纹效果,实现起来一共两步,第一画内圆,第二画多个外圆, ...

  10. docker存储管理及实例

    一.Docker存储概念 1.容器本地存储与Docke存储驱动 容器本地存储:每个容器都被自动分配了内部存储,即容器本地存储.采用的是联合文件系统.通过存储驱动进行管理. 存储驱动:控制镜像和容器在 ...