Hudi 多 FileGroup 分区 MOR 测试表构建指南:MDT、记录级索引与列统计索引全量启用的实战脚本 数据湖湖仓一体大数据数据存储【免费下载链接】hudiUpserts, Deletes And Incremental Processing on Big Data.项目地址https://gitcode.com/gh_mirrors/hud/hudi点击查看免费下载导读本文围绕 Hudi 仓库中 Trino 连接器测试数据集hudi_multi_fg_pt_v8_mor的构建文档展开完整讲解如何用 Spark SQL 生成一张多分区 × 多 FileGroup × 带日志文件 × 全量元数据索引的 MOR 表并剖析其中每个配置项对底层文件布局与索引的影响。读完本文你将掌握一张可同时覆盖 Trino/Hudi 集成测试中 FileGroup、Log 文件、列统计索引、分区统计索引、记录级索引与二级索引六大场景的测试表的标准构建方法并能独立复刻出同类测试数据。数据集文档的定位为 Trino 连接器测试而生的表规格说明书在 Hudi 仓库中hudi-trino/src/test/resources/hudi-testing-data/目录下的 Markdown 文件并不是普通的使用手册而是每一份测试数据的构建脚本 结构规格说明。它们与同名.zip包一一对应.zip中是已经生成好的真实 Hudi 表文件.md则记录了生成这些数据所用的 Spark SQL 脚本和表结构约定。hudi_multi_fg_pt_v8_mor.md就是其中的典型代表它描述了一张名为hudi_multi_fg_pt_v8_mor的测试表这是一张MORMerge On Read表且MDTMetadata Table元数据表已启用生成该数据集的 Hudi 版本修订号为eb212c9dca876824b6c570665951777a772bc463Record Level Index记录级索引已启用recordKey 为id,name复合主键在price列上创建了二级索引共2 个分区[US, SG]每个分区2 个 FileGroup。从文件命名可以推断这是对应测试数据的v8 版本_v8_且在同一目录下存在同名的 v6 版本文档hudi_multi_fg_pt_v6_mor.md其 Revision 标注为release-0.15.0。对照两份文档可以看到v8 版本在 v6 的基础上新增了二级索引secondary index的创建步骤这正对应了 Hudi 在 MDT 中对二级索引能力的持续演进。表的最终结构一览根据文档开头列出的结构清单这张表在写入完成后呈现如下形态维度规格表类型MORMerge On ReadMDT启用Metadata Table主键recordKeyid, name复合主键记录级索引启用二级索引在price列上创建索引名idx_price分区2 个US、SG分区列为country每个分区的 FileGroup2 个Log 文件存在由 UPDATE 产生数据列共 5 个id int、name string、price double、ts long、country string其中country同时充当分区列。在 Trino 测试侧这张表被注册在ResourceHudiTablesInitializer.java的TestingTable枚举中条目为HUDI_MULTI_FG_PT_V8_MOR(hudiMultiFgRegularColumns(), hudiMultiFgPartitionsColumn(), hudiMultiFgPartitions(), false)其列定义hudiMultiFgRegularColumns()与分区定义hudiMultiFgPartitions()在源码中均有明确对应private static ListColumn hudiMultiFgRegularColumns() { return ImmutableList.of( column(id, HIVE_INT), column(name, HIVE_STRING), column(price, HIVE_DOUBLE), column(ts, HIVE_LONG)); } private static MapString, String hudiMultiFgPartitions() { return ImmutableMap.of( countrySG, countrySG, countryUS, countryUS); }从该枚举的isCreateRtTable false可知这张表在 Trino 测试中只注册 RO 表即只读表直接读取 base 文件加日志合并后的结果不额外创建带_rt后缀的实时表视图。这些信息印证了.md文档与测试代码之间严格的一致性——文档即规格代码即实现。完整构建脚本详解文档给出了从零构建这张表的完整 Scala/Spark SQL 脚本。下面保留脚本全文并逐段说明其作用。test(Create table multi filegroup partitioned mor) { withTempDir { tmp val tableName hudi_multi_fg_pt_mor spark.sql( s |create table $tableName ( | id int, | name string, | price double, | ts long, | country string |) using hudi | location ${tmp.getCanonicalPath} | tblproperties ( | primaryKey id,name, | type mor, | preCombineField ts | ) partitioned by (country) .stripMargin) // directly write to new parquet file spark.sql(sset hoodie.parquet.small.file.limit0) spark.sql(sset hoodie.metadata.compact.max.delta.commits1) // partition stats index is enabled together with column stats index spark.sql(sset hoodie.metadata.index.column.stats.enabletrue) spark.sql(sset hoodie.metadata.record.index.enabletrue) spark.sql(sset hoodie.metadata.index.secondary.enabletrue) spark.sql(sset hoodie.metadata.index.column.stats.column.list_hoodie_commit_time,_hoodie_partition_path,_hoodie_record_key,id,name,price,ts,country) // 2 filegroups per partition spark.sql(sinsert into $tableName values(1, a1, 100, 1000, SG),(2, a2, 200, 1000, US)) spark.sql(sinsert into $tableName values(3, a3, 101, 1001, SG),(4, a3, 201, 1001, US)) // create secondary index spark.sql(screate index idx_price on $tableName (price)) // generate logs through updates spark.sql(supdate $tableName set priceprice1) } }第一步建表 DDL建表语句通过using hudi指定数据源为 Huditblproperties中声明了三个核心表属性primaryKey id,name复合主键。两个字段共同构成 recordKey写入时用于去重与更新定位也是记录级索引的键基础type mor表类型为 Merge On Read。基础文件按列式 Parquet 存储后续更新先追加到基于行的 Log 文件读取时再做合并preCombineField ts预合并字段。当同一 recordKey 出现多条记录时以ts值较大者为准保证最终一致性。分区列为country因此表目录下会形成countryUS/、countrySG/两个分区目录。第二步关键写入配置逐个解析脚本中连续设置了 6 个 Spark 会话级 Hudi 配置每个配置都对最终的文件布局与元数据索引产生直接影响hoodie.parquet.small.file.limit0将小文件合并阈值设为 0即关闭小文件合并行为。每次 commit 都会直接写入新的 Parquet 文件而不是填充到已有文件这是保证每个分区出现 2 个 FileGroup的关键——两次 INSERT 各自生成独立的 base 文件形成 2 个 FileGroup。hoodie.metadata.compact.max.delta.commits1控制 MDT 的 compaction 触发频率每当 MDT 侧累积的 delta commit 达到 1 个即触发元数据表压缩。将阈值调小可以让元数据表在测试数据量很小的情况下也能形成压缩后的形态确保测试能覆盖 MDT 压缩路径。hoodie.metadata.index.column.stats.enabletrue启用列统计索引Column Stats Index。该索引在 MDT 的column_stats分区中按列记录每个 FileSlice 的 min/max 等统计信息供查询引擎做分区/文件裁剪。文档注释特别说明分区统计索引partition stats index会随列统计索引一起启用这是二者在实现上的联动关系。hoodie.metadata.record.index.enabletrue启用记录级索引Record Level IndexRLI。该索引提供 recordKey → FileGroup/FileSlice 的全局定位能力是 Hudi 在 MOR 表上高效执行点查与更新定位的关键设施。hoodie.metadata.index.secondary.enabletrue启用二级索引Secondary Index。v8 版本相比 v6 版本的新增配置配合后续的create index idx_price on $tableName (price)语句在price列上建立二级索引使得以price为过滤条件的查询可以直接借由 MDT 中二级索引分区快速定位目标记录。hoodie.metadata.index.column.stats.column.list...显式指定列统计索引要覆盖的列清单_hoodie_commit_time, _hoodie_partition_path, _hoodie_record_key, id, name, price, ts, country。清单同时包含 5 个 Hudi 元数据列与全部 5 个业务列意味着这张表的列统计索引是全列覆盖的任何列的裁剪过滤都能命中统计信息。这些配置项在源码层面均有对应定义。在 HoodieMetadataConfig.java 中可以看到SECONDARY_INDEX_ENABLE_PROP、SECONDARY_INDEX_PARALLELISM、SECONDARY_INDEX_NAME、SECONDARY_INDEX_COLUMN等二级索引相关属性的定义而 TestHoodieMetadataConfig.java 中的测试用例也直接以hoodie.metadata.record.index.enabletrue作为输入属性验证配置解析逻辑证明这些配置键在 Hudi 通用配置层是稳定、可解析的。第三步两次 INSERT 制造多 FileGroupinsert into hudi_multi_fg_pt_mor values(1, a1, 100, 1000, SG),(2, a2, 200, 1000, US) insert into hudi_multi_fg_pt_mor values(3, a3, 101, 1001, SG),(4, a3, 201, 1001, US)两条 INSERT 各写一次 commit。由于hoodie.parquet.small.file.limit0关闭了小文件合并每次 commit 都会为每个分区生成新的 base 文件US分区第一条插入记录(2, a2)第二条插入(4, a3)形成 2 个 FileGroupSG分区第一条插入(1, a1)第二条插入(3, a3)同样形成 2 个 FileGroup。注意第二条插入中出现了两条namea3的记录id3在SG、id4在US由于 recordKey 是id,name复合键这两条记录的 key 并不相同因此它们被正常写入各自的文件组不会被互相覆盖。第四步创建二级索引create index idx_price on hudi_multi_fg_pt_mor (price)在price列上创建名为idx_price的二级索引。Hudi 会在 MDT 中为每个二级索引创建一个独立的索引分区源码中对应PARTITION_NAME_SECONDARY_INDEX_PREFIX前缀的元数据分区索引数据随后续写入增量维护。第五步UPDATE 生成 Log 文件update hudi_multi_fg_pt_mor set priceprice1这是一条全表更新。对 MOR 表而言UPDATE 不会直接改写已有的 Parquet base 文件而是把更新后的记录追加写入对应的Log 文件.log这正是文档生成 logs注释的含义。更新完成后每个 FileGroup 下形成base 文件 log 文件的文件切片结构Trino 在查询该表时需要完成 base 与 log 的实时合并MOR 的 Read Optimized 语义之外的核心读取路径。这张表在 Trino 测试中的消费方式.md文档定义了数据规格而 Trino 连接器通过测试代码真正消费这些数据。可以从几个侧面看到它们的衔接测试数据装配链路。ResourceHudiTablesInitializer.java的initializeTables方法会把hudi-testing-data资源目录下的.zip解压到临时目录将解压出的 Hudi 表完整拷贝到 Trino 文件系统拷贝过程会计算 SHA-256 哈希校验完整性且跳过.crc校验文件通过HudiConnector注入的TrinoFileSystemFactory与HiveMetastoreFactory为每张测试表在 metastore 中注册外部表及分区RO 存储格式使用HUDI_PARQUET_INPUT_FORMATRT 格式使用HUDI_PARQUET_REALTIME_INPUT_FORMAT读取HoodieTableMetaClient获取表版本并回填到TestingTable枚举。索引能力在连接器侧的开关。HudiConfig.java 中默认开启isSecondaryIndexEnabled与isColumnStatsIndexEnabled并定义了hudi.index.secondary-index-enabled、hudi.index.column-stats-index-enabled、hudi.index.column-stats.wait-timeout、hudi.index.record-index.wait-timeout、hudi.index.secondary-index.wait-timeout等内部配置默认等待超时 2 秒说明 Trino 侧在读取 Hudi 表时确实会加载并使用这些 MDT 索引。文档中这张表全量开启 MDT 索引正是为了让这些读取路径在测试中被完整覆盖。MDT 列统计数据的实际访问证据。在InlineSeekableDataInputStream.java的注释中保留了真实测试运行时的路径痕迹inlinefs://.../hudi_multi_fg_pt_v8_mor/.hoodie/metadata/column_stats/这直接证明 Trino 连接器在测试中确实访问了该表的 MDTcolumn_stats分区来读取列统计索引数据。什么场景下应该使用这张表文档在末尾明确列出了这张表的适用场景这是选择测试数据时的直接决策依据需要分区内存在多个 FileGroup 的测试用例两次 INSERT 配合关闭小文件合并使US、SG每个分区都有 2 个 FileGroup可用于验证多文件组场景下的文件裁剪、并行读取与合并逻辑需要 FileGroup 带 Log 文件的测试用例全表 UPDATE 产生 log 文件覆盖 MOR 表 base log 的合并读取路径需要列统计索引的测试用例全列含 5 个元数据列 5 个业务列启用了 column stats可验证基于列统计的文件级/块级裁剪需要分区统计索引的测试用例分区统计索引随列统计索引联动启用需要记录级索引的测试用例hoodie.metadata.record.index.enabletrue开启 RLIrecordKey 为id,name需要二级索引的测试用例price列上的idx_price二级索引可用于验证基于二级索引的查询加速路径。如何复刻你自己的同构测试表如果需要在本地复现或改造这张测试表可以按以下步骤操作在 Spark 环境需包含 Hudi Spark Bundle中将本文的 Scala 脚本中的tableName、location替换为你自己的命名与路径保持tblproperties的primaryKey、typemor、preCombineField三个核心属性不变MOR 复合主键是这张表结构的根基如需多 FileGroup形态务必设置hoodie.parquet.small.file.limit0并分多条 INSERT 写入每条 INSERT 产生一次 commit、每个分区新增一个 FileGroup如需带 Log 文件形态在 INSERT 之后追加 UPDATE 语句即可MOR 表的更新天然落入 log 文件按需开启hoodie.metadata.index.column.stats.enable、hoodie.metadata.record.index.enable、hoodie.metadata.index.secondary.enable三类索引并通过hoodie.metadata.index.column.stats.column.list控制列统计的覆盖范围生成完毕后将表目录归档为 zip 放入测试资源目录并在TestingTable枚举中注册对应的列与分区定义即可被 Trino 连接器测试框架加载。需要说明的是文档中给出的配置组合是为测试数据定制的例如hoodie.metadata.compact.max.delta.commits1会在每次增量后立即压缩元数据表在生产环境中这些参数应按实际数据规模重新评估不宜直接照搬。小结hudi_multi_fg_pt_v8_mor.md看似只是一份测试数据的构建脚本但它实际上浓缩了 Hudi 一张高端局MOR 表的全部关键要素复合主键、双分区、多 FileGroup、log 文件、MDT 下的列统计/分区统计/记录级/二级索引全量覆盖。理解这份文档既能帮助你读懂 Trino 连接器测试数据集的构造逻辑也能作为你在真实业务中组合配置 Hudi 元数据索引、控制文件布局的参考样板。赞分享数据湖湖仓一体大数据数据存储【免费下载链接】hudiUpserts, Deletes And Incremental Processing on Big Data.项目地址https://gitcode.com/gh_mirrors/hud/hudi点击查看免费下载相关推荐Hudi 多分区字段 MOR 表的 Spark SQL 建表与 Trino 分区裁剪实战基于 hudi-trino 测试数据集Hudi 多分区字段 MOR 表的 Spark SQL 建表与 Trino 分区裁剪实战基于 hudi trino 测试数据集 导读 本文以 Apache数据湖湖仓一体大数据数据存储DataHub Redshift 元数据采集实战指南从权限配置、Lineage 到 Usage 与 ProfilingDataHub Redshift 元数据采集实战指南从权限配置、Lineage 到 Usage 与 Profiling 导读 本文以 DataHub 官方 R数据湖湖仓一体大数据数据存储OceanBase表设计终极指南分区与索引优化实战OceanBase表设计终极指南分区与索引优化实战 你是否还在为海量数据查询缓慢而困扰作为企业级分布式关系型数据库OceanBase凭借高可用性、高性能和数据库分布式数据库关系型数据库后端高可用上一篇如何快速掌握CSON高效解析JSON数据的终极C语言库指南下一篇Wing语言监控与日志如何收集和分析云应用的运行数据创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考