
数据湖湖仓一体大数据数据存储【免费下载链接】hudiUpserts, Deletes And Incremental Processing on Big Data.项目地址https://gitcode.com/gh_mirrors/hud/hudi点击查看免费下载本文档源于仓库hudi-trino/src/test/resources/hudi-testing-data/下的测试数据生成脚本完整记录了如何用 Spark SQL 创建一张覆盖 Hudi 全部标量与嵌套复杂类型的 MOR 表含 Metadata Table 索引并通过 INSERT 与 UPDATE 生成基础文件与 log 文件。读者读完可掌握如何构造一张全类型 MOR 表、如何理解各类型在 Spark/Hive 元数据与 Trino 之间的映射关系以及 Trino Hudi 连接器测试testComprehensiveTypes是如何逐列校验读取结果的。它是理解 Hudi 类型系统与 Trino 读取能力边界的实战标本。文档定位一份测试数据的生成脚本而非普通说明文档该目录下的hudi_comprehensive_types_v6_mor.mdv6 版本与hudi_comprehensive_types_v8_mor.mdv8 版本是成对出现的Create script.md文件记录测试表的生成过程同名的.zip文件如 hudi_comprehensive_types_v6_mor.zip则是按该脚本实际生成并导出的 Hudi 表数据供测试运行时解压使用。表结构要点在文档开头即已声明MOR 表Merge-on-Read并启用了 MDTMetadata TableHudi 元数据表表内容对应两个 Hudi 版本修订v6 对应tag release-0.15.0v8 对应提交444cac26cb1077fd2b7deefc7b3713bacb270f9c。测试侧ResourceHudiTablesInitializer.java 中通过枚举HUDI_COMPREHENSIVE_TYPES_V6_MOR与HUDI_COMPREHENSIVE_TYPES_V8_MOR注册这两张表isCreateRtTable true意味着初始化时会同时创建 RORead-Optimized表名无后缀与 RTReal-Time表名追加_rt后缀两张 metastore 表——这正是 MOR 语义下两种读取视角的载体。全类型表结构设计五大类型组的 DDL 剖析文档给出的建表语句以uuid为主键、precombine_field为预合并字段按part_col分区并用TBLPROPERTIES声明primaryKey、type mor、preCombineField。核心价值在于它对 Hudi 支持的数据类型做了系统性铺排数值类型BOOLEAN、TINYINT、SMALLINT、INT、BIGINT、FLOAT、DOUBLE、DECIMAL(10, 2)字符串类型STRING、VARCHAR(50)、CHAR(10)二进制类型BINARY日期时间类型DATE、TIMESTAMPTIMESTAMP_NTZ因 Hudi 暂不支持而注释保留嵌套复杂类型ARRAYINT、ARRAYSTRING、MAPSTRING, INT、STRUCTf1: STRING, f2: INT, f3: BOOLEAN以及层层嵌套的组合形态——数组套结构、Map 套结构、结构套结构、数组套数组、Map 套数组、Map 套 Map结构内再套数组/Map 等共 14 个复杂列。建表 DDL 完整如下来自原文档可直接复制运行CREATE TABLE hudi_type_test_mor ( uuid STRING, precombine_field LONG, -- Numeric Types col_boolean BOOLEAN, col_tinyint TINYINT, col_smallint SMALLINT, col_int INT, col_bigint BIGINT, col_float FLOAT, col_double DOUBLE, col_decimal DECIMAL(10, 2), -- String Types col_string STRING, col_varchar VARCHAR(50), col_char CHAR(10), -- Binary Type col_binary BINARY, -- Datetime Types col_date DATE, col_timestamp TIMESTAMP, -- col_timestamp_ntz TIMESTAMP_NTZ, (No support on Hudi for now) -- Complex types col_array_int ARRAYINT, col_array_string ARRAYSTRING, col_map_string_int MAPSTRING, INT, col_struct STRUCTf1: STRING, f2: INT, f3: BOOLEAN, col_array_struct ARRAYSTRUCTnested_f1: DOUBLE, nested_f2: ARRAYSTRING, col_map_string_struct MAPSTRING, STRUCTnested_f3: DATE, nested_f4: DECIMAL(5,2), col_array_struct_with_map ARRAYSTRUCTf_arr_struct_str: STRING, f_arr_struct_map: MAPSTRING, INT, col_map_struct_with_array MAPSTRING, STRUCTf_map_struct_arr: ARRAYBOOLEAN, f_map_struct_ts: TIMESTAMP, col_struct_nested_struct STRUCTouter_f1: INT, nested_struct: STRUCTinner_f1: STRING, inner_f2: BOOLEAN, col_array_array_int ARRAYARRAYINT, col_map_string_array_double MAPSTRING, ARRAYDOUBLE, col_map_string_map_string_date MAPSTRING, MAPSTRING, DATE, -- Array of structs with single (inner) fields do not work with parquet.version 1.13.1 col_struct_array_struct STRUCTouter_f2: STRING, struct_array: ARRAYSTRUCTinner_f3: TIMESTAMP, inner_f4: STRING, col_struct_map STRUCTouter_f3: BOOLEAN, struct_map: MAPSTRING, BIGINT, part_col STRING ) USING hudi LOCATION your-location TBLPROPERTIES ( primaryKey uuid, type mor, preCombineField precombine_field ) PARTITIONED BY (part_col)对应的 Hive 元数据 Schema 在 ResourceHudiTablesInitializer.java 的hudiComprehensiveTypesColumns()中逐列声明用HIVE_*常量与decimalHiveType、varcharHiveType、charHiveType、listHiveType、mapHiveType、structHiveType等辅助方法构建例如col_tinyint映射为HIVE_BYTE、col_smallint映射为HIVE_SHORT、col_binary映射为HIVE_BINARY复杂列则逐层构造 TypeInfo。这确保了 metastore 中的 Schema 与 Hudi 文件内 Schema 一致是连接器能够正确解码的基础。写入三行数据覆盖全部类型的 INSERT 详解文档随后通过三次INSERT写入三条记录两行进入分区Auuid1、uuid2一行进入分区Buuid3。三次插入在设计上互为补充第 1 行uuid1分区 A所有类型全部填充典型值作为满值基准第 2 行uuid2分区 A数值规模变化如col_int从 1000 变为 2000且首次引入嵌套内部的 null——例如col_array_struct整体为null、col_map_struct_with_array中map_struct4的数组字段为null、col_struct_nested_struct中内层结构为null、col_map_string_map_string_date的整层 Map 为null第 3 行uuid3分区 B除个别列外几乎所有列均为null专门验证空值读取路径。以第 1 行为例INSERT 语句展示了各类型的标准写法注意类型标注的 cast 用法可直接照搬INSERT INTO hudi_type_test_mor VALUES ( uuid1, 1000L, true, cast(1 as tinyint), cast(100 as smallint), 1000, 100000L, 1.1, 10.123, cast(123.45 as decimal(10,2)), string val 1, cast(varchar val 1 as varchar(50)), cast(charval1 as char(10)), cast(binary1 as binary), cast(2025-01-15 as date), cast(2025-01-15 11:30:00 as timestamp), array(1, 2, 3), array(a, b, c), map(key1, 10, key2, 20), struct(struct_str1, 55, false), array(struct(1.1, array(n1,n2)), struct(2.2, array(n3))), map(mapkey1, struct(cast(2024-11-01 as date), cast(9.8 as decimal(5,2)))), array(struct(arr_struct1, map(map_in_struct_k1, 1)), struct(arr_struct2, map(map_in_struct_k2, 2, map_in_struct_k3, 3))), map(map_struct1, struct(array(true, false), cast(2025-01-01 01:01:01 as timestamp)), map_struct2, struct(array(false), cast(2025-02-02 02:02:02 as timestamp))), struct(101, struct(inner_str_1, true)), array(array(1, 2), array(3, 4, 5)), map(arr_key1, array(1.1, 2.2), arr_key2, array(3.3)), map(map_key1, map(mapkey10, cast(2024-01-01 as date), mapkey20, cast(2024-02-02 as date))), struct(outer_str_1, array(struct(cast(2023-11-11 11:11:11 as timestamp), inner_str_1))), struct(true, map(struct_map_k1, 1000L, struct_map_k2, 2000L)), A )第 2、3 行的完整语句请直接参考原文档 hudi_comprehensive_types_v6_mor.md其中第 2 行刻意用null填充部分复杂列的内层字段第 3 行则大面积置空——两者共同构成嵌套空值 整行空值的双重测试覆盖。通过 UPDATE 生成 log 文件MOR 增量语义的关键一步MOR 表的读取特性依赖 log 文件而 log 文件必须由后续的更新操作产生。文档在三次 INSERT 之后执行两条 UPDATE-- Generate log files through updates on partition A UPDATE hudi_type_test_mor SET col_double col_double 100, precombine_field precombine_field 1 WHERE part_col A -- Generate log files through updates on partition B UPDATE hudi_type_test_mor SET col_string updated string, precombine_field precombine_field 1 WHERE part_col B其结果是分区 A 的col_double被整体加 10010.123 → 110.123、20.456 → 120.456分区 B 的col_string被改写为updated string所有行的precombine_field递增 1。由于测试脚本随后关闭了内联 compaction这些更新只进入 log 文件、不合并回基础 Parquet 文件从而在表中同时存在基础文件与 log 文件两种形态——这正是 Trino 连接器验证 MOR 文件切片file slicing与日志合并逻辑所需的真实数据形态。会话级配置控制 compaction、文件大小与 MDT 索引文档在建表后通过spark.sql(...)设置了一批关键会话参数其作用逐条解读如下配置项文档中的值作用hoodie.compact.inline.max.delta.commits9999抬高超大阈值避免写入过程中自动触发 compaction 调度hoodie.compact.inlinefalsefalse显式关闭内联 compaction保证 UPDATE 只产生 log 文件、不合并回基础文件hoodie.parquet.small.file.limit0强制每次写入直接生成新 Parquet 文件避免小文件回填逻辑干扰测试数据布局hoodie.metadata.compact.max.delta.commits1控制 MDT元数据表自身的 compaction 频率hoodie.metadata.index.column.stats.enabletrue开启列统计索引Column Stats Indexhoodie.metadata.record.index.enabletrue开启记录级索引Record Index与列统计索引配合可支撑记录级文件跳过文档注释特别说明开启列统计索引时分区统计索引Partition Stats Index会随之启用。这些参数共同决定了测试表的物理形态——不含 compaction 的 log 文件、独立的新基础文件、带 MDT 索引的元数据表——是后续 Trino 端各类 file skipping、分区裁剪测试能够成立的前提。Trino 侧验证testComprehensiveTypes 如何逐列校验数据生成的最终目的是验证 Trino Hudi 连接器的读取正确性。在 TestHudiSmokeTest.java 的testComprehensiveTypes中测试通过MethodSource(comprehensiveTestParameters)参数化运行对HUDI_COMPREHENSIVE_TYPES_V6_MOR、HUDI_COMPREHENSIVE_TYPES_V8_MOR两张表分别以isRtTable true/false两种模式即_rt实时表与 RO 优化表执行查询。测试会话会开启hudi.metadata_enabledtrue参见测试类中多次出现的SET SESSION hudi.metadata_enabledtrue以 MDT 路径读取。校验思路是逐列比对为每个列预先构造三行期望值对应 uuid1/uuid2/uuid3再用SELECT column FROM table实际查询并与期望值UNION ALL比对最后还执行一次全列联合查询。期望值同时揭示了RT 与 RO 的读取差异precombine_fieldRT 读到BIGINT 1001/1006/1101更新后RO 读到BIGINT 1000/1005/1100基础文件原值col_double分区 A 更新后RT 为DOUBLE 110.123/120.456RO 仍为DOUBLE 10.123/20.456col_string分区 B 更新后RT 为updated stringRO 仍为NULL该行原始写入即为 NULL。这直观印证了 MOR 语义RT 表实时合并 log 与基础文件RO 表只读基础文件。测试注释还专门说明此处不用assertQuery是因为其内部基于 H2QueryRunner、无法表达MAP等类型必须改用 TrinoQueryRunner。期望值同时给出了 Trino 侧的完整类型映射例如col_float→REAL、col_binary→VARBINARYbinary1的 UTF-8 字节表示为X62696e61727931、col_tinyint→TINYINT、col_decimal→DECIMAL 123.45、col_timestamp→TIMESTAMP 2025-01-15 11:30:00.000复杂类型则展开为 Trino 的ARRAY/MAP/ROW字面量如col_map_string_struct的期望值为MAP(ARRAY[mapkey1], ARRAY[CAST(ROW(DATE 2024-11-01, DECIMAL 9.80) AS ROW(nested_f3 DATE, nested_f4 DECIMAL(5,2)))])。除整体比对外测试还专门演示了嵌套字段提取对col_map_string_struct执行SELECT (map_values(col_map_string_struct))[1].nested_f4先map_values把 Map 的值抽成数组再用 1 起始下标取出唯一 ROW最后访问.nested_f4字段——这是 Trino 中访问 Map 内嵌套结构的典型写法也是连接器深层字段解析能力的验证点。v6 与 v8 两版本数据的关系目录中同时存在 v6 与 v8 两套同名资源二者 DDL 与数据完全一致区别仅在于生成时使用的 Hudi 修订版本v6 为release-0.15.0tagv8 为提交444cac26cb1077fd2b7deefc7b3713bacb270f9c。由于 Hudi 各版本的文件布局、元数据表结构与 Parquet 写出版本可能不同成对保留能让连接器测试覆盖同一份表、两种 Hudi 版本产物的兼容性场景comprehensiveTestParameters将两表都纳入参数化也正是为了并行验证。已知限制与注意事项文档注释中明确记录了三条边界信息值得在复用这套数据或扩展测试时留意TIMESTAMP_NTZ暂不支持建表 DDL 中该列被注释注释原文为No support on Hudi for now说明时间戳无时区类型尚未纳入测试覆盖Parquet 版本限制col_struct_array_struct列的注释指出Array of structs with single (inner) fields do not work with parquet.version 1.13.1即单字段内层结构的数组在特定 Parquet 版本下存在问题测试数据刻意绕开了这种形态MDT 是测试前提整个测试以hudi.metadata_enabledtrue与带索引的 MDT 为前提若脱离 MDT 直接读文件则无法覆盖文档所述列统计索引、记录索引对应的跳过与裁剪场景。如何复用这套测试数据如果需要在本地复现或扩展验证可以直接利用目录下的 zip 资源Trino 测试框架会在运行时通过ResourceHudiTablesInitializer将 hudi-testing-data 下的 zip 解压到临时目录再按hudiComprehensiveTypesColumns()定义的数据列与分区列在 metastore 中注册 RO/RT 两张外部表存储格式分别为HUDI_PARQUET_INPUT_FORMAT与HUDI_PARQUET_REALTIME_INPUT_FORMAT。若想重新生成一份该形态的测试表则可把上文 DDL 与三行 INSERT、两条 UPDATE 按顺序在 Spark 中执行并保持文档中的会话参数设置不变。整套资源的生成脚本与校验代码互为印证构成了一条从造数到验数的完整闭环。赞分享数据湖湖仓一体大数据数据存储【免费下载链接】hudiUpserts, Deletes And Incremental Processing on Big Data.项目地址https://gitcode.com/gh_mirrors/hud/hudi点击查看免费下载相关推荐Apache Hudi MOR 表全面类型写入与 Trino 读取验证实战指南Apache Hudi MOR 表全面类型写入与 Trino 读取验证实战指南 导读 本文围绕 hudi trino/src/test/resources/hu数据湖湖仓一体大数据数据存储Hudi CustomKeyGenerator 实战用 Spark SQL 构建多类型混合分区键的 MOR 表附 Trino 连接器测试数据解析Hudi CustomKeyGenerator 实战用 Spark SQL 构建多类型混合分区键的 MOR 表附 Trino 连接器测试数据解析 Hudi数据湖湖仓一体大数据数据存储Hudi 多分区字段 MOR 表的 Spark SQL 建表与 Trino 分区裁剪实战基于 hudi-trino 测试数据集Hudi 多分区字段 MOR 表的 Spark SQL 建表与 Trino 分区裁剪实战基于 hudi trino 测试数据集 导读 本文以 Apache数据湖湖仓一体大数据数据存储上一篇PX4 飞控板卡指南ARKV6X-RTNXP i.MX RT1176特性、接口映射与固件构建下一篇从数字溢出到性能优化Hutool Base62编码对大数字处理差异的深度解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考