Gravitino iceberg catalog backend 为hive 获取元数据过程

Gravitino iceberg catalog backend 为hive 获取元数据过程

Iceberg Catalog (Hive Backend) 元数据获取流程

概述

当 Iceberg Catalog Backend 配置为 Hive 时,Gravitino 通过Hive Metastore (HMS)Iceberg 文件系统元数据两部分协同工作来获取完整的库、表、字段等元数据信息。


1. 元数据来源架构

元数据类型 存储位置 用途
Hive Metastore HMS 数据库 存储表的名称、位置、类型标识table\_type=ICEBERG
Iceberg 元数据文件 文件系统(HDFS/S3/OSS 等) 存储完整的 Schema、分区、排序、快照等详细信息

2. 获取 Schemas (Namespaces) 流程

调用链路

Plain 复制代码
IcebergNamespaceOperations.listNamespaces()
    ↓
IcebergNamespaceOperationExecutor.listNamespaces()
    ↓
IcebergCatalogWrapper.listNamespace()
    ↓
CatalogHandlers.listNamespaces(asNamespaceCatalog, parent)
    ↓
GrHiveCatalog.listNamespaces(namespace)  ← 实际执行

核心代码 (GrHiveCatalog.java:476-501)

Java 复制代码
@Override
public List<Namespace> listNamespaces(Namespace namespace) {
    if (!isValidateNamespace(namespace) && !namespace.isEmpty()) {
        throw new NoSuchNamespaceException("Namespace does not exist: %s", namespace);
    }
    if (!namespace.isEmpty()) {
        return ImmutableList.of();  // Hive 不支持嵌套 namespace
    }
    try {
        // 调用 Hive Metastore Thrift 客户端获取所有数据库
        List<Namespace> namespaces =
            clients.run(IMetaStoreClient::getAllDatabases).stream()
                .map(Namespace::of)
                .collect(Collectors.toList());
        ...
    }
}

关键点

  • 调用 Hive Metastore 的 getAllDatabases\(\) Thrift 接口

  • Hive 只支持单层 namespace(database),不支持多级

  • 使用 CachedClientPool 管理 HMS 客户端连接池


3. 获取 Tables 流程

调用链路

Plain 复制代码
IcebergTableOperations.listTable()
    ↓
IcebergTableOperationExecutor.listTable()
    ↓
IcebergCatalogWrapper.listTable()
    ↓
CatalogHandlers.listTables(catalog, namespace)
    ↓
GrHiveCatalog.listTables(namespace)  ← 实际执行

核心代码 (GrHiveCatalog.java:142-178)

Java 复制代码
@Override
public List<TableIdentifier> listTables(Namespace namespace) {
    Preconditions.checkArgument(
        isValidateNamespace(namespace), "Missing database in namespace: %s", namespace);
    String database = namespace.level(0);

    try {
        // 1. 调用 Hive Metastore 获取所有表名
        List<String> tableNames = clients.run(client -> client.getAllTables(database));
        List<TableIdentifier> tableIdentifiers;

        if (listAllTables) {
            // 2a. 如果配置为列出所有表,直接返回
            tableIdentifiers = tableNames.stream()
                .map(t -> TableIdentifier.of(namespace, t))
                .collect(Collectors.toList());
        } else {
            // 2b. 否则只过滤出 Iceberg 表
            tableIdentifiers = listIcebergTables(
                tableNames, namespace, BaseMetastoreTableOperations.ICEBERG_TABLE_TYPE_VALUE);
        }
        ...
    }
}

过滤 Iceberg 表的逻辑 (GrHiveCatalog.java:342-356)

