ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Hudi 复合记录键与大写字段名 COW 表构建与验证指南:Trino 连接器记录级索引剪枝实战

Hudi 复合记录键与大写字段名 COW 表构建与验证指南:Trino 连接器记录级索引剪枝实战 数据湖湖仓一体大数据数据存储【免费下载链接】hudiUpserts, Deletes And Incremental Processing on Big Data.项目地址https://gitcode.com/gh_mirrors/hud/hudi点击查看免费下载导读本文以 hudi-trino 测试数据集中的生成脚本为核心讲解如何用 Apache Spark 创建一张同时具备多字段复合记录键Composite Record Key与大写字段名Field Names in Caps的 Hudi COPY_ON_WRITE 表并说明该表如何在 Trino Hudi 连接器中用于验证记录级索引Record Level Index的文件剪枝能力。读完本文你将掌握复合键表的数据写入配置、MDTMetadata Table三类索引的启用方式以及从源码与测试用例层面理解 Trino 对复合键谓词的下推剪枝原理。一、这个脚本在仓库中的定位该脚本文件位于 hudi-trino/src/test/resources/hudi-testing-data/hudi_cow_table_with_multi_keys_and_field_names_in_caps.md与之配套的同名.zip归档则存放了脚本运行后产出的完整表实例数据文件 .hoodie元数据。它属于 hudi-trino 模块测试基础设施的一部分测试运行时ResourceHudiTablesInitializer 会解压hudi-testing-data目录下的全部归档注册为枚举 TestingTable.HUDI_COW_TABLE_WITH_MULTI_KEYS_AND_FIELD_NAMES_IN_CAPS再通过 Hive 元数据创建外部表供 SQL 查询使用。该表刻意组合了三个对引擎实现有挑战性的特征特征说明对查询引擎的挑战COW 表类型Copy-on-Write无日志文件读取路径简单便于聚焦索引剪枝本身复合记录键hoodie.table.recordkey.fields Id,Age记录级索引需基于多列构造复合键才能命中大写字段名Id/Name/AgeTrino catalog 通常返回小写列名涉及大小写解析resolve column name casing二、生成脚本逐行解析原文档给出的是完整的 Spark Scala 脚本结构说明仅两行COW 表、多 record key、字段名含大写、无日志文件。脚本整体分三步定义 Schema、构造 DataFrame、写入 Hudi。2.1 定义带大写字段的 Schemaimport org.apache.spark.sql.types._ import org.apache.spark.sql.Row val schema StructType(Seq( StructField(Id, StringType, nullable false), StructField(Name, StringType, nullable true), StructField(Age, IntegerType, nullable true) ))三个字段中Id与Age共同构成复合记录键因此Id被声明为nullable false记录键字段不允许为空Age同时是键的一部分且为IntegerType说明 Hudi 复合键既支持字符串字段也支持数值字段Name是可空字符串后续被指定为二级键secondary key。2.2 构造测试数据val data Seq( Row(1, Alice, 30), Row(2, Bob, 25) ) val df spark.createDataFrame( spark.sparkContext.parallelize(data), schema ) df.show()数据只有两条记录(1,Alice,30)与(2,Bob,25)。规模刻意保持极小——测试的目标是验证「只有 1 条记录被命中时剪枝后也只剩 1 个 split」这一剪枝行为而不是数据吞吐。写入后归档中的两个 Parquet 文件组37dec8f9-5768-4c74-92f3-2bdf16862566-0_5-490-0_...parquet与521f28ea-d7d4-41ec-918d-81eb5efee48c-0_11-496-0_...parquet恰好与两条记录一一对应为「全表 2 个 split、条件查询 1 个 split」的断言提供了物理基础。2.3 Hudi 写入配置var basePath file:///tmp/hudi_cow_table_with_multi_keys_and_field_names_in_caps/ df.write.format(hudi).mode(Append) .option(hoodie.table.name, hudi_cow_table_with_multi_keys_and_field_names_in_caps) .option(hoodie.datasource.write.table.type, COPY_ON_WRITE) .option(hoodie.datasource.write.recordkey.field,Id,Age) .option(hoodie.datasource.write.operation,bulk_insert) .option(hoodie.metadata.index.column.stats.enable, true) .option(hoodie.metadata.record.index.enable, true) .option(hoodie.datasource.write.secondarykey.column, Name) .save(basePath)各选项含义与效果如下选项值作用与注意事项hoodie.table.namehudi_cow_table_with_multi_keys_and_field_names_in_caps表名同时写入hoodie.properties并作为路径目录名hoodie.datasource.write.table.typeCOPY_ON_WRITECOW 表写入时合并数据并重写 Parquet 文件不产生日志文件hoodie.datasource.write.recordkey.fieldId,Age逗号分隔声明复合记录键。写入后固化在表配置hoodie.table.recordkey.fieldsId,Age中是 RLI 构造记录键的依据hoodie.datasource.write.operationbulk_insert批量插入不做定位去重、性能最好适合初始化测试表配合 Append 模式追加数据hoodie.metadata.index.column.stats.enabletrue在 MDT 中构建column_stats索引分区支持基于列统计的谓词剪枝hoodie.metadata.record.index.enabletrue在 MDT 中构建record_index索引分区支持按记录键精确定位文件hoodie.datasource.write.secondarykey.columnName声明二级键字段供二级索引secondary index使用hoodie.datasource.write.partitionpath.field未设置非分区表最终hoodie.table.partition.fields为空keygenerator 为NON_PARTITION三、写入产物zip 归档内部的真实表结构解压同名.ziphudi_cow_table_with_multi_keys_and_field_names_in_caps.zip可以看到脚本执行后的完整物理布局hudi_cow_table_with_multi_keys_and_field_names_in_caps/ ├── 37dec8f9-5768-4c74-92f3-2bdf16862566-0_5-490-0_20250812192305941.parquet # 数据文件组 1 ├── 521f28ea-d7d4-41ec-918d-81eb5efee48c-0_11-496-0_20250812192305941.parquet # 数据文件组 2 ├── .hoodie/ │ ├── hoodie.properties # 表配置版本 8 │ ├── timeline/ # 1 个 commit instant20250812192305941 │ ├── .index_defs/index.json # 索引定义 │ └── metadata/ │ ├── column_stats/ # column_stats 索引分区col-stats-*.log │ ├── record_index/ # record_index 索引分区record-index-*.log │ └── files/ # files 索引分区hfile log └── .hoodie_partition_metadatahoodie.properties中的关键配置节选印证了脚本参数全部落盘生效hoodie.table.namehudi_cow_table_with_multi_keys_and_field_names_in_caps hoodie.table.typeCOPY_ON_WRITE hoodie.table.recordkey.fieldsId,Age hoodie.table.partition.fields hoodie.table.keygenerator.typeNON_PARTITION hoodie.table.metadata.partitionscolumn_stats,files,record_index hoodie.table.version8 hoodie.table.base.file.formatPARQUET hoodie.populate.meta.fieldstrue hoodie.record.merge.modeCOMMIT_TIME_ORDERING而.hoodie/.index_defs/index.json则记录了column_stats索引覆盖的字段集合注意它同时包含 Hudi 元数据字段与全部数据列{ indexDefinitions : { column_stats : { indexName : column_stats, indexType : column_stats, indexFunction : column_stats, sourceFields : [ _hoodie_commit_time, _hoodie_partition_path, _hoodie_record_key, Id, Name, Age ], indexOptions : { } } } }四、Trino 侧的复合键剪枝原理源码级4.1 复合记录键的编码与构造Trino Hudi 连接器执行记录级索引剪枝的核心实现在 HudiRecordLevelIndexSupport常量定义第 59-60 行DEFAULT_COLUMN_VALUE_SEPARATOR :列值与列名的连接符、DEFAULT_RECORD_KEY_PARTS_SEPARATOR ,复合键各部分之间的分隔符这与写入端 record key 编码保持一致canApply第 148-173 行要求所有 record key 字段都必须出现在查询谓词中且谓词类型只能是 EQUAL 或 IN否则放弃 RLI 剪枝回退全量扫描constructRecordKeys第 238-294 行对单键直接取值对复合键则对每个键字段的值做笛卡尔积拼接例如Id1与Age30会组合成id:1,age:30。源码注释明确提醒该函数复杂度为O(m^n)m 为每个键字段的字面量数量n 为键字段数这也是 RLI 只接受 EQUAL/IN 而非范围谓词的原因——范围谓词无法枚举出有限数量的完整复合键。4.2 二级键与列统计索引二级键由 HudiSecondaryIndexSupport 处理通过readSecondaryIndexLocationsWithKeys(..., indexName)按二级键值反查记录位置列统计索引column_stats则服务于普通列上的范围/等值谓词剪枝本表中Age30这类谓词同样可以借助列统计直接跳过不可能包含该值的文件组。4.3 大小写字段名的处理测试基础设施在 ResourceHudiTablesInitializer 中有明确注释表 Schema 的列名是大写的但 Trino catalog 返回小写列名因此注册元数据时统一使用小写id/name/age。也就是说SQL 查询写WHERE id1 and age30而表配置里 record key 字段仍是大写的Id,Age二者需要依赖连接器的大小写解析能力会话属性resolveColumnNameCasing对齐。五、端到端验证测试用例剖析仓库中的 TestHudiSmokeTest.testMultiKeyRLIWithColumnNameUsingUppercaseLetters 正是围绕这张表设计的端到端验证Session session SessionBuilder.from(getSession()) .withMdtEnabled(true) // 启用 Metadata Table .withColStatsIndexEnabled(false) // 关闭列统计索引隔离变量 .withRecordLevelIndexEnabled(true) // 启用记录级索引 .withRecordIndexTimeout(10s) .withSecondaryIndexEnabled(false) .withPartitionStatsIndexEnabled(false) .withResolveColumnNameCasingEnabled(true) // 允许大小写解析 .build();测试逻辑全表扫描SELECT * FROM hudi_cow_table_with_multi_keys_and_field_names_in_caps→ 断言totalSplits 2、totalRows 2两个文件组各一条记录带复合键谓词查询SELECT * FROM ... WHERE id1 and age30→ 断言prunedSplits 1、prunedRows 1核心断言assertThat(prunedSplits).isLessThan(totalSplits)且精确到1证明 RLI 对复合键的剪枝精确命中了唯一包含id1、age30的文件组未发生误剪或漏剪。值得注意的是测试关闭了 column stats 与 secondary index确保Age参与剪枝是经由复合记录键的完整构造id:1,age:30完成的而非列统计兜底——这正是复合键 RLI 路径的独立验证价值。六、实战要点速查关注点结论复合键声明写入时用逗号分隔hoodie.datasource.write.recordkey.fieldId,Age写入后固化于hoodie.table.recordkey.fields键字段约束键字段不可为 null类型可混合字符串 数值均可RLI 生效前提查询谓词须覆盖全部键字段且只允许/IN否则回退全量扫描大小写场景Trino catalog 列名小写化与表配置中的大写键字段靠resolveColumnNameCasing对齐剪枝效果复合键条件下可从 2 个 split 精确剪枝到 1 个 split仓库测试断言归档复用.zip可直接作为 hudi-trino 集成测试输入无需重新运行 Spark 写入七、总结hudi_cow_table_with_multi_keys_and_field_names_in_caps生成脚本虽然只有一段 Spark 写入代码却集中覆盖了 Hudi 元数据索引体系中最具组合难度的三个场景复合记录键的编码、大写字段名的跨引擎映射、MDT 多索引协同。通过配套归档与 TestHudiSmokeTest 中的断言读者既可以把它当作 Trino Hudi 连接器索引能力的对照实验样本也可以直接仿照该脚本在自己的 Spark 环境里构造同构测试表复现从「全表 2 split」到「命中 1 split」的剪枝行为。赞分享数据湖湖仓一体大数据数据存储【免费下载链接】hudiUpserts, Deletes And Incremental Processing on Big Data.项目地址https://gitcode.com/gh_mirrors/hud/hudi点击查看免费下载相关推荐Apache Hudi Trino 连接器实践创建含大写字段名的 MOR 表测试数据验证列名大小写感知查询与索引剪枝Apache Hudi Trino 连接器实践创建含大写字段名的 MOR 表测试数据验证列名大小写感知查询与索引剪枝 导读 本文围绕 Hudi 仓库中 Tr数据湖湖仓一体大数据数据存储Trino 查询大写字段名 Hudi COW 表字段大小写兼容与索引文件跳过的完整实践Trino 查询大写字段名 Hudi COW 表字段大小写兼容与索引文件跳过的完整实践 本文聚焦 Apache Hudi Trino Connector h数据湖湖仓一体大数据数据存储Hudi 字段名含大写字母的 COW 分区表Spark 建表脚本与 Trino 大小写列名兼容实践Hudi 字段名含大写字母的 COW 分区表Spark 建表脚本与 Trino 大小写列名兼容实践 导读 本篇文章围绕 Hudi 官方测试数据生成脚本 hud数据湖湖仓一体大数据数据存储上一篇如何快速解决electerm终端字体模糊问题3个高效配置方案下一篇FastAPI部署10个自动扩展技巧提升API性能创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表