当我使用“STORED AS AVRO”子句创建 Hive 表时,Avro 架构存储在哪里?

2024-03-09

至少有两种不同的方法来创建由 Avro 数据支持的 Hive 表:

  1. 基于 Avro 模式创建表(在本例中,存储在 hdfs 中):

    创建表 users_from_avro_schema 行格式 SERDE 'org.apache.hadoop.hive.serde2.avro.AvroSerDe' 存储为输入格式“org.apache.hadoop.hive.ql.io.avro.AvroContainerInputFormat” 输出格式 'org.apache.hadoop.hive.ql.io.avro.AvroContainerOutputFormat' TBLPROPERTIES('avro.schema.url'='hdfs:///user/root/avro/schema/user.avsc');

  2. 通过显式指定 hive 列来创建表STORED AS AVRO clause:

    创建表 users_stored_as_avro( id 整数, 名称 STRING ) 存储为 AVRO;

我是否正确,在第一种情况下的元数据users_from_avro_schema表不存储在 Hive Metastore 中,而是从读取 avro 模式文件的 SERDE 类推断出来?或者表元数据可能存储在 Metastore 中,在创建表时添加,但是将 hive 元数据与 Avro 模式同步的策略是什么?我的意思是两种情况:

  1. 更新表元数据(添加/删除列)和
  2. 通过更改更新 Avro 架构avro.schema.url财产。

在第二种情况下,当我打电话时DESCRIBE FORMATTED users_stored_as_avro没有avro.schema.*属性定义,所以我不知道哪个 Avro 模式用于读取/写入数据。它是根据存储在 Metastore 中的表元数据动态生成的吗?

This 《Programming Hive》一书讨论了从 SerDe 类推断有关列的信息,但另一方面HIVE-4703 https://issues.apache.org/jira/browse/HIVE-4703删除这个from deserializer信息表单列评论。如何检查给定表(Metastore 或 Avro 架构)的列类型的来源是什么?


我决定发布对@DuduMarkovitz 给出的答案的补充。

为了使代码示例更加简洁,让我们澄清一下STORED AS AVRO子句相当于以下三行:

ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.avro.AvroSerDe'
STORED AS INPUTFORMAT 'org.apache.hadoop.hive.ql.io.avro.AvroContainerInputFormat'
OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.avro.AvroContainerOutputFormat'

让我们看看当我们创建一个表来引用存储在 hdfs 中的 avro 模式时会发生什么。这是架构:

{
  "namespace": "io.sqooba",
  "name": "user",
  "type": "record",
  "fields": [
    {"name": "id", "type": "int"},
    {"name": "name", "type": "string"}
  ]
}

我们使用以下命令创建表:

CREATE TABLE users_from_avro_schema
STORED AS AVRO
TBLPROPERTIES ('avro.schema.url'='hdfs:///user/tulinski/user.avsc');

Hive 已正确推断模式,我们可以通过调用以下命令来查看:

hive> DESCRIBE users_from_avro_schema;
OK
id                      int
name                    string

Hive Metastore 向我们展示了相同的结果(我使用 @DuduMarkovitz 的查询):

+------------------------+-------------+-------------+-----------+
| tbl_name               | column_name | integer_idx | type_name |
+------------------------+-------------+-------------+-----------+
| users_from_avro_schema | id          |           0 | int       |
| users_from_avro_schema | name        |           1 | string    |
+------------------------+-------------+-------------+-----------+

到目前为止,一切都很好,一切都按我们的预期进行。 但让我们看看更新后会发生什么avro.schema.url属性指向我们架构的下一个版本(users_v2.avsc),如下所示:

{
  "namespace": "io.sqooba",
  "name": "user",
  "type": "record",
  "fields": [
    {"name": "id", "type": "int"},
    {"name": "name", "type": "string"},
    {"name": "email", "type": ["null", "string"], "default":null}
  ]
}

我们只是添加了另一个名为电子邮件的字段。
现在我们更新指向 hdfs 中 avro 模式的表属性:

ALTER TABLE users_from_avro_schema SET TBLPROPERTIES('avro.schema.url'='hdfs:///user/tulinski/user_v2.avsc');

表元数据是否已更改?

hive> DESCRIBE users_from_avro_schema;
OK
id                      int
name                    string
email                   string

是啊,酷!但是您是否期望 Hive Metastore 包含这个附加列?
不幸的是,Metastore 中没有任何变化:

+------------------------+-------------+-------------+-----------+
| tbl_name               | column_name | integer_idx | type_name |
+------------------------+-------------+-------------+-----------+
| users_from_avro_schema | id          |           0 | int       |
| users_from_avro_schema | name        |           1 | string    |
+------------------------+-------------+-------------+-----------+

我怀疑 Hive 有以下推断模式的策略:它尝试从为给定表指定的 SerDe 类获取它。当 SerDe 无法提供架构时,Hive 会查找元存储。
让我们通过删除来检查avro.schema.url财产:

hive> ALTER TABLE users_from_avro_schema UNSET TBLPROPERTIES ('avro.schema.url');
OK
Time taken: 0.33 seconds
hive> DESCRIBE users_from_avro_schema;
OK
id                      int
name                    string
Time taken: 0.363 seconds, Fetched: 2 row(s)

描述向我们展示存储在 Metastore 中的数据。让我们通过添加一列来修改它们:

ALTER TABLE users_from_avro_schema ADD COLUMNS (phone string);

它当然会改变 Hive Metastore:

+------------------------+-------------+-------------+-----------+
| tbl_name               | column_name | integer_idx | type_name |
+------------------------+-------------+-------------+-----------+
| users_from_avro_schema | id          |           0 | int       |
| users_from_avro_schema | name        |           1 | string    |
| users_from_avro_schema | phone       |           2 | string    |
+------------------------+-------------+-------------+-----------+

但是当我们设置avro.schema.url再次回到user_v2.avscHive Metastore 中的内容不再重要:

hive> ALTER TABLE users_from_avro_schema SET TBLPROPERTIES('avro.schema.url'='hdfs:///user/tulinski/user_v2.avsc');
OK
Time taken: 0.268 seconds
hive> DESCRIBE users_from_avro_schema;
OK
id                      int
name                    string
email                   string

Avro 架构优先于 Metastore。

上面的示例表明,我们应该避免将 Hive 模式更改与 avro 模式演变混合在一起,因为否则我们很容易陷入 Hive Metastore 与读写数据时使用的实际模式之间的混乱和不一致。当我们通过更新来更改 avro 架构定义时,就会出现第一个不一致的情况avro.schema.url属性,但如果我们了解 Hive 推断模式的策略,我们就可以接受这一点。我还没有检查 Hive 的源代码,我对模式逻辑的怀疑是否正确,但上面的示例让我确信下面发生的事情。

我扩展了我的答案,以表明即使 Avro 模式和符合 Avro 模式的 Hive Metastore 数据之间存在冲突,也可以读取。 请再看一下我上面的例子。我们的表定义指向具有三个字段的 avro 模式:

id    int
name  string
email string

而在 Hive Metastore 中有以下列:

id    int
name  string
phone string

电子邮件与电话
让我们创建一个包含符合以下条件的单个用户记录的 avro 文件user_v2.avsc架构。这是它的 json 表示形式:

{
  "id": 123,
  "name": "Tomek",
  "email": {"string": "tomek@tomek"}
}

要创建 avro 文件,我们调用:

java -jar avro-tools-1.8.2.jar fromjson --schema-file user_v2.avsc user_tomek_v2.json > user_tomek_v2.avro

尽管 Hive Metastore 不包含,我们仍然能够查询我们的表email列,它包含phone列代替:

hive> set hive.cli.print.header=true;
hive> select * from users_from_avro_schema;
OK
users_from_avro_schema.id   users_from_avro_schema.name users_from_avro_schema.email
123 Tomek   tomek@tomek
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

当我使用“STORED AS AVRO”子句创建 Hive 表时,Avro 架构存储在哪里? 的相关文章

随机推荐