Java 复制代码
private List<TableIdentifier> listIcebergTables(
    List<String> tableNames, Namespace namespace, String tableTypeProp)
    throws TException, InterruptedException {
    // 1. 批量获取表对象(避免 OOM)
    List<Table> tableObjects =
        clients.run(client -> client.getTableObjectsByName(namespace.level(0), tableNames));
    
    // 2. 过滤出 Iceberg 表(通过表参数中的 table_type 标识)
    return tableObjects.stream()
        .filter(table ->
            table.getParameters() != null
                && (tableTypeProp.equalsIgnoreCase(
                        table.getParameters().get(BaseMetastoreTableOperations.TABLE_TYPE_PROP))
                    || TableType.VIRTUAL_VIEW.name().equalsIgnoreCase(table.getTableType())))
        .map(table -> TableIdentifier.of(namespace, table.getTableName()))
        .collect(Collectors.toList());
}

关键点

  • 调用 Hive Metastore 的 getAllTables\(database\) 获取表名列表

  • 调用 getTableObjectsByName\(\) 批量获取表详情(避免逐表查询的性能问题)

  • 通过表参数 table\_type=ICEBERG 过滤出 Iceberg 管理的表

  • 配置项 list\-all\-tables=true 可跳过过滤,返回所有 Hive 表


4. 加载完整表元数据 (从 Iceberg 元数据文件)

调用链路

Plain 复制代码
IcebergCatalogOperations.loadTable()
    ↓
icebergCatalogWrapper.loadTable(tableIdentifier)
    ↓
CatalogHandlers.loadTable(catalog, tableIdentifier)
    ↓
GrHiveCatalog.loadTable(tableIdentifier)
    ↓
HiveTableOperations.current() → 读取文件系统 metadata.json

核心代码 (IcebergCatalogOperations.java:386-400)

Java 复制代码
@Override
public Table loadTable(NameIdentifier tableIdent) throws NoSuchTableException {
    try {
        LoadTableResponse tableResponse =
            icebergCatalogWrapper.loadTable(
                IcebergCatalogWrapperHelper.buildIcebergTableIdentifier(tableIdent));
        
        // 从 Iceberg TableMetadata 解析完整元数据
        IcebergTable icebergTable =
            IcebergTable.fromIcebergTable(tableResponse.tableMetadata(), tableIdent.name());

        LOG.info("Loaded Iceberg table {}", tableIdent.name());
        return icebergTable;
    } catch (org.apache.iceberg.exceptions.NoSuchTableException e) {
        throw new NoSuchTableException(e, ICEBERG_TABLE_DOES_NOT_EXIST_MSG, tableIdent.name());
    }
}

从 Iceberg 元数据转换 (IcebergTable.java:157-181)

Java 复制代码
public static IcebergTable fromIcebergTable(TableMetadata table, String tableName) {
    // 1. 属性 - 从 Iceberg 元数据文件读取
    Map<String, String> properties = new HashMap<>(table.properties());
    properties.putAll(IcebergTablePropertiesUtil.buildReservedProperties(table));
    
    // 2. Schema/字段信息 - 从 Iceberg 元数据文件读取
    Schema schema = table.schema();
    IcebergColumn[] icebergcolumns =
        schema.columns().stream().map(ConvertUtil::fromNestedField).toArray(IcebergColumn[]::new);
    
    // 3. 分区信息 - 从 Iceberg 元数据文件读取
    Transform[] partitionSpec = FromIcebergPartitionSpec.fromPartitionSpec(table.spec(), schema);
    
    // 4. 排序信息 - 从 Iceberg 元数据文件读取
    SortOrder[] sortOrder = FromIcebergSortOrder.fromSortOrder(table.sortOrder());
    
    // 5. 位置信息 - 从 Iceberg 元数据文件读取
    String location = table.location();
    
    // 6. 构建完整的 Gravitino Table 对象
    return IcebergTable.builder()
        .withComment(table.property(IcebergTablePropertiesMetadata.COMMENT, null))
        .withLocation(table.location())
        .withProperties(properties)
        .withColumns(icebergColumns)
        .withName(tableName)
        .withAuditInfo(AuditInfo.EMPTY)
        .withPartitioning(partitionSpec)
        .withSortOrders(sortOrder)
        .withDistribution(getDistribution(properties))
        .withIndexes(indexes)
        .build();
}

5. 数据流总结

Plain 复制代码
┌─────────────────────────────────────────────────────────────────┐
│                    Gravitino Iceberg Catalog                     │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  listTables(namespace)                                          │
│    ↓                                                            │
│  1. Hive Metastore (HMS)                                        │
│     - getAllTables(database) → 表名列表                          │
│     - getTableObjectsByName() → 表对象(含 table_type 参数)      │
│     - 过滤出 table_type=ICEBERG 的表                              │
│    ↓                                                            │
│  2. 文件系统上的 Iceberg 元数据文件                                  │
│     - loadTable(tableIdentifier)                                │
│     - 读取 metadata.json 文件                                    │
│     - 解析:Schema、分区、排序、属性、位置等                       │
│    ↓                                                            │
│  3. fromIcebergTable(TableMetadata)                             │
│     - 将 Iceberg 元数据转换为 Gravitino 格式                        │
│     - 返回完整的 Table 对象(含字段、分区等详细信息)               │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

6. 配置参数

参数 默认值 说明
hive\.metastore\.uris - Hive Metastore Thrift 服务地址
hive\.metastore\.warehouse\.dir - 数据仓库根目录
list\-all\-tables false 是否列出所有表(包括非 Iceberg 表)
iceberg\.catalog\.client\.pool\.size - HMS 客户端连接池大小

7. 关键结论

Gravitino 的 Iceberg Catalog(Hive Backend)严重依赖 Iceberg 在文件系统上维护的元数据文件来提供完整的表信息:

  1. HMS 只存储&#34;表的存在性&#34;和&#34;类型标识&#34; - 用于快速列出哪些表是 Iceberg 表

  2. Iceberg 元数据文件存储完整 Schema - 字段名、类型、注释、nullable、分区、排序、快照历史等

  3. 每次 loadTable 都会读取文件系统元数据 - 确保获取最新信息

这种设计的好处是:

  • Iceberg 元数据是单一事实来源(Single Source of Truth)

  • HMS 只作为&#34;目录索引&#34;,不存储详细元数据

  • 支持 Iceberg 的 ACID 快照隔离和时间旅行特性

(注:文档内容基于gravitino 0.9版本源码由 AI整理生成)

相关推荐
段一凡-华北理工大学1 小时前
工业领域的Hadoop架构学习~系列文章06:Hive数据仓库
数据仓库·hadoop·架构·高炉炼铁·工业智能体·高炉智能化·hive数据仓库
zgl_2005377916 小时前
源代码:跨数据库通用SQL语法解析与标注拆解
大数据·数据库·数据仓库·sql·etl·源代码管理
暴躁小师兄数据学院17 小时前
【AI大数据工程师特训笔记】第13讲:数据库性能手术刀
大数据·数据库·数据仓库·sql·postgresql
段一凡-华北理工大学1 天前
工业领域的Hadoop架构学习~系列文章04:YARN资源调度架构
人工智能·hadoop·学习·架构·系统架构·高炉炼铁·高炉炼铁智能化
卷毛迷你猪1 天前
快速实验篇(A2-2)数据清洗规则修正与多语言实现验证
hadoop·分布式
段一凡-华北理工大学1 天前
工业领域的Hadoop架构学习~系列文章05:Kafka消息队列 - 工业数据流传输
人工智能·hadoop·学习·架构·kafka·工业智能体·高炉炼铁智能化
qiuyepiaoling2 天前
数仓设计基础
数据仓库
兔子宇航员03012 天前
HIVE SQL 中 NULL 值在 JOIN 和 GROUP BY 中的致命陷阱与解决方案
hive·hadoop·sql
段一凡-华北理工大学2 天前
工业领域的Hadoop架构学习~系列文章02:HDFS架构深度剖析
大数据·人工智能·hadoop·学习·架构·高炉炼铁